Android——自定义组件

自定义组件共分为:自定义组合控件,自定义View,自定义ViewGroup

自定义ViewGroup一共七步:

  1.继承ViewGroup,将统一调用第三的构造方法。重写onMeasure(),onLayout()方法,创建数据集合对象,创建孩子行列集合对象。编写常量横向外边距,纵向外边距,组件属性  

  2.创建孩子,设置孩子,添加孩子

  3.测量孩子,测量自己,行列分布

  4.布局孩子,外边距使用

  5.编写逻辑

  6.暴露接口

  7.暴露属性

 

方法:

  removeAllViews():删除ViewGroup所有孩子

  addView(View view):添加孩子

  getChild(int index):获取指定位置的孩子

  measureChild(View child, int widthMeasureSpace, int heightMeasureSpace):测量孩子

  MeasureSpec.getSize(int width):获取size

  MeasureSpec.makeMeasureSpec(int width, MeasureSpec.AT_MOST):创建MeasureSpec

  view.getMeasureWidth():测量后可调用,获取组件宽度 

具体代码:

  1. 工具代码SizeUtil.java,App.java

public class SizeUtils {
    public static int dip2px(float dpValue){
        float scale = LitePalApplication.getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}
复制代码
public class App extends Application {
    private static Context mContext = null;
    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }
    public static Context getAppContext() {
        return mContext;
    }
}
复制代码

 

  2.FlowLayout.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="汉堡包"
    android:paddingLeft="20dp"
    android:paddingRight="20dp"
    android:paddingTop="10dp"
    android:paddingBottom="10dp"
    android:textColor="@color/text_grey"
    android:background="@drawable/selector_flow_test">

</TextView>
复制代码

 

  3.FlowLayout.java

复制代码
public class FlowLayout extends ViewGroup {
    private List<List<View>> allLineList = new ArrayList<>();
    private List<String> dataList = new ArrayList<>();
    private static final int DEFAULT_HORIZON_MARGIN = SizeUtil.dip2px(5);
    private static final int DEFAULT_VERTICAL_MARGIN = SizeUtil.dip2px(5);
    private static final int DEFAULT_CHILD_MAX_LINE = 3;
    private static final float DEFAULT_CHILD_TEXT_SIZE = 8;
    private float childTextSize;
    private int childMaxLine;

    public FlowLayout(Context context) {
        this(context, null);
    }

    public FlowLayout(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
        childTextSize = typedArray.getDimension(R.styleable.FlowLayout_childTextSize, DEFAULT_CHILD_TEXT_SIZE);
        childMaxLine = typedArray.getInt(R.styleable.FlowLayout_childMaxLine, DEFAULT_CHILD_MAX_LINE);
        typedArray.recycle();
    }

    // 2. 创建孩子,设置孩子,添加孩子
    public void setDataList(List<String> dataList ){
        removeAllViews();
        this.dataList.clear();
        this.dataList.addAll(dataList);
        for (String data : this.dataList) {
            TextView child = (TextView)LayoutInflater.from(getContext()).inflate(R.layout.item_flow_text, this, false);
            child.setText(data);
            child.setTextSize(childTextSize);
            addView(child);
        }
    }

    // 3.测量孩子,测量自己,行列分布
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int parentWidthSize = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeightSize = MeasureSpec.getSize(heightMeasureSpec);
        int childWidthSize = MeasureSpec.makeMeasureSpec(parentWidthSize, MeasureSpec.AT_MOST);
        int childHeightSize = MeasureSpec.makeMeasureSpec(parentHeightSize,MeasureSpec.AT_MOST);
        if( getChildCount() == 0 ){
            return;
        }
        allLineList.clear();
        List<View> lineList = new ArrayList<>();
        allLineList.add(lineList);

        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            final  int j = i;
            child.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onItemClickListener != null) {
                        onItemClickListener.onItemClick(child,dataList.get(j),j);
                    }
                }
            });
            measureChild(child,childWidthSize,childHeightSize);

            if( lineList.size() == 0 ){
                lineList.add(child);
            }else {
                if( allLineList.size() == childMaxLine){
                    break;
                }
                    int totalLineWidth = 0;
                for (View view : lineList) {
                    totalLineWidth += view.getMeasuredWidth() + DEFAULT_HORIZON_MARGIN;
                }
                if( totalLineWidth + child.getMeasuredWidth() + DEFAULT_HORIZON_MARGIN <= parentWidthSize){
                    lineList.add(child);
                }else {
                    lineList = new ArrayList<>();
                    lineList.add(child);
                    allLineList.add(lineList);
                }
            }
        }

        int targetHeightSize = (getChildAt(0).getMeasuredHeight() + DEFAULT_HORIZON_MARGIN) * allLineList.size();
        setMeasuredDimension(parentWidthSize,targetHeightSize);
    }

    // 4.布局孩子,外边距通过layout画出
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if( getChildCount() == 0 ){
            return;
        }
        int currentLeft = DEFAULT_HORIZON_MARGIN;
        int currentTop = 0;
        int currentRight = 0;
        int currentBottom = getChildAt(0).getMeasuredHeight();
        for (List<View> lineList : allLineList) {
            for (View child : lineList) {
                currentRight = currentLeft + child.getMeasuredWidth();
                child.layout(currentLeft,currentTop,currentRight,currentBottom);
                currentLeft = currentRight + DEFAULT_HORIZON_MARGIN;
            }
            currentLeft = 0;
            currentRight = 0;
            currentTop = currentBottom + DEFAULT_VERTICAL_MARGIN;
            currentBottom = currentTop + getChildAt(0).getMeasuredHeight();
        }
    }

    public interface OnItemClickListener {
        public void onItemClick(View view ,String data,int position);
    }
    private OnItemClickListener onItemClickListener;

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }
}
复制代码

 

  4.FlowLayoutActivity.java,FlowLayout.xml

复制代码
public class FlowLayoutActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_flow_layout);
        List<String> data = new ArrayList<>();
        data.add("键盘");
        data.add("显示器");
        data.add("鼠标");
        data.add("ipad");
        data.add("air pod");
        data.add("Android手机");
        data.add("mac pro");
        data.add("大疆mini3 pro");
        data.add("ChatGPT");
        data.add("耳机");
        data.add("Noval AI");
        data.add("键盘");
        data.add("显示器");
        data.add("鼠标");
        data.add("键盘");
        data.add("显示器");
        data.add("鼠标");
        data.add("ipad");
        data.add("air pod");
        data.add("Android手机");
        data.add("mac pro");
        data.add("大疆mini3 pro");
        data.add("ChatGPT");
        data.add("耳机");
        data.add("Noval AI");
        data.add("键盘");
        data.add("显示器");
        data.add("鼠标");
        FlowLayout flowLayout = this.findViewById(R.id.flow_layout);
        flowLayout.setTextList(data);

        flowLayout.setOnItemClickListener(new FlowLayout.OnItemClickListener() {
            @Override
            public void onItemClickListener(View v, String text) {
                Toast.makeText(FlowLayoutActivity.this,"text "+text,Toast.LENGTH_SHORT).show();

            }
        });
    }

    private static final String TAG = "FlowLayoutActivity";
}
复制代码
复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".flow.FlowLayoutActivity">

    <com.example.myandroiddemo.flow.FlowLayout
        android:id="@+id/flow_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="10dp" />
    
</LinearLayout>
复制代码

 

  

 

posted @   remix_alone  阅读(167)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示