How can I do something like a FlowLayout in Android?

后端 未结 9 1298
情歌与酒
情歌与酒 2020-11-22 08:11

How can I do something like a FlowLayout in Android?

相关标签:
9条回答
  • 2020-11-22 08:41

    Like one of the previous answers, I started with the solution here: http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html

    I extended it to account for varying heights of children as below.

    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.View;
    import android.view.ViewGroup;
    
    // Custom layout that wraps child views to a new line
    public class FlowLayout extends ViewGroup {
    
        private int marginHorizontal;
        private int marginVertical;
    
        public FlowLayout(Context context) {
            super(context);
            init();
        }
    
        public FlowLayout(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init();
        }
    
        private void init() { // Specify the margins for the children
            marginHorizontal = getResources().getDimensionPixelSize(R.dimen.activity_half_horizontal_margin);
            marginVertical = getResources().getDimensionPixelSize(R.dimen.activity_half_vertical_margin);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int childLeft = getPaddingLeft();
            int childTop = getPaddingTop();
            int lowestBottom = 0;
            int lineHeight = 0;
            int myWidth = resolveSize(100, widthMeasureSpec);
            int wantedHeight = 0;
    
            for (int i = 0; i < getChildCount(); i++) {
                final View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
    
                child.measure(getChildMeasureSpec(widthMeasureSpec, 0, child.getLayoutParams().width),
                        getChildMeasureSpec(heightMeasureSpec, 0, child.getLayoutParams().height));
                int childWidth = child.getMeasuredWidth();
                int childHeight = child.getMeasuredHeight();
                lineHeight = Math.max(childHeight, lineHeight);
    
                if (childWidth + childLeft + getPaddingRight() > myWidth) { // Wrap this line
                    childLeft = getPaddingLeft();
                    childTop = marginVertical + lowestBottom; // Spaced below the previous lowest point
                    lineHeight = childHeight;
                }
                childLeft += childWidth + marginHorizontal;
    
                if (childHeight + childTop > lowestBottom) { // New lowest point
                    lowestBottom = childHeight + childTop;
                }
            }
    
            wantedHeight += childTop + lineHeight + getPaddingBottom();
            setMeasuredDimension(myWidth, resolveSize(wantedHeight, heightMeasureSpec));
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            int childLeft = getPaddingLeft();
            int childTop = getPaddingTop();
            int lowestBottom = 0;
            int myWidth = right - left;
            for (int i = 0; i < getChildCount(); i++) {
                final View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
                int childWidth = child.getMeasuredWidth();
                int childHeight = child.getMeasuredHeight();
    
                if (childWidth + childLeft + getPaddingRight() > myWidth) { // Wrap this line
                    childLeft = getPaddingLeft();
                    childTop = marginVertical + lowestBottom; // Spaced below the previous lowest point
                }
                child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
                childLeft += childWidth + marginHorizontal;
    
                if (childHeight + childTop > lowestBottom) { // New lowest point
                    lowestBottom = childHeight + childTop;
                }
            }
        }
    }
    

    I used this as a solution for wrapping multi-line TextEdits. Hope it helps!

    0 讨论(0)
  • 2020-11-22 08:42

    Nice simple self-contained FlowLayout code here (just a few concise gist.github files):

    http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html

    However, the activity there out of the box didn't work for me to load the custom layout.

    I found this work-around [ using the 2-param .inflate() call from this example ]:

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        // ..
    
        setContentView(R.layout.main_res_layout_activity_main);
    
        ViewGroup flowContainer = getFlowLayoutView(); 
    
        // ..
    }
    
    ViewGroup getFlowLayoutView()
    {
        LayoutInflater inflater = getLayoutInflater();
    
        ViewGroup flowLayout = 
            (ViewGroup)
                inflater.inflate(
                        R.layout.main_res_layout_activity_main,
                        (FlowLayout) findViewById(R.id.flow_container)
                );
    
        return flowLayout;
    }
    
    0 讨论(0)
  • 2020-11-22 08:53

    There is a library from Google, called "flexbox-layout". You should check it out.

    To use it in RecyclerView, you can use something like that:

    val layoutManager = FlexboxLayoutManager(activity)
    layoutManager.flexDirection = FlexDirection.ROW
    layoutManager.flexWrap = FlexWrap.WRAP
    layoutManager.justifyContent = JustifyContent.FLEX_START
    layoutManager.alignItems = AlignItems.FLEX_START 
    recyclerView.layoutManager=layoutManager
    
    0 讨论(0)
提交回复
热议问题