亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

了解自定義View和繼承View,繼承ViewGroup,繼承已有View,繼承已有ViewGroup實例ji

2019-11-09 18:05:07
字體:
來源:轉載
供稿:網友

自定義View的分類

繼承View

當我們需要實現的效果是一個不規則效果的時候,那么這時就需要繼承 View 來實現了,我們需要重寫 onDraw 方法,在該方法里實現各種不規則的圖形和效果。當我們使用這種方式的時候,需要自己去處理 warp_content 和 padding。

繼承ViewGroup

當系統所提供的 LinearLayout、FrameLayout 等布局控件無法滿足我們的需求時,這時我們就需要使用這種方式來實現自己想要的布局效果了。當我們使用這種方式的時候,需要重寫 onLayout 方法來對子 View 進行布局,以及測量本身和子 View 寬高,還需要處理本身的 padding 和子 View 的 margin。

繼承已有View

當我們需要基于已有的 View 進行擴展或修改的時候,那么就可以使用這種方式。比如說,我們需要一個圓角的 ImageView,那么這時就可以繼承 ImageView 進行修改了。當我們使用這種方式的時候,一般不需要自己去處理 wrap_content 和 padding 等,因為系統控件已經幫我們做好了。

繼承已有布局

這種方式也叫做:自定義組合 View。該方式比較簡單,當我們需要將一組 View 組合在一起,方便后期復用的時候,就可以使用該方法。當我們使用這種方式的時候,不需要去處理 ViewGroup 的測量和布局流程,因為系統控件已經幫我們做好了。

那么下面我們就從實例的角度來看看自定義View吧

繼承View的實例

當我們自定義View繼承子View時,我們需要注意的細節有:1 View是wrap_content時需要手動測量View的寬高2 View有padding值的時候需要處理在這里我們寫一個規范的自定義View, 畫出一個圓注意: 要對 View 的 padding 和 LayoutParams 是 wrap_content 的情況進行處理,否則 padding 將會無法生效、wrap_content 的效果會和 match_parent 一樣其中重寫onMeasure方法, 判斷當是wrap_content的情況時,自己測量view的寬或高
package com.example.mycustomviewdemo;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.view.View;/** * 繼承View的自定義控件 * 注意 view是wrap_content時需要手動測量View的寬高 * View有padding值時需要處理 */public class MyCircleView extends View {    PRivate Paint mPaint;    private int mRadius;    public MyCircleView(Context context) {        this(context,null);    }    public MyCircleView(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public MyCircleView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init() {        mPaint = new Paint();   //初始化畫筆        mPaint.setColor(Color.GREEN);        mPaint.setAntiAlias(true);        mRadius = 80;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int width = 0;        int height =0;        if(widthMode == MeasureSpec.EXACTLY) {            width = widthSize;        }else {            //widthMode == MeasureSpec.AT_MOST模式 自己設置控件寬度            //當是wrap_content或者給具體dp的時候會走這里            width = mRadius * 2 +  getPaddingRight() + getPaddingLeft();        }        if(heightMode == MeasureSpec.EXACTLY) {            height = heightSize;        }else {            height = mRadius * 2 + getPaddingTop() + getPaddingBottom();        }        //注意最后 調用這個方法 讓屬性生效        setMeasuredDimension(width,height);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //處理padding        int pl = getPaddingLeft();        int pr = getPaddingRight();        int pt = getPaddingTop();        int pb = getPaddingBottom();        int width = getWidth() - pl - pr;  //控件本身的寬度        int height = getHeight() - pt - pb; //控件本身的高度        int centerX = width /2 + pl;  //中心點的橫坐標        int centerY = height /2  + pt;  //中心點的縱坐標        canvas.drawCircle(centerX,centerY,mRadius,mPaint);    }}

繼承ViewGroup實例

當我們自定義View繼承自ViewGroup的時候,需要實現孩子的onLayout方法指定子View的擺放位置,并且需要重寫 onMeasure 方法來測量大小。在這個實例當中,我們簡單模仿下 LinearLayout ,只不過只實現其 Vertical 模式,在這個實例當中,我們需要注意的細節有:1 ViewGroup是wrap_content時需要手動測量2 當ViewGroup本身有padding值的時候需要處理3 當子View有margin值時需要處理規范自定義ViewGroup, 這幾個細節我們要處理,代碼:
package com.example.mycustomviewdemo;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;/** * 繼承ViewGroup實例 * * 注意: * ViewGroup是wrap_content需要手動測量 * 當ViewGroup本身有padding值時要處理 * 當子view有margin值時要處理 */public class MySimpleVerticalLayout extends ViewGroup {    private Context mContext;    public MySimpleVerticalLayout(Context context) {        this(context,null);    }    public MySimpleVerticalLayout(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public MySimpleVerticalLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mContext = context;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //獲取ViewGroup測量模式  大小        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        //獲取ViewGroup的padding(內邊距)值        int pt = getPaddingTop();        int pb = getPaddingBottom();        int pl = getPaddingLeft();        int pr = getPaddingRight();        //先測量孩子, 才能得到孩子具體的寬高;    ------->> 這一步很重要        measureChildren(widthMeasureSpec,heightMeasureSpec);        int width = 0;        int height = 0;        int maxWidth = 0;        if(widthMode == MeasureSpec.AT_MOST) {            for(int i = 0; i < getChildCount();i++) {                View childAt = getChildAt(i);                if(childAt.getVisibility() == GONE) {                    continue;                }                //寬度為孩子中 最寬的一個                //孩子還有個MarginLayoutParams屬性                MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childAt.getLayoutParams();                int childWidth = childAt.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin;                maxWidth  = maxWidth > childWidth ? maxWidth : childWidth;            }            //將遍歷后的最寬的寬度加上左右內邊距 賦值            width = maxWidth + pl + pr;        }        if(heightMode == MeasureSpec.AT_MOST) {            for(int i = 0; i < getChildCount();i++) {                View childAt = getChildAt(i);                if(childAt.getVisibility() == GONE) {                    continue;                }                //高度為所有的孩子高度之和加上內邊距之和                MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childAt.getLayoutParams();                height += childAt.getMeasuredHeight() + marginLayoutParams.topMargin + marginLayoutParams.bottomMargin;            }            //最終的高度            height += (pt + pb);        }        //做判斷, 并將值設置        setMeasuredDimension(widthMode == MeasureSpec.AT_MOST ? width : widthSize,heightMode == MeasureSpec.AT_MOST ? height : heightSize);    }    /**     * 對子View進行擺放     * @param changed     * @param l     * @param t     * @param r     * @param b     */    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        //viewGroup的padding值影響孩子的擺放        int pt = getPaddingTop();        int pb = getPaddingBottom();        int pl = getPaddingLeft();        int pr = getPaddingRight();        int cl = 0;        int ct = 0;        int cr = 0;        int cb = 0;        int bm = 0;     //這個bm很神奇        for(int i =0; i < getChildCount();i++) {            //判斷當子view沒有被Gone掉時候            View childAt = getChildAt(i);            if(childAt.getVisibility() != GONE) {                //計算每個View的位置                MarginLayoutParams marginLayoutParams= (MarginLayoutParams) childAt.getLayoutParams();                cl = marginLayoutParams.leftMargin;                ct += marginLayoutParams.topMargin;                cr = childAt.getMeasuredWidth() + marginLayoutParams.leftMargin;                cb += childAt.getMeasuredHeight() + marginLayoutParams.topMargin;                //對子View進行布局,  注意 一定要調用childAt.layout()方法                childAt.layout(cl + pl, ct + pt + bm, cr + pr,cb + pb + bm);                ct += childAt.getMeasuredHeight();                bm += marginLayoutParams.bottomMargin;            }        }    }    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new MarginLayoutParams(mContext, attrs);    }}

繼承已有View的實例

繼承自系統已有View時,一般是對其原有功能進行擴展或者修改, 比如一個Button  在這里注意監聽器的使用

繼承已有ViewGroup的實例

這種自定義 View 的實現方式也叫做:“自定義組合控件”,是一種比較簡單的自定義 View 方式。使用這種方式時,由于是繼承已有的系統控件,所以我們不需去測量、布局、處理 margin、padding等,因為系統控件本身已經處理好了。當我們的項目中有一些布局在很多地方都要用到的話,那么第一時間肯定就要想到復用了。復用的話,有人可能會想到使用 include 復用布局,但是如果這樣的話,當布局改動性很大時,使用 include 并不是很靈活。這時候,就可以使用 ”繼承已有 ViewGroup“ 這種方式了。下面一個實例,就拿我們平時可能經常要寫的 Item 為例吧:
package com.example.mycustomviewdemo;import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.View;import android.widget.FrameLayout;import android.widget.ImageView;import android.widget.TextView;/** * 繼承已有的ViewGroup 自定義View的實例,常用item布局 */public class MyCustomItemLayout extends FrameLayout {    private Context mContext;    private String mLeftText;    private int mRightImageResourceId;    private String mRightText;    private TextView mTxt_left;    private TextView mTxt_right;    private ImageView mImg_right;    public void setLeftText(String leftText) {        mLeftText = leftText;    }    public void setRightImageResourceId(int rightImageResourceId) {        mRightImageResourceId = rightImageResourceId;    }    public void setRightText(String rightText) {        mRightText = rightText;    }    public MyCustomItemLayout(Context context) {        this(context,null);    }    public MyCustomItemLayout(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public MyCustomItemLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        this.mContext = context;        //取出自定義屬性        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyCustomItemLayout);        mLeftText = typedArray.getString(R.styleable.MyCustomItemLayout_leftText);        //默認圖片為箭頭        mRightImageResourceId = typedArray.getResourceId(R.styleable.MyCustomItemLayout_rightImage, R.drawable.ic_arrow_right);        mRightText = typedArray.getString(R.styleable.MyCustomItemLayout_rightText);        typedArray.recycle();  //回收釋放資源        initView();        initData();    }    private void initData() {        //兩種初始化數據的方法,  外界通過set方法進行設置; 布局中直接定義        mTxt_left.setText(mLeftText);        mTxt_right.setText(mRightText);        mImg_right.setImageResource(mRightImageResourceId);    }    private void initView() {        //注意  這第二個參數傳 this;  兩個參數的方法默認會調用三個參數的方法,  第二個參數不為null時,相當于三個參數中root不為null,attach為true        View view = LayoutInflater.from(mContext).inflate(R.layout.layout_customitem, this);        mTxt_left = (TextView) findViewById(R.id.txt_left);        mTxt_right = (TextView) findViewById(R.id.txt_right);        mImg_right = (ImageView) findViewById(R.id.img_right);    }}首先自定義一個類,繼承自 FrameLayout,當然,這里你也可以選擇繼承 LinearLayout 或者其他,根據具體需求來。其中在構造中獲取了自定義屬性,最主要的地方就是填充布局那里,將布局填充到了當前控件也就是自定義的 ViewGroup 上。填充的布局如下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="wrap_content"              android:background="?android:selectableItemBackground"              android:gravity="center_vertical"              android:padding="15dp">    <TextView        android:id="@+id/txt_left"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:drawablePadding="5dp"        android:ellipsize="end"        android:maxLines="1"        android:textColor="@color/text_black"        android:textSize="@dimen/txt14"/>    <TextView        android:id="@+id/txt_right"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:layout_marginLeft="10dp"        android:layout_weight="1"        android:ellipsize="end"        android:gravity="right"        android:maxLines="1"        android:textSize="@dimen/txt14"/>    <ImageView        android:id="@+id/img_right"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginLeft="5dp"        android:src="@mipmap/ic_arrow_right"/></LinearLayout>在項目中 有相類似的Item布局的使用時, 可以直接在布局中通過自定義屬性設置數據:
<com.example.mycustomviewdemo.MyCustomItemLayout       android:layout_width="match_parent"       android:layout_height="wrap_content"       android:layout_marginTop="10dp"       app:leftText="版本更新"       app:rightText="V1.1"       app:rightImage="@drawable/ic_arrow_right"       />也可以通過暴露的方法設置數據至此,自定義控件四種繼承方式講解完畢,  下面看一三個自定義控件的效果
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲欧美日韩精品久久奇米色影视| 日韩中文字幕av| 91久久嫩草影院一区二区| 国产精品久久久久aaaa九色| 欧美性开放视频| 欧美丝袜美女中出在线| 精品成人国产在线观看男人呻吟| 欧美日韩国产在线看| 在线观看久久久久久| 亚洲人成电影在线观看天堂色| 久久免费精品日本久久中文字幕| 欧美黄色www| 亚洲女人被黑人巨大进入| 久久久之久亚州精品露出| 亚洲国产成人在线视频| 成人网中文字幕| 91精品久久久久久久久中文字幕| 国产精品久久久久久久午夜| 这里只有视频精品| 中文字幕日韩欧美精品在线观看| 欧美日韩亚洲高清| 国产精品亚洲欧美导航| 成人国产精品久久久| 懂色av中文一区二区三区天美| 国产成人欧美在线观看| 欧美黄色片在线观看| 97久久久久久| 欧美性xxxx极品hd欧美风情| 亚洲激情久久久| 亚洲一级一级97网| 欧美精品videos性欧美| 成人在线小视频| 亚洲黄在线观看| 国产精品午夜一区二区欲梦| 亚洲成av人片在线观看香蕉| 久久精品成人动漫| 色樱桃影院亚洲精品影院| 庆余年2免费日韩剧观看大牛| 中文字幕免费精品一区| 精品国产成人在线| 久久福利视频导航| 欧美成人性色生活仑片| 亚洲欧美日韩精品久久奇米色影视| 日韩av网站导航| 2023亚洲男人天堂| 欧美影院成年免费版| 国产精品对白刺激| 成人黄色av网| 国产欧美亚洲精品| 国产视频丨精品|在线观看| 91中文在线观看| 亚洲第一黄色网| 亚洲aa中文字幕| 国产精品美女久久| 懂色av中文一区二区三区天美| 国产精品网红直播| 久久久国产视频| 国产在线观看不卡| 色偷偷88888欧美精品久久久| 亚洲欧美日韩爽爽影院| 亚洲色图校园春色| 亚洲第一区第一页| 性欧美暴力猛交69hd| 97国产一区二区精品久久呦| 国产999精品久久久影片官网| 亚洲免费一在线| 欧美性xxxxx极品| 中文字幕av一区| 91网站免费观看| 日韩暖暖在线视频| 亚洲免费视频网站| 精品色蜜蜜精品视频在线观看| 国产精品视频免费在线观看| 91深夜福利视频| 日韩免费电影在线观看| 欧美成人亚洲成人日韩成人| 精品无人区太爽高潮在线播放| 久热精品在线视频| 亚洲国产精品va在线看黑人| 欧美精品一区二区免费| 亚洲欧美日韩图片| 日韩亚洲第一页| 国模吧一区二区| 亚洲国产日韩欧美在线动漫| 欧美国产第二页| 久久精品青青大伊人av| 亚洲精品视频在线观看视频| 日韩欧美国产一区二区| 亚洲高清在线观看| 麻豆国产va免费精品高清在线| 国产精品九九九| 欧美电影免费观看大全| 国产精品吊钟奶在线| 中文字幕国产精品久久| 国产精品爽黄69| www.欧美精品一二三区| 欧美激情精品久久久久久大尺度| 精品久久久久久久中文字幕| 亚洲精品日产aⅴ| 国产午夜精品全部视频在线播放| 亚洲欧美www| 欧美激情中文网| 亚洲精品视频网上网址在线观看| 亚洲国产婷婷香蕉久久久久久| 97久久精品国产| 久久久欧美精品| 91亚洲国产精品| 国产综合久久久久| 亚洲成人激情在线观看| 亚洲精品欧美一区二区三区| 亚洲免费福利视频| 97视频人免费观看| 日韩av电影在线播放| 一区二区av在线| 亚洲一级一级97网| 亚洲国产日韩欧美综合久久| 成人97在线观看视频| 国产91免费观看| 91精品国产色综合久久不卡98| 精品国产视频在线| 欧美亚洲视频在线看网址| 欧美精品videossex性护士| 日韩在线视频免费观看高清中文| 一区二区三区国产在线观看| 国产精品视频久| 久久久久久久久久久av| 欧美性猛交xxxx久久久| 国产女精品视频网站免费| 欧美人成在线视频| 精品国产欧美成人夜夜嗨| 国产精品久久一区| 国内精品久久久久久久| 668精品在线视频| 91精品久久久久久久久久久久久久| 91av视频在线| 国产成+人+综合+亚洲欧美丁香花| 成人在线观看视频网站| 欧美激情视频在线| 日韩精品视频中文在线观看| 日韩中文在线中文网在线观看| 国产精品扒开腿做| 精品爽片免费看久久| 中文字幕亚洲综合久久筱田步美| 亚洲欧美国产精品专区久久| 成人中心免费视频| www国产精品视频| 久久免费高清视频| 97精品久久久中文字幕免费| 欧美孕妇孕交黑巨大网站| 国产在线高清精品| 日韩网站免费观看高清| 欧美另类老女人| 伊人av综合网| 亚洲激情 国产| 欧美理论电影在线播放| 欧美中文字幕精品| 亚洲精品电影网在线观看| 成人性生交大片免费看小说| 欧美电影免费看| 国产精品十八以下禁看| 亚洲精品免费网站| 日韩欧美一区二区三区| 欧美日韩ab片| 欧美日本中文字幕|