Zyoo Zyoo - 6 months ago 39
Android Question

StaggeredGridLayoutManager dislocation (2)

Same problem, don't know if this counts as a duplicate.

I have a problem with Android's

StaggeredGridLayoutManager
. The description of the problem is pretty much the same with StaggeredGridLayoutManager dislocation.

Here's the screenshot (sorry for the censorship, those are
CardViews
):

enter image description here

And the adapter:

public class ProductItemStaggeredAdapter extends RecyclerView.Adapter<ViewHolderRVProductItem> {
public ProductItemStaggeredAdapter(RealmResults<ProductItem> items, int theme) {
mItems = items;
this.theme = theme;
setHasStableIds(true);
}

@Override
public ViewHolderRVProductItem onCreateViewHolder(final ViewGroup parent, final int viewType) {
Context context = parent.getContext();
int blackGrey1 = ContextCompat.getColor(context, R.color.black_grey1);
int white = ContextCompat.getColor(context, R.color.white);
LayoutInflater inflater = LayoutInflater.from(context);
View view;

ViewHolderRVProductItem vh = null;
switch (viewType) {
case 100:
/** Error **/
view = inflater.inflate(R.layout.item_retry, parent, false);
StaggeredGridLayoutManager.LayoutParams lp3 = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
lp3.setFullSpan(true);
view.setLayoutParams(lp3);
view.setOnClickListener(retryClickListener);
vh = new ViewHolderRVProductItem(view);
break;
case 101:
/** Loading **/
view = inflater.inflate(R.layout.item_loading, parent, false);
StaggeredGridLayoutManager.LayoutParams lp4 = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
lp4.setFullSpan(true);
view.setLayoutParams(lp4);
vh = new ViewHolderRVProductItem(view);
break;
case Banner.ONE:
/**
* This banner occupies 1 column of the screen
* The height is set programmatically based on screen width
*
* Product image ratio is 32 x 15
*/
view = inflater.inflate(R.layout.item_banner_big, parent, false);
view.setOnClickListener(productClickListener);
StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
lp.setFullSpan(true);
view.setLayoutParams(lp);

view.setOnClickListener(productClickListener);

vh = new ViewHolderRVProductItem(view);
break;
case Banner.TWO:
/**
* This banner occupies 1 column of the screen
* The height is smaller than BANNER_ONE
* The height is set programmatically based on screen width
*/
view = inflater.inflate(R.layout.item_banner_big, parent, false);
view.setOnClickListener(productClickListener);
StaggeredGridLayoutManager.LayoutParams lp2 = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
lp2.setFullSpan(true);
view.setLayoutParams(lp2);

view.setOnClickListener(productClickListener);

vh = new ViewHolderRVProductItem(view);
break;
case Banner.THREE:
/**
* This banner occupies 3 column of the screen
* The height is set programmatically based on screen width
*/
view = inflater.inflate(R.layout.item_banner_long_rect, parent, false);
view.setOnClickListener(productClickListener);
vh = new ViewHolderRVProductItem(view);
break;
case Banner.FOUR:
/**
* This banner occupies 3 column of the screen
* The height is smaller than BANNER_THREE
* The height is set programmatically based on screen width
*/
view = inflater.inflate(R.layout.item_banner_long_rect, parent, false);
view.setOnClickListener(productClickListener);
vh = new ViewHolderRVProductItem(view);
break;
default: /** ProductItem.BANNER_FIVE **/
/**
* This banner occupies 2 column of the screen
* The height is set programmatically based on screen width
*/
view = inflater.inflate(R.layout.item_banner_recommended, parent, false);
view.setOnClickListener(productClickListener);
vh = new ViewHolderRVProductItem(view);
break;
}

/** Set image ratio **/
if (vh.productImage != null) {
final ViewHolderRVProductItem finalVh = vh;
vh.itemView.post(new Runnable() {
@Override
public void run() {
setImageRatio(finalVh.productImage, viewType, finalVh.productImage.getWidth());
}
});
}

return vh;
}

@Override
public void onBindViewHolder(final ViewHolderRVProductItem holder, final int position) {
if (holder == null) return;

final Context context = holder.itemView.getContext();
final ProductItem item = mItems.get(position);

holder.itemView.setTag(item);

final int bannerType = holder.getItemViewType();
final Banner banner = bannerType == Banner.ONE ? item.getBanner1() : (bannerType == Banner.FIVE ? item.getBanner5() : (bannerType == Banner.TWO ? item.getBanner2() : (bannerType == Banner.THREE ? item.getBanner3() : item.getBanner4())));

if (banner != null && holder.productImage != null) {
holder.productImage.post(new Runnable() {
@Override
public void run() {
float width = holder.productImage.getWidth();
float height = holder.productImage.getHeight();
Picasso.with(context)
.load(banner.getImageURL6())
.resize((int) width, (int) height)
.into(holder.productImage);
}
});
}
}

private void setImageRatio(ImageView imgview, int bannerType, int width) {
Context context = imgview.getContext();
switch (bannerType) {
case Banner.ONE:
/** Product image ratio is 32 x 15 **/
float height = (15f / 32f) * width;
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) imgview.getLayoutParams();
params.width = width;
params.height = (int) height;
imgview.setLayoutParams(params);
break;
case Banner.TWO:
/** Product image ratio is 11 x 3 **/
float height1 = (3f / 11f) * width;
LinearLayout.LayoutParams params1 = (LinearLayout.LayoutParams) imgview.getLayoutParams();
params1.width = width;
params1.height = (int) height1;
imgview.setLayoutParams(params1);
break;
case Banner.THREE:
/** Product image ratio: 27 x 40 **/
float height2 = (40f / 27f) * width;
RelativeLayout.LayoutParams params2 = (RelativeLayout.LayoutParams) imgview.getLayoutParams();
params2.width = (int) width;
params2.height = (int) height2;
imgview.setLayoutParams(params2);
break;
case Banner.FOUR:
int dip8 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8f, context.getResources().getDisplayMetrics());

/** Product image ratio: 1 x 1 **/
int size = (int) width - dip8;
RelativeLayout.LayoutParams params3 = (RelativeLayout.LayoutParams) imgview.getLayoutParams();
params3.width = size;
params3.height = size;
params3.leftMargin = dip8;
params3.topMargin = dip8;
params3.rightMargin = dip8;
imgview.setLayoutParams(params3);
break;
case Banner.FIVE:
/** Product image ratio: 162 x 71 **/
float height3 = (71f / 162f) * width;
RelativeLayout.LayoutParams params4 = (RelativeLayout.LayoutParams) imgview.getLayoutParams();
params4.width = (int) width;
params4.height = (int) height3;
imgview.setLayoutParams(params4);
break;
}
}
}


The thing that the previous problem and this problem have done is changing the
ImageView
width & height programmatically. Why changing
View
's layout have impact in
RecyclerView
?

Answer

I've found an ultimate solution. Rather than using previous solution, i have found the culprit:

    final ViewHolderRVProductItem finalVh = vh;
        vh.itemView.post(new Runnable() {
            @Override
            public void run() {
                setImageRatio(finalVh.productImage, viewType, finalVh.productImage.getWidth());
            }
        });

I think it's not recommended to modify ImageView's size using post inside an adapter. I'm now using AspectRatioImageView and it's working smoothly.