Android喜马拉雅集成之》自定义控件FlowTextLayout的实现

自定义控件FlowTextLayout

开发工具:Android Studio 4.0.2

文件名称:FlowTextLayout.java

package com.hl.maya.views;

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.hl.maya.R;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义控件
 */
public class FlowTextLayout extends ViewGroup {
    public static final String TAG = "FlowTextLayout";

    private List<Line> mLines = new ArrayList<>();
    private Line mCurrentLineCursor;
    private int mHorizontalSpace = 20;
    private int mVerticalSpace = 20;
    private OnFlowTextItemClickListener mListener;
    private List<String> mTexts = null;

    public FlowTextLayout(Context context) {
        super(context,null);
    }

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

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

    /**
     * 设置控件的样式
     * @param texts
     */
    public void setTextContents(List<String> texts){
        this.mTexts = texts;
        for (String text : texts) {
            final TextView item = new TextView(getContext());
            item.setText(text);
            item.setBackground(getResources().getDrawable(R.drawable.shape_flow_text_bg));
            item.setPadding(40,10,40,10);
            //设置点击事件
            item.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(mListener != null){
                        mListener.onFlowTextItemClick(item.getText().toString());
                    }
                }
            });
            item.setTextColor(Color.parseColor("#888585"));
            item.setTextSize(18);
            item.setGravity(Gravity.CENTER);
            addView(item);
        }
    }

    public void setSpace(int horizontalSpace,int verticalSpace){
        this.mHorizontalSpace = horizontalSpace;
        this.mVerticalSpace = verticalSpace;
    }

    /**
     * 测量
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mLines.clear();
        mCurrentLineCursor = null;
        //获取宽度
        int layoutWidth = MeasureSpec.getSize(widthMeasureSpec);
        //计算最大宽度
        int maxLineWidth = layoutWidth - getPaddingLeft() - getPaddingRight();
        //先测量孩子
        int count = getChildCount();
        //如果子view 的数量为0 就不再需要继续测量
        //if (count == 0) return;

        for (int i=0;i<count;i++){
            View view = getChildAt(i);
            //如果子 View 不可见,停止这次view 测量
            if(view.getVisibility() == View.GONE){
                continue;
            }

            //测量孩子
            measureChild(view,widthMeasureSpec,heightMeasureSpec);
            //往Lines添加孩子
            if(mCurrentLineCursor == null){
                mCurrentLineCursor = new Line(maxLineWidth,mHorizontalSpace);
                //添加到line中
                mLines.add(mCurrentLineCursor);
                //行中一个孩子都没有
                mCurrentLineCursor.addView(view);
            } else {
                boolean canAdd = mCurrentLineCursor.canAdd(view);
                if (canAdd) {
                    //可以添加
                    mCurrentLineCursor.addView(view);
                } else {
                    //新建行
                    mCurrentLineCursor = new Line(maxLineWidth,mHorizontalSpace);
                    //添加到line中
                    mLines.add(mCurrentLineCursor);
                    //将view添加到line中
                    mCurrentLineCursor.addView(view);
                }
            }
        }

        //设置自己的宽度和高度
        int measureWidth = layoutWidth;
        float allHeight = 0;
        for (int i = 0; i< mLines.size();i++) {
            float mHeight = mLines.get(i).mHeight;
            allHeight += mHeight;
            //加间距
            if (i != 0) {
                allHeight += mVerticalSpace;
            }
        }

        int measuredHeight = (int)(allHeight + getPaddingTop() + getPaddingBottom() + 0.5f);
        setMeasuredDimension(measureWidth,measuredHeight);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int paddingLeft = getPaddingLeft();
        int offestTop = getPaddingTop();
        for (int i=0;i<mLines.size();i++){
            Line line = mLines.get(i);
            //给行布局
            line.layout(paddingLeft,offestTop);
            offestTop += line.mHeight + mVerticalSpace;
        }
    }

    /**
     * 对外提供点击事件的接口
     * @param listener
     */
    public void setOnFlowTextItemClickListener(OnFlowTextItemClickListener listener){
        this.mListener = listener;
    }

    /**
     * 设置点击事件接口
     */
    public interface  OnFlowTextItemClickListener{
        void onFlowTextItemClick(String text);
    }

    private class Line{
        //属性
        private List<View> mViews = new ArrayList<View>();
        private float mMaxWidth;
        private float mUsedWidth;
        private float mHeight;
        private float mMarginLeft;
        private float mMarginRight;
        private float mMarginTop;
        private float mMarginBottom;
        private float mHorizontalSpace;

        public Line(int maxWidth,int horizontalSpace){
            this.mMaxWidth = maxWidth;
            this.mHorizontalSpace = horizontalSpace;
        }

        /**
         * 添加view 记录属性的变化
         * @param view
         */
        public void addView(View view){
            //加载view的方法
            int size = mViews.size();
            int viewWidth = view.getMeasuredWidth();
            int viewHeight = view.getMeasuredHeight();
            //计算高和宽
            if (size == 0){
                //还没有添加view
                if(viewWidth > mMaxWidth){
                    mUsedWidth = mMaxWidth;
                } else {
                    mUsedWidth = viewWidth;
                }
                mHeight = viewHeight;
            } else {
                //多个view的情况下
                mUsedWidth += viewWidth + mHorizontalSpace;
                mHeight = mHeight < viewHeight ? viewHeight : mHeight;
            }
            //将view记录到集合中
            mViews.add(view);
        }

        /**
         * 给孩子设置布局
         * @param paddingLeft
         * @param offestTop
         */
        public void layout(int paddingLeft, int offestTop){
            int currentLeft = paddingLeft;
            int size = mViews.size();

            //判断已经使用的额宽度是否小于最大的宽度
            float extra = 0;
            float widthAvg = 0;
            if(mMaxWidth > mUsedWidth){
                extra = mMaxWidth - mUsedWidth;
                widthAvg = extra/size;
            }

            for (int i=0; i<size;i++) {
                View view = mViews.get(i);
                int viewWidth = view.getMeasuredWidth();
                int viewHeight = view.getMeasuredHeight();
                //判断是否有富余
                if(widthAvg != 0){
                    //改变宽度
                    int newWidth = (int) (viewWidth + widthAvg + 0.5f);
                    int widthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth,MeasureSpec.AT_MOST);
                    int heightMeasureSpec = MeasureSpec.makeMeasureSpec(viewHeight,MeasureSpec.EXACTLY);
                    view.measure(widthMeasureSpec,heightMeasureSpec);

                    viewWidth = view.getMeasuredWidth();
                    viewHeight = view.getMeasuredHeight();
                }

                //布局
                int left = currentLeft;
                int top = (int) (offestTop + (mHeight - viewHeight)/2 + 0.5f);
                //int top = offsetTop;
                int right = left + viewWidth;
                int bottom = top + viewHeight;
                view.layout(left,top,right,bottom);
                currentLeft += viewWidth + mHorizontalSpace;
            }
        }

        /**
         * 用来判断是否可以将view 添加到line中
         * @param view
         * @return
         */
        public boolean canAdd(View view){
            //判断瑟吉欧否能添加view
            int size = mViews.size();
            if(size == 0){
                return true;
            }
            int viewWidth = view.getMeasuredWidth();
            //预计使用的宽度
            float planWidth = mUsedWidth + mHorizontalSpace + viewWidth;

            if(planWidth > mMaxWidth){
                //不能添加到line中
                return false;
            } else {
                return true;
            }
        }

    }
}

控件背景 shape_flow_text_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle"
    xmlns:android="http://schemas.android.com/apk/res/android" >

    <corners android:radius="20dp"/>
    <stroke android:width="1dp" android:color="#888585"/>
</shape>

使用代码

布局文件中调用 activity.xml

<com.hl.maya.views.FlowTextLayout
        android:id="@+id/ftl_search"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
private FlowTextLayout mSearchFlowText;
//初始化控件
mSearchFlowText = this.findViewById(R.id.ftl_search);
//设置数据
mSearchFlowText.setTextContents(hotwords);

//设置点击事件
//点击热词的时候执行的事件
        mSearchFlowText.setOnFlowTextItemClickListener(new FlowTextLayout.OnFlowTextItemClickListener() {
            @Override
            public void onFlowTextItemClick(String text) {
                Toast.makeText(SearchActivity.this,text,Toast.LENGTH_SHORT).show();
            }
        });

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_35652070

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值