4

I there any way to implement a staggered layout using google's Flexbox library similar to this

Layout implemented using StaggeredLayoutManager

The above layout is created using StaggeredLayoutManger also maintaining the aspect ratio of the image

I have tried the code:

recyclerView.apply {
        layoutManager = FlexboxLayoutManager(context).apply {
            flexWrap = FlexWrap.WRAP
            justifyContent = JustifyContent.CENTER
        }
        adapter = mAdapter
    }

But it's making the layout with single column and aspect ratio is also not maintained(Considering that images are of large size).

Prithvi Bhola
  • 3,041
  • 1
  • 16
  • 32

3 Answers3

5

enter image description here

So this is what I have done in my one project , use FlexBoxLayout, same in my case some pictures were very large in size , so had to do something about concurrency.

  flexboxLayoutManager = new FlexboxLayoutManager(yourActivity.this);
  flexboxLayoutManager.setFlexWrap(FlexWrap.WRAP);
  flexboxLayoutManager.setAlignItems(AlignItems.STRETCH);
  flexboxLayoutManager.setFlexDirection(FlexDirection.ROW);
  recyclerView.setLayoutManager(flexboxLayoutManager);

Main logic comes in adapter, on onBindViewHolder

 Glide.with(context)
         .load(String.format("yourUrlHere")
         .diskCacheStrategy(DiskCacheStrategy.ALL)
         .animate(R.anim.fadein)
         .override(dpToPx(90) ,dpToPx(90)) // here replace with your desired size.
         .centerCrop()
         .listener(new RequestListener<String, GlideDrawable>() {
                    @Override
                    public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
                        //  holder.loader.setVisibility(View.GONE);
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                        //  holder.loader.setVisibility(View.GONE);
                        return false;
                    }
                })
         .priority(Priority.IMMEDIATE)
          .into(viewHolder.imageView);

   ViewGroup.LayoutParams lp = viewHolder.imageView.getLayoutParams();
    if (lp instanceof FlexboxLayoutManager.LayoutParams) {
        FlexboxLayoutManager.LayoutParams flexboxLp = (FlexboxLayoutManager.LayoutParams) lp;
        Random random = new Random();
        int val = random.nextInt(5);
        if (val ==0){
            val = 1;
        }
        flexboxLp.setFlexGrow(val);
        flexboxLp.setFlexShrink(1f);

    } 

And you can solve your problem , using this code, as i have implemented by myself in one project. Hope this solves your problem. Happy coding :)

Note : In my project depending upon requirement, I have used flexboxLayoutManager.setFlexDirection(FlexDirection.COLUMN); so my layout is like this.

Atif AbbAsi
  • 5,633
  • 7
  • 26
  • 47
Abdul Kawee
  • 2,687
  • 1
  • 14
  • 26
  • @Atif AbbAsi Can I achieve this for the below layout https://stackoverflow.com/questions/67395159/how-to-show-the-recyclerview-as-a-two-or-three-items-in-a-row-and-needs-to-set-o – sejn May 05 '21 at 05:43
0

Use

flexDirection = FlexDirection.ROW
alignItems = AlignItems.STRETCH

Instead of

justifyContent = JustifyContent.CENTER

Your new code will be like

recyclerView.apply {
        layoutManager =FlexboxLayoutManager(context).apply {
            flexWrap = FlexWrap.WRAP
            flexDirection = FlexDirection.ROW
            alignItems = AlignItems.STRETCH
        }
        adapter = mAdapter
    }
Anisuzzaman Babla
  • 6,510
  • 7
  • 36
  • 53
  • That has no effect. When the images are large enough they will take an entire "row" each. I fear that it's just how flexbox works. – Nitzan Tomer Jul 16 '18 at 19:28
0

Its seem like you want your design like Pinterest. If you want a smooth user experience as per above image then you need to have the image height/width before loading image so that you can set the proper aspect ratio. Pinterest and other do the same way.

You need to use GridLayoutManager for this and using ConstrainLayout you can easily set the image aspect ratio like this.

private val set = ConstraintSet()

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val poster = mMoviePosters[position]

    Glide.with(holder.itemView.context)
                .setDefaultRequestOptions(requestOptions)
                .load(poster.imageUrl)
                .into(holder.mImgPoster)

    val ratio =String.format("%d:%d", poster.width,poster.height)
    set.clone(holder.mConstraintLayout)
    set.setDimensionRatio(holder.mImgPoster.id, ratio)
    set.applyTo(holder.mConstraintLayout)
}

I have already written a detail blog post about it. If you want to know more read Aspect Ratio in Staggered LayoutManager using Constraint Layout

Burhanuddin Rashid
  • 5,260
  • 6
  • 34
  • 51