国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android中使用自定義ViewGroup的總結

2019-12-12 04:01:50
字體:
來源:轉載
供稿:網友

分類

自定義Layout可以分為兩種情況。

  • 自定義ViewGroup,創造出一些不同于LinearLayout,RelativeLayout等之類的ViewGroup。比如:API 14以后增加的GridLayout、design support library中的CoordinatorLayout等等。
  • 自定義一些已經有的Layout然后加一些特殊的功能。比如:TableLayout以及percent support library中的PercentFrameLayout等等。

流程

自定義View的流程是:onMeasure()->onLayout()->onDraw()。自定義ViewGroup的時候一般是不要去實現onDraw的,當然也可能有特殊的需求,比如:CoordinatorLayout。

所以onMeasure和onLayout基本能做大部分我們接觸的ViewGroup。但是僅僅的知道在onMeasure中測量ViewGroup的大小以及在onLayout中計算Child View的位置還是不夠。

比如:怎么可以給ViewGroup的Child View設置屬性?

一個例子。

寫一個自定義的ViewGroup,增加一個屬性控制Child View的大小(長寬)占ViewGroup的比例。

假設是一個LinearLayout,那么就先定義一個CustomLinearLayout。

public class CustomLinearLayout extends LinearLayout {  public CustomLinearLayout(Context context) {    super(context);  }  public CustomLinearLayout(Context context, AttributeSet attrs) {    super(context, attrs);  }  public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);  }  @TargetApi(Build.VERSION_CODES.LOLLIPOP)  public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {    super(context, attrs, defStyleAttr, defStyleRes);  }}

其它拋開不說,我們是需要增加屬性用來控制Child View的大小。那么就先在value/attr.xml中定義那個屬性(使用CustomLinearLayout_Layout來與CustomLinearLayout區分下,當然這個名字是隨意的)。

<declare-styleable name="CustomLinearLayout_Layout">  <!-- 定義比例 -->  <attr name="inner_percent" format="float"/></declare-styleable>

ViewGroup調用addView()的時候最終都會調用到這個方法。

public void addView(View child, int index, LayoutParams params)

這個params代表的就是View的配置,ViewGroup.LayoutParams中就包含了width、height,LinearLayout.LayoutParams增加了weight屬性等等。那么我們就應該實現一個LayoutParams。那么現在就是這樣了。

public class CustomLinearLayout extends LinearLayout {  public CustomLinearLayout(Context context) {    super(context);  }  public CustomLinearLayout(Context context, AttributeSet attrs) {    super(context, attrs);  }  public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);  }  @TargetApi(Build.VERSION_CODES.LOLLIPOP)  public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {    super(context, attrs, defStyleAttr, defStyleRes);  }  public static class LayoutParams extends LinearLayout.LayoutParams {    private float innerPercent;    private static final int DEFAULT_WIDTH = WRAP_CONTENT;    private static final int DEFAULT_HEIGHT = WRAP_CONTENT;    public LayoutParams() {      super(DEFAULT_WIDTH, DEFAULT_HEIGHT);      innerPercent = -1.0f;    }    public LayoutParams(float innerPercent) {      super(DEFAULT_WIDTH, DEFAULT_HEIGHT);      this.innerPercent = innerPercent;    }    public LayoutParams(ViewGroup.LayoutParams p) {      super(p);    }    @TargetApi(Build.VERSION_CODES.KITKAT)    public LayoutParams(LinearLayout.LayoutParams source) {      super(source);    }    @TargetApi(Build.VERSION_CODES.KITKAT)    public LayoutParams(LayoutParams source) {      super(source);      this.innerPercent = source.innerPercent;    }    public LayoutParams(Context c, AttributeSet attrs) {      super(c, attrs);      init(c, attrs);    }    private void init(Context context, AttributeSet attrs) {      TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomLinearLayout_Layout);      innerPercent = a.getFloat(R.styleable.CustomLinearLayout_Layout_inner_percent, -1.0f);      a.recycle();    }  }}

現在就可以在xml使用我們的屬性了。

<?xml version="1.0" encoding="utf-8"?><com.egos.samples.custom_layout.CustomLinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:app="http://schemas.android.com/apk/res-auto"  android:layout_width="200dp"  android:layout_height="200dp"  android:id="@+id/test_layout"  android:background="#ffff0000"  android:gravity="center"  android:orientation="vertical">  <ImageView    android:text="Egos"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:onClick="add"    android:background="#ff00ff00"    app:inner_percent="0.8"/></com.egos.samples.custom_layout.CustomLinearLayout>

只是然并軟,并沒有作用。

那么到底是怎么去控制Child View的大小呢?當然是在onMeasure控制的。addView會執行下面的代碼。

requestLayout();invalidate(true);

這樣的話就會重新的走一遍onMeasure(),onLayout()了。實現onMeasure()的方法以后直接去處理Child View的大小,因為我繼承的是LinearLayout,所以其實是會處理到measureChildBeforeLayout()。最終是在measureChildBeforeLayout的時候來處理Child View的大小。

@Override protected void measureChildWithMargins(View child, int parentWidthMeasureSpec,                    int widthUsed, int parentHeightMeasureSpec, int heightUsed) {  // 在xml強制寫成match_parent,然后在這里強制設置成  if (child != null && child.getLayoutParams() instanceof LayoutParams &&      ((LayoutParams) child.getLayoutParams()).innerPercent != -1.0f) {    parentWidthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (MeasureSpec.getSize(parentWidthMeasureSpec) *        ((LayoutParams) child.getLayoutParams()).innerPercent), MeasureSpec.getMode(parentWidthMeasureSpec));    parentHeightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (MeasureSpec.getSize(parentHeightMeasureSpec) *        ((LayoutParams) child.getLayoutParams()).innerPercent), MeasureSpec.getMode(parentHeightMeasureSpec));    super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,      parentHeightMeasureSpec, heightUsed);  } else {    super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,        parentHeightMeasureSpec, heightUsed);  }}

這樣就可以實現最開始的需求了。

其實還有一些細節是需要處理的,下面的代碼就是。

/** * 當checkLayoutParams返回false的時候就會執行到這里的generateLayoutParams */ @Overrideprotected LinearLayout.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {  return super.generateLayoutParams(lp);}/** * 當addView的時候沒有設置LayoutParams的話就會默認執行這里的generateDefaultLayoutParams */@Overrideprotected LayoutParams generateDefaultLayoutParams() {  return new LayoutParams();}/** * 寫在xml中屬性的時候就會執行這里的generateLayoutParams */@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {  return new LayoutParams(getContext(), attrs);}

總結一下

  • 自定義View和ViewGroup需要多多注意的都是onMeasure、onLayout、onDraw。
  • 把ViewGroup自身的屬性和Child View的屬性區分開。
  • 可以多多的參考support包中的代碼,調試也非常的方便。

做Android開發,自身需要自定義View的地方確實是比較的多,只是大部分都會有相應的開源庫。但是我們還是應該需要熟練的知道該如何自定義一個ViewGroup。

自己是一個比較健忘的人,所以寫的詳細點。

完整的代碼戳這里。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 南皮县| 科尔| 理塘县| 墨江| 邯郸市| 增城市| 乌拉特前旗| 志丹县| 库尔勒市| 南京市| 民权县| 南平市| 彭泽县| 阳曲县| 房山区| 肥东县| 鸡泽县| 莒南县| 邯郸县| 巴彦淖尔市| 黄骅市| 商城县| 简阳市| 遂川县| 高碑店市| 乌拉特中旗| 松滋市| 五峰| 车险| 庄浪县| 江口县| 桐梓县| 新野县| 邳州市| 乳源| 榆树市| 广德县| 宜州市| 弥勒县| 华蓥市| 台山市|