標籤:
View概述
對於一個view,他應該有兩個位置:一個是顯示位置(即我們人眼看到的位置),一個是點擊位置(即接收使用者點擊事件的位置)。
在初始化完成後,兩個位置是重合的,因此“所見即所點”。但,當調用了scrollTo(),scrollBy()或者tweens動畫後,所見已經不和所點重合:所見位置發現變化,但所點還在原地。這也是屬性動畫和tweens動畫的區別,前者仍舊保持了所見即所點。
位置
mLeft,mTop,mBottom和mRight:分別表示原始的左上方的x,y座標,右下角的x,y座標。它們都是相對於父組件而言的。如果控制項的左上方與父控制項的左上方重合,那麼mLeft,mTop都是0。可以通過getLeft(),getRight(),getTop()和getBottom()擷取相應的值。
x,y,translationX和translationY。x,y分別表示View相對於其父控制項的當前的左上方座標,tranlationX和translationY為View在x,y軸上移動的距離。x = mLeft+translationX;y = mTop + translationY。
在移動時,mLeft,mRight,mBottom與mTop是不變的,變化的只有x,y,translationX和translationY。
mScrollX與mScrollY:表示顯示地區一共移動的位移,它跟mLeft以及translationX等值無關。mScrollY表示點擊地區的上邊座標減內容地區的上邊座標。由於scrollTo/scrollBy兩個方法只改變內容地區,而點擊地區並沒有變化。所以scrollBy(100,0)時,意味著內容地區的左邊緣要比現在的左邊緣少100個像素,因此映像往左移(使用者看到的永遠只是內容地區,而不是點擊地區)。
可以將View的座標分為三類:第一類mLeft等四個屬性,表示View的原始座標,一旦顯示之後不可修改;第二類,在原始座標基礎上進行移動得到的新座標,它並不能影響原始座標,但可以改變當前位置;第三類,內容地區的座標,即不能改變原始座標也不能改變新座標,只是修改內容地區的座標。
setLeft()與LayoutParams.leftMargin的區別
兩者都可以改變mLeft的值:即改變子View在父View中的初始位置。但setLeft()只是修改了mLeft的值,不會影響其他屬性mRight,mTop和mBottom的值。並且不會請求父組件重新測量,布局。
但後者會同時修改mLeft,mRight等四個屬性的值,並會引起重新測量和布局。
對於兩者來說,它們都會引起點擊地區的改變,只不過前者不影響mScrollX與mScrollY的值,後者卻會影響。通過LayoutParams進行修改,相當於對該控制項進行重建,mScrollX與mScrollY會被初始化為0。
移動
根據View的三類座標,對View進行移動也有三種方法。
第一種,改變內容地區。有兩種方式:
1,通過scrollTo()/scrollBy()
2,通過補間動畫。其實質也是通過scrollTo()/scrollBy()。
第二種:改變點擊地區。有兩種方式:
1,改變mLeft,x,y,translationX和translationY等屬性的值。
2,使用屬性動畫。其實質仍舊是修改上述四個屬性的值。
第三種:改變初始位置。只有一種方式:
使用LayoutParams,並修改其中的leftMargin,topMargin等幾個跟margin相關的值。
比較
第一種方式並沒有修改點擊地區,所以如果要移動的View有點擊事件的話,需要單獨進行處理。後兩種不需要。
如果想移動View在父View中的位置,第一種方法中沒辦法使用scrollTo/scrollBy,但可以使用動畫。
常用方法
getTop(),getLeft(),getBottom()與getRight()擷取的該view在父組件中的相對位置。顯示位置改變後,並不會影響該值。例如ScrollView不斷滑動時,getScrollY()的值會不斷變化,但getTop()的值是固定的。在ScrollView中,即使在當前該view還沒有顯示出來,它一樣有getTop(),也就是說它的位置已經在ScrollView中擺放好了。
scrollTo(),scrollBy():移動view的顯示位置,並不移動它的點擊位置。平移動畫也是通過這兩個方法實現的。
getScrollX(),getScrollY():擷取該view通過scrollBy()或者scrollTo()移動的總位移(這裡是位移,而不距離)。
setTranslationX():設定x軸平衡距離。與scrollTo()的區別在於,它將view的點擊位置和顯示位置同時移動。
onScrollChanged():每一次調用scrollTo()後便回調該方法。例如ScrollView不斷滑動時,就會一直回調該方法,不管是手指按下還是螢幕自動滾動。它的前兩個參數指的是當前在水平和垂直方向的scroll位移——顯示位置的移動距離;後兩個參數指前一次的scroll位移。
overScrollBy():在滾動過程中的回調,其參數非常有用(註:在魅族手機上對該方法的回調有問題,會出現亂七八糟的現象)。前兩個參數為:調用該方法時,本次滾動在x,y軸上的移動距離;第三四個參數為:到調用該方法時,在x,y軸上總的滾動距離,不包括本次的滾動距離;第五六個參數為:在x,y軸上能滾動的距離,可以理解為它的內容高度減去控制項自身的高度;第七八個參數為:在x,y軸上能額外滾動的距離,即超出範圍後仍舊能滾動的距離。最後一個參數為:調用該方法是,是因為觸摸滾動還是自動滾動。
上面說的都是ScrollView,並不適合於ListView,因為ListView在顯示時並不會將所有的View都建立好。當然對所有的View來說,onScrollChanged及scrollBy等方法的含義是一樣的,因為這些方法在View類中。
dispatchDraw()與onDraw():dispatchDraw()主要用於子View的繪製,而onDraw()用於自身的繪製。並且,dispatchDraw()在onDraw()之後調用。
computeScroll():由父View調用。當子View更新了mScrollX或者mScrollY值時,可以在該方法中更改子view的位置。此方法一般在view需要根據手勢進行移動時才重寫。它在onDraw()前調用。
onAttachedToWindow():在onDraw()前的某一時刻調用,但是也有可能在onMeasure()前調用。當view依附於window上時調用。只有該方法之後,才有可用來繪製的surfaceview(Android所有繪製的映像都是在SurfaceView上的,除了自己使用SurfaceView外)。
onDetachedFromWindow():與onAttachedToWindow()相反,當view從window上脫落時調用。此方法之後用來繪製的SurfaceView已經不存在了。
捲軸相關屬性
scrollbarFadeDuration:捲軸消失動畫的期間。如果把該值設定的非常大,可以間接實現捲軸一直效果的效果。
scrollbarThumbHorizontal、scrollbarThumbVertical:捲軸中滾動的圖片。
scrollbarTrackHorizontal、scrollbarTrackVertical:捲軸的滾動軌道(track),也即是捲軸的背景。
fadeScrollbars:捲軸是否消失。false,捲軸一直存在;true,捲軸會在不使用時淡出。
scrollbarStyle:主要用來決定捲軸的位置。有四個值:insideOverlay,insideInset與outsideOverlay,outsideInset。outside是說捲軸一直處在view的邊界,而inside代表捲軸會被padding影響,從而往裡移。Overlay說捲軸覆蓋在內容地區上,不增加padding的值;而inset卻是增加padding值,相當於把內容地區再往裡擠。樣本:
<ListView android:id="@+id/listView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10px" android:scrollbarStyle="insideOverlay" > </ListView>
scrollbarStyle="insideOverlay"時
scrollbarStyle="insideInset"時
對比上面兩圖可以發現,當為Overlay時,內容地區(即紅色地區)距離邊框(黑色)的距離是10px(ListView中設定了padding為10px);當為inset時內容地區距離邊框不止10px,但是捲軸的右邊距離邊框是10px。
scrollbarStyle="outsideOverlay"時
scrollbarStyle="outsideInset"時
再對比四幅圖可以發現:outside的時候捲軸是處於view的邊緣的,而inside的時捲軸會受padding影響,從而不一定會處於邊緣。
ImageViewscaleType:
參考:http://www.cnblogs.com/carmanloneliness/archive/2012/08/06/2625489.html
center:圖片大小為原始大小,如果圖片大小大於ImageView控制項,則截取圖片中間部分;若小於,則直接將圖片置中顯示。
fitXY:將圖片縮放到與imageview大小相同,而且圖片的長寬縮放比例不一致。如果圖片比ImageView大,那麼圖片就會縮小到ImageView的大小;如果圖片比ImageView小,那麼圖片就會擴大到整個ImageView。
fitStart,fitCenter與fitEnd:將圖片的長寬按同一比例進行縮放,直到使ImageView能完全包裹住圖片,並且圖片的某一邊和ImageView對應的邊長度相等。但此時並不能保證圖片與組件之間沒有空隙。片的寬要放大3倍,高要放大2倍。那麼就會放大2倍,此時高剛好充滿整個組件,但是寬卻與兩邊保留的有空隙。
centerInside:當ImageView的大小大於圖片的大小時,圖片置中顯示,不進行任何縮放;當ImageView的大小小於圖片的大小時,那麼選取長寬縮小比例中的最大值進行縮小,然後置中顯示,此時類似於fitCenter。
centerCrop:將圖片等比例縮放後截取圖片中間的部分顯示。如果ImageView大於圖片的大小,那麼選取長寬放大比例中的最大值進行放大;如果ImageView大於圖片的大小,那麼選取長寬放大比例中的最小值進行縮小。這樣做的目的是保證無論圖片是放大還是縮小,圖片都能將ImageView全部填滿不留空隙。
Checkbox與RadioButton
經常需要自訂這兩種組件,也就是更換其中的圖片。在更換表徵圖之後,會發現兩個都佔有了一定的空白範圍。
結果如:
點擊其中的紅框部分,一樣可以勾選上複選框。這是因為系統預設的為兩者帶有一個透明的背景。只需要在布局檔案中為它們的background屬性@null即可。另外:button的值也為@null。
當然也可以採用自訂群組合控制項的方法,只不過比較麻煩。
具體style樣式為:
<style name="MyCheckBox" parent="@android:style/Widget.CompoundButton.CheckBox"> <item name="android:background">@null</item> <item name="android:layout_width">wrap_content</item> <item name="android:layout_height">wrap_content</item> <item name="android:layout_gravity">center_vertical</item> <item name="android:button">@null</item> <item name="android:layout_marginLeft">20dp</item> <item name="android:drawablePadding">5dp</item> <item name="android:drawableRight">@drawable/activity_contactor_select_selector</item> <item name="android:textColor">#27415C</item> <item name="android:textSize">14sp</item> <item name="android:layout_marginTop">5dp</item> <item name="android:layout_marginBottom">5dp</item> </style>
其中drawableRight的值為一個選取器,也就是定義選中和未選中的兩種樣式。如下:<
<item android:drawable="@drawable/selected" android:state_checked="true"></item> <item android:drawable="@drawable/no_selected" android:state_checked="false"></item> <item android:drawable="@drawable/no_selected"></item>
View入門