流式布局SearchFlowLayout

看到搜索框下面一般都有最近的搜索记录,这些搜索记录一般是流式布局,下面的是一个流式布局,一个继承ViewGroup的自定义view,其中一种使用场景就是在搜索框下面,效果图如下:


下面是SearchFlowLayout的源码:

public class SearchFlowLayout extends ViewGroup {
    List<Line> lines = new ArrayList<Line>();//所有的行
    private Line currentLine;

    public SearchFlowLayout(Context context) {
        super(context);
    }

    public SearchFlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SearchFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private OnItemClickListener mListener;

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.mListener = listener;
    }

    public interface OnItemClickListener {
        void click(int position);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        lines.clear();
        currentLine = null;
        int width = MeasureSpec.getSize(widthMeasureSpec);
        float maxWidth = width - getPaddingLeft() - getPaddingRight();
        float horizontalDistance = dp2px(getContext(), 10);
        float vercitalDistance = dp2px(getContext(), 10);
        int childCount = getChildCount();
        currentLine = new Line(maxWidth, horizontalDistance, vercitalDistance);
        lines.add(currentLine);
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            final int position = i;
            childView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mListener != null) {
                        mListener.click(position);
                    }
                }
            });
            measureChild(childView, widthMeasureSpec, heightMeasureSpec);
            if (currentLine.canAddView(childView)) {
                currentLine.addView(childView);
            } else {
                currentLine = new Line(maxWidth, horizontalDistance, vercitalDistance);
                if (currentLine.canAddView(childView)) {
                    currentLine.addView(childView);
                }
                lines.add(currentLine);
            }
        }

        int hight = 0;
        for (int i = 0; i < lines.size(); i++) {
            if (i == 0) {
                hight += getPaddingTop();
            } else if (i == lines.size() - 1) {
                hight += getPaddingBottom();
            }
            hight += lines.get(i).mLineHight + vercitalDistance;
        }

        setMeasuredDimension(width, hight);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int lineTop = getPaddingTop();
        for (int i = 0; i < lines.size(); i++) {
            Line line = lines.get(i);
            line.layout(lineTop);
            lineTop += line.mLineHight + line.mVercitalDistance;
        }
    }

    /**
     * 每一行
     */
    class Line {
        public List<View> mViews = new ArrayList<View>();
        public float mHorizontalDistance;//行中两个子View之间水平间距
        public float mVercitalDistance;//两个行竖直间距
        public float mMaxWidth;//行中的最大的宽度
        public float mUseWidth;//行中已经使用的宽度
        public float mLineHight;//行的高度

        public Line(float maxWidth, float horizontalDistance, float vercitalDistance) {
            this.mMaxWidth = maxWidth;
            this.mHorizontalDistance = horizontalDistance;
            this.mVercitalDistance = vercitalDistance;
        }

        /**
         * 是否能添加View
         *
         * @param view
         * @return
         */
        private boolean canAddView(View view) {

            if (mViews.size() == 0) {
                mUseWidth += getPaddingLeft() + getPaddingRight() + view.getMeasuredWidth();
                return true;
            } else {
                mUseWidth += view.getMeasuredWidth() + mHorizontalDistance;
            }
            if (mUseWidth <= mMaxWidth) {
                return true;
            }
            return false;
        }

        /**
         * 添加View
         *
         * @param view
         */
        private void addView(View view) {
            mViews.add(view);
            mLineHight = mLineHight < view.getMeasuredHeight() ? view.getMeasuredHeight() : mLineHight;
        }

        /**
         * 摆放子view
         */
        private void layout(int lineTop) {
            int left = getPaddingLeft();
            int top = lineTop;
            int right = 0;
            int bottom = 0;

            for (int i = 0; i < mViews.size(); i++) {
                View view = mViews.get(i);
                right = left + view.getMeasuredWidth();
                bottom = top + view.getMeasuredHeight();

                view.layout(left, top, right, bottom);
                left += view.getMeasuredWidth() + mHorizontalDistance;

            }
        }
    }

    /**
     * dp转px
     *
     * @param context
     * @param dp
     * @return
     */
    public int dp2px(Context context, float dp) {
        float density = context.getResources().getDisplayMetrics().density;
        int px = (int) (dp * density + 0.5f);
        return px;
    }
}

使用:

xml布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        android:background="#E6E6E6">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:orientation="horizontal"
            android:background="@drawable/search_bg"
            android:layout_marginLeft="10dp"
           android:layout_marginRight="10dp">
            <ImageView
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_marginLeft="10dp"
                android:layout_gravity="center_vertical"
                android:background="@drawable/search1"/>
            <EditText
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@null"
                />
        </LinearLayout>
    </FrameLayout>
    <com.org.sleepgod.widget.SearchFlowLayout
        android:id="@+id/fl_view"
        android:padding="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </com.org.sleepgod.widget.SearchFlowLayout>
</LinearLayout>

java代码:

public class FlowLayoutActivity extends Activity {

    private SearchFlowLayout mSearchFlowLayout;
    private String[] mNames = new String[]{"大主宰","龙王传说","一念永恒","雪鹰领主","帝霸","最强狂兵","美食供应商","我是大明星","全职法师","我的贴身校花","重生完美时代"
    ,"318女生宿舍"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_flowlayout);
        mSearchFlowLayout = (SearchFlowLayout) findViewById(R.id.fl_view);
        for (int i = 0; i < mNames.length; i++) {
            TextView textView = new TextView(this);
            textView.setText(mNames[i]);
            textView.setBackgroundResource(R.drawable.text_bg);
            GradientDrawable gradientDrawable = (GradientDrawable) textView.getBackground();
            gradientDrawable.setStroke(1, UIUtils.randomColor());
            mSearchFlowLayout.addView(textView);
        }

        mSearchFlowLayout.setOnItemClickListener(new SearchFlowLayout.OnItemClickListener() {
            @Override
            public void click(int position) {
                Toast.makeText(FlowLayoutActivity.this,mNames[position],Toast.LENGTH_SHORT).show();
            }
        });
    }
}

text_bg

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#FFFFFF" />
    <stroke
        android:width="1dp"
        android:color="#61e0fe" />
    <padding
        android:bottom="6dp"
        android:left="10dp"
        android:right="10dp"
        android:top="6dp" />
    <corners android:radius="25dp" />
</shape>

search_bg

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="25dp"/>
    <solid android:color="#FFF"/>
    <stroke android:color="#7A7A7A"></stroke>
</shape>


源码链接:https://github.com/sleepgodMaster/sleepgod-master/blob/master/src/main/java/com/org/sleepgod/widget/SearchFlowLayout.java




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值