自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android: 自定義View

移動開發(fā) Android
如果功能布局要求非常定制化,已經(jīng)不能由Android內(nèi)置的View創(chuàng)建 —這時候就需要使用自定義View了。而這意味著在大多數(shù)情況下,我們將需要相當(dāng)長的時間來完成它。但這并不意味著我們不應(yīng)該這樣做,因為實現(xiàn)它是非常令人興奮和有趣的。

簡介

每天我們都會使用很多的應(yīng)用程序,盡管他們有不同的約定,但大多數(shù)應(yīng)用的設(shè)計是非常相似的。這就是為什么許多客戶要求使用一些其他應(yīng)用程序沒有的設(shè)計,使得應(yīng)用程序顯得獨特和不同。

如果功能布局要求非常定制化,已經(jīng)不能由Android內(nèi)置的View創(chuàng)建 —這時候就需要使用自定義View了。而這意味著在大多數(shù)情況下,我們將需要相當(dāng)長的時間來完成它。但這并不意味著我們不應(yīng)該這樣做,因為實現(xiàn)它是非常令人興奮和有趣的。

我最近面臨了類似的情況:我的任務(wù)是使用ViewPager實現(xiàn)Android應(yīng)用引導(dǎo)頁。不同于iOS,Android并沒有提供這樣的View,所以我不得不編寫一個自定義View來實現(xiàn)它。

我花了一些時間來實現(xiàn)它。幸運(yùn)的是,時下很多開源項目都有類似可復(fù)用的View,這節(jié)省了我和其他開發(fā)者的時間。我決定基于這種View創(chuàng)建一個公共庫。如果你有類似的功能需求并且缺乏時間實現(xiàn)它,可以在github repo發(fā)現(xiàn)它。 

 

 

Sample of using PageIndicatorView 

Sample of using PageIndicatorView

繪制!

因為編寫自定義View比起普通的View更耗時,你應(yīng)該只在為了實現(xiàn)特定的功能但沒有更簡單的方法情況下使用自定義View,或者你希望通過自定義View解決以下問題:

  1. 性能。如果你布局里面有很多View,你想通自定義View優(yōu)化它,使其更輕量。
  2. 視圖層次結(jié)構(gòu)復(fù)雜。
  3. 一個完全自定義的View,需要手動繪制才能實現(xiàn)。

如果你還沒有嘗試過編寫自定義View,這篇文章將教會你繪制扁平的自定義View的一些技巧。我將會告訴你整體的視圖結(jié)構(gòu),如何實現(xiàn)具體的功能,不要重犯常見的錯誤,以及實現(xiàn)動畫效果!

我們需要知道的***件事 –View的生命周期。不知出于某種原因,谷歌并沒有提供View生命周期的圖表,由于開發(fā)者普遍對其有誤解,導(dǎo)致了一些意想不到的錯誤和問題,所以我們要認(rèn)清這過程。 

 

 

View生命周期的圖表 

構(gòu)造函數(shù)

每個View的生命都是從構(gòu)造函數(shù)開始。而且這是一個繪制初始化,進(jìn)行各種計算,設(shè)定默認(rèn)值或做任何我們需要的事情很好的地方。

但是,為了使我們的View更易于使用和配置,Android提供了很有用的AttributeSet接口。它很容易實現(xiàn),而且絕對值得花時間去了解和實現(xiàn)它,因為它會幫助你(和你的團(tuán)隊)通過靜態(tài)參數(shù)來設(shè)置View,對于以后新特性加入或者新屏幕拓展性支持也更好。

首先,創(chuàng)建一個新的文件attrs.xml。所有不同的自定義View屬性都可以放在該文件中。正如你看到的這個例子,我們有一個PageIndicatorView和它的唯一屬性piv_count。 

 

 

Custom Attributes sample 

Custom Attributes sample

緊接著在View的構(gòu)造函數(shù)中,你需要獲取這個屬性并使用它,如下圖所示。

  1. public PageIndicatorView(Context context, AttributeSet attrs) { 
  2.     super(context, attrs); 
  3.     TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.PageIndicatorView); 
  4.     int count = typedArray.getInt(R.styleable.PageIndicatorView_piv_count,0); 
  5.     typedArray.recycle(); 
  6.  

注意:

  • 在創(chuàng)建自定義屬性使用一個簡單的前綴,以避免與其它View類似的屬性名稱沖突。一般我們使用View名稱縮寫,就像例子中的piv_。
  • 如果你使用的是Android Studio,一旦你使用完屬性,lint會建議你調(diào)用recycle()方法 。The reason is just to get rid of inefficiently bound data that’s not gonna be used again。[譯者注:翻譯有點拗口,其實就是回收TypedArray,以便后面重用]

onAttachedToWindow

父View調(diào)用addView(View)后,這個View將被依附到一個窗口。在這個階段,我們的View會知道它被包圍的其他view。如果你的View和其他View在相同的layout.xml,這是通過id找到他們的好地方(你可以通過屬性進(jìn)行設(shè)置),同時可以保存為全局(如果需要)的引用。

onMeasure

這意味著我們的自定義View到了處理自己的大小的時候。這是非常重要的方法,因為在大多數(shù)情況下,你的View需要有特定的大小以適應(yīng)你的布局。

當(dāng)你重寫此方法,需要記得的是,最終要設(shè)置setMeasuredDimension(int width, int height) 。 

 

 

onMeasure 

onMeasure

當(dāng)處理自定義View的大小時候,使用者可能通過layout.xml或者動態(tài)設(shè)置了具體的大小。要正確地計算它,我們需要做幾件事情。

1.計算你的View內(nèi)容所需的大小(寬度和高度)。

2.獲取你的View MeasureSpec大小和模式(寬度和高度)。

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
  2.         int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
  3.         int widthSize = MeasureSpec.getSize(widthMeasureSpec); 
  4.         int heightMode = MeasureSpec.getMode(heightMeasureSpec); 
  5.         int heightSize = MeasureSpec.getSize(heightMeasureSpec); 
  6.     }  

3.檢查MeasureSpec 設(shè)置和調(diào)整View(寬度和高度)的尺寸模式。

  1. int width; 
  2.   if (widthMode == MeasureSpec.EXACTLY) { 
  3.      width = widthSize; 
  4.    } else if (widthMode == MeasureSpec.AT_MOST) { 
  5.      width = Math.min(desiredWidth, widthSize); 
  6.   } else { 
  7.     width = desiredWidth; 
  8.   }  

注意:

看看MeasureSpec的值:

  • MeasureSpec.EXACTLY 意味著硬編碼大小值,所以你應(yīng)該設(shè)置指定的寬度或高度。
  • MeasureSpec.AT_MOST 用于表明你的View匹配父View的大小,所以它應(yīng)該和他想要的大小一樣大。

[譯者注:此時View尺寸只要不超過父View允許的***尺寸即可]

  • MeasureSpec.UNSPECIFIED 實際上是視圖包裝尺寸。因此,你可以使用上面計算所需的大小。

在通過setMeasuredDimension設(shè)置最終值之前,以防萬一,可以檢查這些值不為負(fù)數(shù)。這可以避免在布局預(yù)覽時一些問題。

onLayout

此方法分配大小和位置給它的每一個子View。正因為如此,我們正在研究一個扁平的自定義視圖(繼承簡單的View)不具有任何子View,那么就沒有理由重寫此方法。[譯者注:實現(xiàn)可以參考Custom Layouts on Android]

onDraw

這就是發(fā)生魔法的地方。在這里,使用Canvas和Paint對象你將可以畫任何你需要的東西。

一個Canvas實例從onDraw參數(shù)得來,它一般用于繪制不同形狀,而Paint對象定義形狀顏色。簡單地說,Canvas用于繪制對象,而Paint用于造型。它們無處不在,無論繪制的是一個直線,圓或長方形。 

 

 

onDraw() — methods example 

onDraw() — methods example

使自定義View,要始終牢記onDraw會花費(fèi)大量的時間。當(dāng)布局有一些變化,滾動、快速滑動都會導(dǎo)致重新繪制。所以這就是為什么Android Studio也建議:避免在onDraw中進(jìn)行對象分配的操作,對象應(yīng)該只創(chuàng)建一次并在將來重用。 

 

 

onDraw() — Paint object recreation 

onDraw() — Paint object recreation 

 

 

onDraw() — Paint object reuse 

onDraw() — Paint object reuse

注意:

  • 在執(zhí)行繪制時始終牢記重用對象,而不創(chuàng)建新的。不要依賴于IDE高亮一個潛在的問題,而是自己有意識地去做這件事,因為在onDraw調(diào)用一個內(nèi)部會創(chuàng)建對象的方法時,IDE無法識別它。
  • 同時請不要硬編碼View大小。其他開發(fā)者在使用時可以定義不同的大小,所以View大小應(yīng)該取決于它有什么尺寸。

View 更新

從View的生命周期圖可以得知,可以重繪View自身有兩種方法。invalidate()和requestLayout()方法會幫助你在運(yùn)行時動態(tài)改變View狀態(tài)。但為什么需要兩個方法?

  • invalidate()用來簡單重繪View。例如更新其文本,色彩或觸摸交互性。View將只調(diào)用onDraw()方法再次更新其狀態(tài)。
  • requestLayout()方法,你可以看到其將會從`onMeasure()開始更新View。這意味著你的View更新后,它改變它的大小,你需要再次測量它,并依賴于新的大小來重新繪制。

動畫

在自定義View中,動畫是一幀一幀的過程。這意味著,如果你想使一個圓半徑從小變大,你將需要逐步增加半徑并調(diào)用invalidate()來重繪它。

在自定義View動畫中,ValueAnimator是你的好朋友。下面這個類將幫助你從任何值開始執(zhí)行動畫到***,甚至支持Interpolator(如果需要)。

  1. ValueAnimator animator = ValueAnimator.ofInt(0, 100); 
  2. animator.setDuration(1000); 
  3. animator.setInterpolator(new DecelerateInterpolator()); 
  4. animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
  5.   public void onAnimationUpdate(ValueAnimator animation) { 
  6.     int newRadius = (int) animation.getAnimatedValue(); 
  7.   } 
  8. });  

注意:

當(dāng)每一次新的動畫值出來時,不要忘記調(diào)用invalidate()。

責(zé)任編輯:龐桂玉 來源: 安卓開發(fā)精選
相關(guān)推薦

2016-11-16 21:55:55

源碼分析自定義view androi

2016-04-12 10:07:55

AndroidViewList

2017-03-02 13:33:19

Android自定義View

2012-05-18 10:52:20

TitaniumAndroid模塊自定義View模塊

2013-05-20 17:33:44

Android游戲開發(fā)自定義View

2013-01-06 10:43:54

Android開發(fā)View特效

2017-03-14 15:09:18

AndroidView圓形進(jìn)度條

2021-10-26 10:07:02

鴻蒙HarmonyOS應(yīng)用

2011-08-02 11:17:13

iOS開發(fā) View

2013-04-01 14:35:10

Android開發(fā)Android自定義x

2017-05-19 10:03:31

AndroidBaseAdapter實踐

2015-02-12 15:33:43

微信SDK

2010-02-07 14:02:16

Android 界面

2017-05-18 12:36:16

android萬能適配器列表視圖

2013-01-09 17:22:38

Android開發(fā)Camera

2015-02-12 15:38:26

微信SDK

2011-08-18 17:32:55

iPhone開發(fā)Table Cell

2013-05-02 14:08:18

2014-12-10 10:37:45

Android自定義布局

2015-02-11 17:49:35

Android源碼自定義控件
點贊
收藏

51CTO技術(shù)棧公眾號