中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android中如何自定義View

發布時間:2021-07-20 15:04:30 來源:億速云 閱讀:135 作者:Leah 欄目:移動開發

這篇文章給大家介紹Android中如何自定義View,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

 前言

View,有很多的名稱。不論是你熟知的布局,還是控件,他們全部都繼承自View。

Android中如何自定義View

文內部分圖片轉載自Carson_Ho大佬的文章

思維導圖

Android中如何自定義View

工作流程

measure

其實通過layout中的第二張圖我們已經知道了控件大小的計算了。

  • height = bottom - top

  • width = right - left

對于ViewGroup而言,就是對容器內子控件的遍歷和計算了。

因為直接繼承自View的控件使用wrap_cotent和match_parent是顯示出來的效果是相同的。需要我們使用MeasureSpec中的getMode()方法來對當前的模式進行區分和比較。

模式狀態
UNSPECIFIED未指定模式,View想多大就多大,父容器不做限制,一般用于系統內部的測量
AT_MOST最大模式,對應wrap_content,View的大小不大于SpecSize的值
EXACTLY精確模式,對應match_parent,View的大小為SpecSize的值
@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);          // 類似這樣的判斷,后面不過多復述         // 用于判斷是不是wrap_content         // 如果不進行處理,效果會是match_parent         if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){             setMeasuredDimension(20, 20);         } }

layout

在確定位置時,我們有一個非常需要主要的地方—— 坐標系。

Android系統的坐標系和平時畫的坐標系并不相同。

Android中如何自定義View

所以相對應的,我們的位置計算方法自然和我們原來的正好是相反的。

Android中如何自定義View

4個頂點的位置分別由4個值決定:

  • top:子View上邊界到所在容器上邊界的距離。

  • left:子View左邊界到所在容器左邊界的距離。

  • bottom:子View下邊界到所在容器上邊界的距離。

  • right:子View右邊界到所在容器左邊界的距離。

所有的計算都是相對于所在容器才能夠開始的。

draw

一共有6個步驟:

  1. 如果需要,則繪制背景 --drawBackground(canvas);

  2. 保存當前canvas層 --saveCount = canvas.getSaveCount();

  3. 繪制View的內容 --if (!dirtyOpaque) onDraw(canvas);

  4. 繪制子View --dispatchDraw(canvas);

  5. 如果需要,則繪制View的褪色邊緣,類似于陰影效果 --canvas.restoreToCount(saveCount);

  6. 繪制裝飾,比如滾動條 --onDrawForeground(canvas);

關于開發者需要重寫的方法一般是第三步繪制View的內容對應的onDraw()。

private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);     @Override     protected void onDraw(Canvas canvas) {         super.onDraw(canvas);         int width = getWidth();         int height = getHeight();         // 在畫布上進行類似這樣的操作         canvas.drawLine(0, height/2, width,height/2, paint);     }

入門自定義View

在日常項目的布局文件中我們經常會使用到xmlns:app="http://schemas.android.com/apk/res-auto"這樣標簽,其實他就是用來引入我們自定義的標簽使用的。

1.在res/values目錄下創建attrs

<?xml version="1.0" encoding="utf-8"?> <resources>     <declare-styleable name="DefaultView">         <attr name="color" format="color"/>     </declare-styleable> </resources>

2.在DefaultView(Context context, @Nullable AttributeSet attrs)中獲取。以下是整個完整代碼。

/**  * author: ClericYi  * time: 2020-01-30  */ public class DefaultView extends View {     private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);     private int mColor = Color.RED;      public DefaultView(Context context, @Nullable AttributeSet attrs) {         super(context, attrs);         initAttrs(context, attrs);         initDraw();     }      private void initAttrs(Context context, @Nullable AttributeSet attrs) {         TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DefaultView);         // 從styleable中獲取的名字是系統會生成的,一般是 類名_name 的形式         mColor = array.getColor(R.styleable.DefaultView_color, Color.GREEN);         // 獲取完資源后即使回收         array.recycle();     }      private void initDraw() {         paint.setColor(mColor);         paint.setStrokeWidth(3f);     }      @Override     protected void onDraw(Canvas canvas) {         super.onDraw(canvas);         int width = getWidth();         int height = getHeight();         canvas.drawLine(0, height/2, width,height/2, paint);     }      @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);          if(widthMode == MeasureSpec.AT_MOST){             setMeasuredDimension(20, 20);         }     } }

基礎的性能優化

首先的話我們先了解如何去知道一個View是否被過度繪制了?

其實在我們手機中的開發模式已經存在這個選項了。

Android中如何自定義View


下方給出繪制的次數對應圖

Android中如何自定義View

那如何做到性能優化呢?

在這個問題之前,需要了解什么是過度繪制,你可以理解為同一位置的控件不斷的疊加而產生的無用數據,那我們就來說說集中解決方案吧。

方案1:減少嵌套層數。

Android中如何自定義View

因為只是一個案例,想說的意思,如果多個LinearLayout嵌套實現的效果,如果能被一個ConstraintLayout直接實現,那么就用后者替代,因為不會這樣在同一個區域重復出現。

方案2:去除默認的背景

Android中如何自定義View

這個解決方案其實針對的背景會被自動繪制的問題,如果我們把這個層次消去,從繪制角度老說也是一種提升了。正如圖示一般直接減少了一層的繪制。

在代碼中的具體表現,通過對style.xml中的Theme進行修改:

<item name="android:windowBackground">@null</item>

總結

Android中如何自定義View

關于Android中如何自定義View就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

石景山区| 政和县| 永仁县| 牙克石市| 渝中区| 蒙山县| 甘洛县| 曲阜市| 新蔡县| 昭通市| 溧阳市| 济阳县| 宝应县| 尖扎县| 上高县| 屏东市| 商丘市| 赤水市| 兰坪| 奈曼旗| 德庆县| 延边| 金华市| 乐至县| 永济市| 繁峙县| 洪洞县| 枣庄市| 乌兰浩特市| 玉环县| 德兴市| 开封县| 河北省| 鹰潭市| 政和县| 洞头县| 二连浩特市| 衡水市| 平遥县| 疏附县| 思南县|