android 自定義view時,實現動起來的幾種方法
前言
在自定義view時如何讓她動起來呢?本人在14年面世的時候就被問到了listview下拉重新整理時,如何下拉如何上移,還記得本人當初的答案是使用屬性動畫,被人好好的鄙視了一番,說多了,好了拔劍吧
- offsetLeftAndRight(offsetX) or offsetTopAndBottom(offsetY)
- layout方法
- 動態設定margin
- 動態設定pading(專門試了一下可以使用)
- scrollby和scrollto
offsetLeftAndRight(offsetX) or offsetTopAndBottom(offsetY)
上原始碼
public void offsetLeftAndRight(int offset) {
if (offset != 0) {
final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
if (isHardwareAccelerated()) {
invalidateViewProperty(false, false);
} else {
final ViewParent p = mParent;
if (p != null && mAttachInfo != null) {
final Rect r = mAttachInfo.mTmpInvalRect;
int minLeft;
int maxRight;
if (offset < 0) {
minLeft = mLeft + offset;
maxRight = mRight;
} else {
minLeft = mLeft;
maxRight = mRight + offset;
}
r.set(0, 0, maxRight - minLeft, mBottom - mTop);
p.invalidateChild(this, r);
}
}
} else {
invalidateViewProperty(false, false);
}
mLeft += offset;
mRight += offset;
mRenderNode.offsetLeftAndRight(offset);
if (isHardwareAccelerated()) {
invalidateViewProperty(false, false);
invalidateParentIfNeededAndWasQuickRejected();
} else {
if (!matrixIsIdentity) {
invalidateViewProperty(false, true);
}
invalidateParentIfNeeded();
}
notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
判斷offset是否為0,也就是說是否存在滑動距離,不為0的情況下,根據是否在矩陣中做過標記來操作。如果做過標記,沒有開啟硬體加速則開始計算座標。先獲取到父view,如果父view不為空,在offset<0時,計算出左側的最小邊距,在offset>0時,計算出右側的最大值,其實分析了這麼多主要的實現程式碼就那一句 mRenderNode.offsetLeftAndRight(offset),由native實現的左右滑動,以上分析的部分主要計算view顯示的區域。
最後總結一下,offsetLeftAndRight(int offset)就是通過offset值改變了View的getLeft()和getRight()實現了View的水平移動。
offsetTopAndBottom(int offset)方法實現原理與offsetLeftAndRight(int offset)相同,offsetTopAndBottom(int offset)通過offset值改變View的getTop()、getBottom()值,同樣給出核心程式碼mRenderNode.offsetTopAndBottom(offset),這個方法也是有native實現
在實現自定義view的時候,可以直接使用這兩個方法,簡單,方便
layout
layout(int l, int t, int r, int b)
第一個引數 view左側到父佈局的距離
第二個引數 view頂部到父佈局之間的距離
第三個引數 view右側到父佈局之間的距離
第四個引數 view底端到父佈局之間的距離
scrollTo 和 scrollBy
scrollBy方法簡單粗暴,呼叫scrollTo 方法,在當前的位置繼續偏移(x , y)
這裡把它歸類到通過改變父佈局實現view移動是有原因,如果在view中使用這個方法改變的是內容,不是改變view本身,如果在ViewGroup使用這個方法,改變的是子view的位置,相對來說這個實用的概率比較大.
LayoutParams
LayoutParams儲存佈局引數,通過改變區域性引數裡面的值改變view的位置,如果佈局中有多個view,那麼多個view的位置整體移動
@Override public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX;
int offsetY = y - lastY;
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) getLayoutParams();
params.leftMargin = getLeft() + offsetX;
params.topMargin = getTop() + offsetY;
setLayoutParams(params);
break;
}
return true;
}