Categories
discuss

How to get an offset in RecyclerView ItemDecorator

I have written two ItemDecorator‘s for RecyclerView. Each adds some top offset in getItemOffsets(). Let’s say:

  • First decorator adds 20dp top offset
  • Second decrator adds 30dp top offset

Now, when I add both of them to RecyclerView, each item is correctly offsetted by 50dp, that’s good.

But here comes the question: How do I get this offset in onDraw/onDrawOver?

Usually decorators draw their stuff by traversing parent.getChildAt(i) stuff and getting child.getTop() for example to draw above child view of RecyclerView.

But in this case, doing so would mix up the drawing of other decorator, because it would also use child.getTop().

So at the moment it seems like both decorators need to know about each other and each other’s height.

Am I missing something here? I hope I am.

EDIT: I reported an issue to Android issue tracker and it seems this will be worked on. Star it to keep track of progress: https://code.google.com/p/android/issues/detail?id=195746

Answer

tl;dr No you are not missing anything. But you can get the values needed in getItemOffsets, albeit it seems a little bit dirty to me.

Basically there is only one option of getting the decorated height other than managing decorations yourself: LayoutManager.getDecoratedTop();

onDraw

In onDraw you get the whole canvas of the recyclerView, c.getClipBounds() does not hold any information. Albeit the javadoc of adding decorations says that decorations should just draw withing their bounds.

Also, getting parent.getLayoutManager().getDecoratedTop() will give you the same values in every decoration, since it’s already too late here, those values are for layouting purposes.

We are too late, layouting is done and we missed it.

getItemOffsets

Please note that I tested the following with a LinearLayoutManager and it might as well not work with the others (Most definitely not with most custom ones). Since I am relying on measuring happening between those calls, which is not documented, the given solution might break with some future version.

I just felt I needed that disclaimer. I found a working solution (watch the mOffset):

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    mOffset = parent.getLayoutManager().getTopDecorationHeight(view);
    outRect.set(0, 10, 0, 0);
}

This works, because the recyclerview, when calculating the total inset of the child, is updating the views package local LayoutParams variable. While we cannot access the layout parameter variable itself, calling getTopDecorationHeight actually uses the (currently) dirty inset, giving us the proper value.
Hence, you can get the offset of the previous decorations before applying your own!

To apply it, just remove the other decorations offset when drawing your decoration:

c.drawRect(child.getLeft() + child.getTranslationX(),
        mOffset + layoutManager.getDecoratedTop(child) + child.getTranslationY(),
        child.getRight() + child.getTranslationX(),
        child.getBottom() + child.getTranslationY(), paint);

This will actually apply the other decorations offset, then draw your own from the correct top.

Some Problems

This is now a basic, working solution for the default usecase. BUT. If you have different offsets depending on the item VIEW_TYPE or the adapter position things get tricky.

You will either duplicate your logic and keep various offsets for various view types or you have to store / retrieve the offset for every view or viewtype.

To do so, you could either add some custom tag with view.setTag(key, object) or doing something similar with the RecyclerView.State object that’s getting passed around.

Categories
discuss

Android toolbar home button not showing

I am trying to create a toolbar which also have the Home icon/button so that the user can go back to home with it.

This is my code:

AndroidManifest.xml

<activity
            android:name=".SettingsActivity"
            android:noHistory="true"
            android:theme="@style/AppTheme">
        <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".MainActivity"/>
</activity>

toolbar.xml:

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:background="@color/ColorPrimary"
    android:elevation="2dp"
    android:theme="@style/Base.ThemeOverlay.AppCompat.Dark"/>

settings_activity.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent">

<include
        android:id="@+id/tool_bar"
        layout="@layout/toolbar"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"/>
</LinearLayout

SettingsActivity.java

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.settings_activity);

    toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.tool_bar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setHomeButtonEnabled(true);
}
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
}

@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}

However all I see is the name of my application and no UP/Home button at all?

Can you help me please

Answer

Change this:

getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);

with:

getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Categories
discuss

Realm.getInstance(context) not working anymore after Migration

After doing a migration, i cant use the Realm.getInstance(context); anymore

Error: java.lang.IllegalArgumentException: Configurations cannot have different schema versions if used to open the same file. 1 vs. 0

i saw that i must use the created configs previosly to do the migration

RealmConfiguration config1 = new RealmConfiguration.Builder(this)
                .schemaVersion(1)
                .migration(new Migration())
                .build();

now i must create the config1 again everywhere i use the

Realm.getInstance(context);

i used to add this for each method to avoid any kind of null

public List<CustomClass> getAll() {
realm = Realm.getInstance(context);
....
}



public CustomClass getOneById(int id) {
realm = Realm.getInstance(context);
...
}

and sometimes outside the DAO class where i dynamically change the database i use this:

Realm.getInstance(context).beginTransaction();

change object

Realm.getInstance(context).commitTransaction();

now i must create this CONFIG1 (RealmConfiguration) EVERYWHERE? or is there any other approach?

i tried adding to the MainClass this Realm.setDefaultConfiguration(CONFIG1); but no success =/

i was wrong for checking or avoiding null on realm object calling the getInstance for each method?

Answer

Use Realm.setDefaultConfiguration(CONFIG1); to set default configuration :

and use Realm.getDefaultInstance(); to get default realm instance.

Categories
discuss

What is the JavaFX equivalent of androids AsyncTask?

I currently have to do some network operations for my javaFX program, and this is how im doing it now:

  • 1 Thread class
  • 1 Interface with callback methods
  • 1 Main class Implementing that Interface

I am implementing those inside the Main class and getting updates like onProgress(), onDone() etc.. via the Thread class which has a Interface object inside it..

However in android this task is a lot easier, Just using the AsyncTask which works great.

There you have

// Ui thread

  • onPreExecute()

// Background Thread

  • doInBackground()

// Ui thread

  • onProgressUpdate()

// Ui thread

  • onPostExecute()

Is there a Class that works this way too, in JavaFX? I need progress updates for a progress bar and I need to know when a task is done without freezing the UI screen.

Answer

I am not an Android programmer, so I cannot verify that this is a direct equivalent, but it sounds as though you are looking for the Task class.

You can create a Task and either use it as a Runnable in a background thread, or submit it to an Executor. You can bind to, or register a listener with, its progressProperty and you can register handlers via the setOnSucceeded, setOnFailed and similar methods.

The progressProperty (and other properties) are updated on the FX Application Thread (so it is safe to update the UI in response to changes in their values), and the handlers for the state events (succeeded, failed, etc) are also invoked on the FX Application Thread.

Categories
discuss

Serialization for Java Calendar

How do I create a custom serialization for java Calendar to json by extending json serializer<Calendar>?

I tried the same for java.until.Date and it’s working. In the serialization method, I converted Date as String and write it in json format.

The sample code done for java.util.Date is similar to code given below

  public class CDJsonDateSerializer extends JsonSerializer<Date>{
  @Override
  public void serialize(Date date, JsonGenerator jsonGenerator,SerializerProvider provider)
 throws IOException {

      SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
      String dateString = dateFormat.format(date);
     jsonGenerator.writeString(dateString);
 }
}

And it is used like so:

 @JsonSerialize(using = CDJsonDateSerializer.class)
 private Date startDate;

What can I do for Serialize Calendar in java to json without losing data in Calendar object ?

Answer

From JSON to Calendar

Create a JsonSerializer:

public class CalendarSerializer extends JsonSerializer<Calendar> {

    private SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");

    @Override
    public void serialize(Calendar calendar, JsonGenerator jsonGenerator,
                          SerializerProvider serializerProvider) throws IOException {

        String dateAsString = formatter.format(calendar.getTime());
        jsonGenerator.writeString(dateAsString);

    }
}

And then use it:

@JsonSerialize(using = CalendarSerializer.class)
private Calendar calendar;

From Calendar to JSON

Create a JsonDeserializer:

public class CalendarDeserializer extends JsonDeserializer<Calendar> {

    private SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");

    @Override
    public Calendar deserialize(JsonParser jsonParser,
                                DeserializationContext deserializationContext) 
                                throws IOException {

        String dateAsString = jsonParser.getText();

        try {
            Date date = formatter.parse(dateAsString);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar;
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

And then use it:

@JsonDeserialize(using = CalendarDeserializer.class)
private Calendar calendar;
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..