自定義View(一) 自定義View的概述

不怕跌倒,所以飛翔

自定義View概述

1.自定義View分類

  • 自定義View 直接繼承View主要是繪制
  • 自定義ViewGroup 繼承ViewGroup主要是計算所有子控件的大小和位置
  • 繼承相應的View,如TextView,Button,LinearLayout等

2.自定義View的流程

自定義view的繪制流程

3.相應的構造函數(shù):

當你繼承View會有4個相應的構造方法:

public void SloopView(Context context) {}
public void SloopView(Context context, AttributeSet attrs) {}
public void SloopView(Context context, AttributeSet attrs, int defStyleAttr) {}
public void SloopView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {}
  • 第一個是new對象的時候調用的方法
  • 第二個是在布局文件中使用的時候調用的方法
  • 第三個是設置主題的時候調用的方法,這里你可以指定,也可以寫死
  • 第四個是在21版本新添加的方法,暫且不論

4.View的測量(onMeasure)

這個方法的作用是用來測量View的相應的方法,基本上有固定的模板代碼,其實就是計算整個View占用的大小

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        int realWidth;/*真是的寬度*/
        int realHeight;/*真是的高度*/

        if (widthMode == MeasureSpec.EXACTLY) {
            realWidth = width;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            realWidth = 500;/*這里是定義的最大值*/
        } else {
            realWidth = 500;/*未知寬度的時候*/
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            realHeight = height;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            realHeight = 500;/*這里是定義的最大值*/
        } else {
            realHeight = 500;/*未知高度的時候*/
        }

        setMeasuredDimension(realWidth, realHeight);
    }

這里記住相應的三種狀態(tài):

  • AT_MOST 最大值,但是不會超過父容器
  • EXACTLY 具體指,指定了具體的大小
  • UNSPECIFIED 未知大小,這里是父容器沒有指定相應的大小(其實上面的兩種狀態(tài)考慮到的話就可以不用去設置這個了)

上面這個例子基本上就是onMeasure的模板代碼,但是有的控件涉及到重繪界面,那么只要把相應的realWidth和realHeight寫成動態(tài)的就可以了.但是基本的邏輯是不會改變的...

5.View的繪制(onDraw)

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

這個方法主要涉及到Canvas的相應操作,后面會單提出來去講.其實就是相應的API的一些繪制操作.

6.View大小的改變操作(onSizeChanged)

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

其實這個方法是確定View大小的方法,但是如果你調用** requestLayout();**方法的時候是強制重繪,整個繪制流程都會重新走一遍,也就是說onMeasue(),onSizeChanged()和onDraw()都會重新執(zhí)行,這樣也就達到了相應的改變View的效果了,這種一般都是和手勢有關的View.

7.子View位置的確定(onLayout)

確定布局的函數(shù)是onLayout,它用于確定子View的位置,在自定義ViewGroup中會用到,他調用的是子View的layout函數(shù)。


View位置的確定

其實這里面只有一張圖的事情,理解了這張圖就能更好的設置相應的位置了.

8.相應的屬性值

其實這部分的代碼也是相應的模板代碼,只要記住了就行.

  • 在相應的res文件夾下創(chuàng)建一個attrs的xml文件,用來實現(xiàn)自定義View的style(也就是可以使用的屬性)
        <declare-styleable name="HorizontalEditItemView">
            <attr name="title" format="string" />
            <attr name="etHint" format="string" />
        </declare-styleable>
    
    

這里的屬性你可以隨意定義,只要符合你的習慣就行

  • 在自定義View中使用該屬性
           TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HorizontalEditItemView);
            String title = typedArray.getString(R.styleable.HorizontalEditItemView_title);
            String etHint = typedArray.getString(R.styleable.HorizontalEditItemView_etHint);
              
            typedArray.recycle();
    

這里使用完TypedArray之后一定要進行釋放.


概述的內容就這么多,其實寫的挺晦澀的,這里講的太仔細的話,效果還是一樣的,只有你真正的去使用,才能去理解.這里只是一個概述,后面的文章會在使用的時候更加完善的講解!

參考文獻:
GcsSloop的自定義系類文章
Carson_Ho關于自定義的文章

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容