什么是自定義View?

1、自定義View分類(lèi)

1、自定義View

在沒(méi)有現(xiàn)成的View,需要自己實(shí)現(xiàn)的時(shí)候,就使用自定義View,一般繼承自View,SurfaceView或其他的View;

2、自定義ViewGroup

自定義ViewGroup一般是利用現(xiàn)有的組件根據(jù)特定的布局方式來(lái)組成新的組件,人多繼承自ViewGroup或各種Layout;

2、自定義View的圖

6df4334c5c4332bc10e6c4db0732332.png
78702912b20c0d41f59622014db4049.png

所以,自定義View任督二脈就在于此:

  • 自定義View主要是實(shí)現(xiàn) onMeasure + onDraw
  • 自定義ViewGroup主要是實(shí)現(xiàn)onMeasure + onLayout

3、View的層級(jí)

View的層級(jí).png
自定義流程.png

4、getMeasureWidth與getWidth的區(qū)別

21454b47aafa864a9361d28b28d02d4.png

5、Android中兩種坐標(biāo)系

Android屏幕坐標(biāo)系.png
視圖坐標(biāo)系.png

6、MeasureSpec 是什么 ?

MeasureSpec是View中的內(nèi)部類(lèi),基本都是二進(jìn)制運(yùn)算。由于int是32位的,用高兩位表示mode,低30位表示size,MODE SHIFT = 30的作用是移位

  • UNSPECIFIED:不對(duì)View大小做限制,系統(tǒng)使用
  • EXACTLY:確切的大小,如: 100dp
  • AT_MOST:大小不可超過(guò)某數(shù)值,如: matchParent,最大不能超過(guò)你爸爸

7、為什么要measure ?

計(jì)算大小.png
舉例說(shuō)明.png

8、Android中 lastLine怎么使用

lastLine是TextView中的一個(gè)屬性,用于指定文本的最后一行的行號(hào)。它可以用來(lái)控制文本的顯示方式,例如在最后一行添加省略號(hào)或者在最后一行顯示特定的文本。在Android中,lastLine屬性可以通過(guò)XML布局文件或者代碼動(dòng)態(tài)設(shè)置。

lastLine是TextView中的一個(gè)屬性,用于指定TextView中最后一行的行號(hào)??梢酝ㄟ^(guò)以下方式使用:

1、在XML布局文件中設(shè)置:

<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" />

在這個(gè)例子中,我們?cè)O(shè)置了TextView的最大行數(shù)為3,當(dāng)文本超過(guò)3行時(shí),將使用省略號(hào)來(lái)表示。同時(shí),我們將lastLine屬性設(shè)置為3,表示最后一行的行號(hào)為3。

2、在Java代碼中設(shè)置:

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

這個(gè)例子中,我們通過(guò)findViewById方法獲取了TextView的實(shí)例,并調(diào)用setLastLine方法將最后一行的行號(hào)設(shè)置為3。注意:lastLine屬性只在TextView的maxLines屬性設(shè)置為一個(gè)大于0的值時(shí)才有效。如果maxLines屬性設(shè)置為0或者不設(shè)置,lastLine屬性將不起作用。

9、Android visibleState使用

Android中的visibleState是一個(gè)狀態(tài)列表,用于定義視圖的可見(jiàn)性狀態(tài)。它可以用于定義視圖的不同狀態(tài),例如:可見(jiàn)、不可見(jiàn)、半透明等。
使用visibleState需要以下步驟:
1、在XML布局文件中定義狀態(tài)列表:

<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>

在視圖中設(shè)置狀態(tài)列表:

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

在代碼中設(shè)置視圖的可見(jiàn)性狀態(tài):

View myView = findViewById(R.id.my_view);
myView.setVisibility(View.VISIBLE); // 設(shè)置可見(jiàn)狀態(tài)
myView.setVisibility(View.INVISIBLE); // 設(shè)置不可見(jiàn)狀態(tài)
myView.setVisibility(View.GONE); // 設(shè)置隱藏狀態(tài)

注意:在使用visibleState時(shí),需要將視圖的背景設(shè)置為狀態(tài)列表。

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); //每個(gè)item橫向間距
    private int mVerticalSpacing = dp2px(8); //每個(gè)item橫向間距

    private List<List<View>> allLines = new ArrayList<>(); // 記錄所有的行,一行一行的存儲(chǔ),用于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();
    }
    //四個(gè)參數(shù) 自定義屬性

    private void clearMeasureParams() {
        allLines.clear();
        lineHeights.clear();
    }

    //度量
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        clearMeasureParams();//內(nèi)存 抖動(dòng)
        //先度量孩子
        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; //記錄這行已經(jīng)使用了多寬的size
        int lineHeight = 0; // 一行的行高

        int parentNeededWidth = 0;  // measure過(guò)程中,子View要求的父ViewGroup的寬
        int parentNeededHeight = 0; // measure過(guò)程中,子View要求的父ViewGroup的高

        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);

            LayoutParams childLP = childView.getLayoutParams();
            if (childView.getVisibility() != View.GONE) {
                //將layoutParams轉(zhuǎn)變成為 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) {

                    //一旦換行,我們就可以判斷當(dāng)前行需要的寬和高了,所以此時(shí)要記錄下來(lái)
                    allLines.add(lineViews);
                    lineHeights.add(lineHeight);

                    parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacing;
                    parentNeededWidth = Math.max(parentNeededWidth, lineWidthUsed + mHorizontalSpacing);

                    lineViews = new ArrayList<>();
                    lineWidthUsed = 0;
                    lineHeight = 0;
                }
                // view 是分行l(wèi)ayout的,所以要記錄每一行有哪些view,這樣可以方便layout布局
                lineViews.add(childView);
                //每行都會(huì)有自己的寬和高
                lineWidthUsed = lineWidthUsed + childMesauredWidth + mHorizontalSpacing;
                lineHeight = Math.max(lineHeight, childMeasuredHeight);

                //處理最后一行數(shù)據(jù)
                if (i == childCount - 1) {
                    allLines.add(lineViews);
                    lineHeights.add(lineHeight);
                    parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacing;
                    parentNeededWidth = Math.max(parentNeededWidth, lineWidthUsed + mHorizontalSpacing);
                }

            }
        }



        //再度量自己,保存
        //根據(jù)子View的度量結(jié)果,來(lái)重新度量自己ViewGroup
        // 作為一個(gè)ViewGroup,它自己也是一個(gè)View,它的大小也需要根據(jù)它的父親給它提供的寬高來(lái)度量
        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="兒童洗衣機(jī)" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/shape_button_circular"
                android:text="洗衣機(jī)全自動(dòng)" />

            <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="兒童汽車(chē)可坐人" />

            <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="兒童滑板車(chē)" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/shape_button_circular"
                android:text="穩(wěn)壓器 電容" />


            <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="圖書(shū)勛章日" />
        </com.example.flowlayout.FlowLayout>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:text="搜索發(fā)現(xiàn)"
            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="圖書(shū)勛章日" />

            <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="藍(lán)胖子" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/shape_button_circular"
                android:text="嬰兒洗衣機(jī)" />

            <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="遙控車(chē)可坐" />


            <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="剪刀車(chē)" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/shape_button_circular"
                android:text="滑板車(chē)兒童" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/shape_button_circular"
                android:text="空調(diào)風(fēng)扇" />

            <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>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容