美文网首页
什么是自定义View?

什么是自定义View?

作者: 我要离开浪浪山 | 来源:发表于2023-04-16 23:32 被阅读0次

    1、自定义View分类

    1、自定义View

    在没有现成的View,需要自己实现的时候,就使用自定义View,一般继承自View,SurfaceView或其他的View;

    2、自定义ViewGroup

    自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,人多继承自ViewGroup或各种Layout;

    2、自定义View的图

    6df4334c5c4332bc10e6c4db0732332.png 78702912b20c0d41f59622014db4049.png

    所以,自定义View任督二脉就在于此:

    • 自定义View主要是实现 onMeasure + onDraw
    • 自定义ViewGroup主要是实现onMeasure + onLayout

    3、View的层级

    View的层级.png 自定义流程.png

    4、getMeasureWidth与getWidth的区别

    21454b47aafa864a9361d28b28d02d4.png

    5、Android中两种坐标系

    Android屏幕坐标系.png 视图坐标系.png

    6、MeasureSpec 是什么 ?

    MeasureSpec是View中的内部类,基本都是二进制运算。由于int是32位的,用高两位表示mode,低30位表示size,MODE SHIFT = 30的作用是移位

    • UNSPECIFIED:不对View大小做限制,系统使用
    • EXACTLY:确切的大小,如: 100dp
    • AT_MOST:大小不可超过某数值,如: matchParent,最大不能超过你爸爸

    7、为什么要measure ?

    计算大小.png 举例说明.png

    8、Android中 lastLine怎么使用

    lastLine是TextView中的一个属性,用于指定文本的最后一行的行号。它可以用来控制文本的显示方式,例如在最后一行添加省略号或者在最后一行显示特定的文本。在Android中,lastLine属性可以通过XML布局文件或者代码动态设置。

    lastLine是TextView中的一个属性,用于指定TextView中最后一行的行号。可以通过以下方式使用:

    1、在XML布局文件中设置:

    <TextView
        android:id="@+id/myTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:maxLines="3"
        android:ellipsize="end"
        android:lastLine="3" />
    

    在这个例子中,我们设置了TextView的最大行数为3,当文本超过3行时,将使用省略号来表示。同时,我们将lastLine属性设置为3,表示最后一行的行号为3。

    2、在Java代码中设置:

    TextView myTextView = findViewById(R.id.myTextView);
    myTextView.setLastLine(3);
    

    这个例子中,我们通过findViewById方法获取了TextView的实例,并调用setLastLine方法将最后一行的行号设置为3。注意:lastLine属性只在TextView的maxLines属性设置为一个大于0的值时才有效。如果maxLines属性设置为0或者不设置,lastLine属性将不起作用。

    9、Android visibleState使用

    Android中的visibleState是一个状态列表,用于定义视图的可见性状态。它可以用于定义视图的不同状态,例如:可见、不可见、半透明等。
    使用visibleState需要以下步骤:
    1、在XML布局文件中定义状态列表:

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_visible="true" android:alpha="1.0" />
        <item android:state_visible="false" android:alpha="0.0" />
    </selector>
    

    在视图中设置状态列表:

    <View
        android:id="@+id/my_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/my_state_list" />
    

    在代码中设置视图的可见性状态:

    View myView = findViewById(R.id.my_view);
    myView.setVisibility(View.VISIBLE); // 设置可见状态
    myView.setVisibility(View.INVISIBLE); // 设置不可见状态
    myView.setVisibility(View.GONE); // 设置隐藏状态
    

    注意:在使用visibleState时,需要将视图的背景设置为状态列表。

    10、Android flexBox Layout使用

    地址:https://blog.csdn.net/weixin_39397471/article/details/90212231

    11、自定义FlowLayout

    258e112d537e3f2729c455ca6d18cf0.png

    2、FlowLayout :

    package com.example.flowlayout;
    
    import android.content.Context;
    import android.content.res.Resources;
    import android.graphics.Canvas;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.util.TypedValue;
    import android.view.View;
    import android.view.ViewGroup;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    public class FlowLayout extends ViewGroup {
        private static final String TAG = "FlowLayout";
        private int mHorizontalSpacing = dp2px(16); //每个item横向间距
        private int mVerticalSpacing = dp2px(8); //每个item横向间距
    
        private List<List<View>> allLines = new ArrayList<>(); // 记录所有的行,一行一行的存储,用于layout
        List<Integer> lineHeights = new ArrayList<>(); // 记录每一行的行高,用于layout
    
    
        public FlowLayout(Context context) {
            super(context);
    //        initMeasureParams();
        }
    
        //反射
        public FlowLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
    //        initMeasureParams();
        }
    
        //主题style
        public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    //        initMeasureParams();
        }
        //四个参数 自定义属性
    
        private void clearMeasureParams() {
            allLines.clear();
            lineHeights.clear();
        }
    
        //度量
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            clearMeasureParams();//内存 抖动
            //先度量孩子
            int childCount = getChildCount();
            int paddingLeft = getPaddingLeft();
            int paddingRight = getPaddingRight();
            int paddingTop = getPaddingTop();
            int paddingBottom = getPaddingBottom();
    
            int selfWidth = MeasureSpec.getSize(widthMeasureSpec);  //ViewGroup解析的父亲给我的宽度
            int selfHeight = MeasureSpec.getSize(heightMeasureSpec); // ViewGroup解析的父亲给我的高度
    
            List<View> lineViews = new ArrayList<>(); //保存一行中的所有的view
            int lineWidthUsed = 0; //记录这行已经使用了多宽的size
            int lineHeight = 0; // 一行的行高
    
            int parentNeededWidth = 0;  // measure过程中,子View要求的父ViewGroup的宽
            int parentNeededHeight = 0; // measure过程中,子View要求的父ViewGroup的高
    
            for (int i = 0; i < childCount; i++) {
                View childView = getChildAt(i);
    
                LayoutParams childLP = childView.getLayoutParams();
                if (childView.getVisibility() != View.GONE) {
                    //将layoutParams转变成为 measureSpec
                    int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight,
                            childLP.width);
                    int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom,
                            childLP.height);
                    childView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    
                    //获取子view的度量宽高
                    int childMesauredWidth = childView.getMeasuredWidth();
                    int childMeasuredHeight = childView.getMeasuredHeight();
    
                    //如果需要换行
                    if (childMesauredWidth + lineWidthUsed + mHorizontalSpacing > selfWidth) {
    
                        //一旦换行,我们就可以判断当前行需要的宽和高了,所以此时要记录下来
                        allLines.add(lineViews);
                        lineHeights.add(lineHeight);
    
                        parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacing;
                        parentNeededWidth = Math.max(parentNeededWidth, lineWidthUsed + mHorizontalSpacing);
    
                        lineViews = new ArrayList<>();
                        lineWidthUsed = 0;
                        lineHeight = 0;
                    }
                    // view 是分行layout的,所以要记录每一行有哪些view,这样可以方便layout布局
                    lineViews.add(childView);
                    //每行都会有自己的宽和高
                    lineWidthUsed = lineWidthUsed + childMesauredWidth + mHorizontalSpacing;
                    lineHeight = Math.max(lineHeight, childMeasuredHeight);
    
                    //处理最后一行数据
                    if (i == childCount - 1) {
                        allLines.add(lineViews);
                        lineHeights.add(lineHeight);
                        parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacing;
                        parentNeededWidth = Math.max(parentNeededWidth, lineWidthUsed + mHorizontalSpacing);
                    }
    
                }
            }
    
    
    
            //再度量自己,保存
            //根据子View的度量结果,来重新度量自己ViewGroup
            // 作为一个ViewGroup,它自己也是一个View,它的大小也需要根据它的父亲给它提供的宽高来度量
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    
            int realWidth = (widthMode == MeasureSpec.EXACTLY) ? selfWidth: parentNeededWidth;
            int realHeight = (heightMode == MeasureSpec.EXACTLY) ?selfHeight: parentNeededHeight;
            setMeasuredDimension(realWidth, realHeight);
        }
    
        //布局
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            int lineCount = allLines.size();
    
            int curL = getPaddingLeft();
            int curT = getPaddingTop();
    
            for (int i = 0; i < lineCount; i++){
                List<View> lineViews = allLines.get(i);
    
                int lineHeight = lineHeights.get(i);
                for (int j = 0; j < lineViews.size(); j++){
                    View view = lineViews.get(j);
                    int left = curL;
                    int top =  curT;
    
    //                int right = left + view.getWidth();
    //                int bottom = top + view.getHeight();
    
                     int right = left + view.getMeasuredWidth();
                     int bottom = top + view.getMeasuredHeight();
                     view.layout(left,top,right,bottom);
                     curL = right + mHorizontalSpacing;
                }
                curT = curT + lineHeight + mVerticalSpacing;
                curL = getPaddingLeft();
            }
    
        }
    
    //    @Override
    //    protected void onDraw(Canvas canvas) {
    //        super.onDraw(canvas);
    //    }
    
        public static int dp2px(int dp) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
        }
    
    }
    

    2、子布局:

    <?xml version="1.0" encoding="utf-8"?>
    <ScrollView 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"
        tools:context=".MainActivity">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="8dp"
                android:text="搜索历史"
                android:textColor="@android:color/black"
                android:textSize="18sp"/>
            <com.example.flowlayout.FlowLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingLeft="10dp"
                android:layout_margin="8dp">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="水果味孕妇奶粉" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="儿童洗衣机" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="洗衣机全自动" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="小度" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="儿童汽车可坐人" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="抽真空收纳袋" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="儿童滑板车" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="稳压器 电容" />
    
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="羊奶粉" />
    
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="奶粉1段" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="图书勋章日" />
            </com.example.flowlayout.FlowLayout>
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="8dp"
                android:text="搜索发现"
                android:textColor="@android:color/black"
                android:textSize="18sp" />
            <com.example.flowlayout.FlowLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="8dp">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="惠氏3段" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="奶粉2段" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="图书勋章日" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="伯爵茶" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="阿迪5折秒杀" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="蓝胖子" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="婴儿洗衣机" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="小度在家" />
    
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="遥控车可坐" />
    
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="搬家袋" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="剪刀车" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="滑板车儿童" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="空调风扇" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="空鼓锤" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/shape_button_circular"
                    android:text="笔记本电脑" />
            </com.example.flowlayout.FlowLayout>
        </LinearLayout>
    
    </ScrollView>
    

    相关文章

      网友评论

          本文标题:什么是自定义View?

          本文链接:https://www.haomeiwen.com/subject/grmqjdtx.html