1. 程式人生 > >android 自定義view時,實現動起來的幾種方法

android 自定義view時,實現動起來的幾種方法

前言

在自定義view時如何讓她動起來呢?本人在14年面世的時候就被問到了listview下拉重新整理時,如何下拉如何上移,還記得本人當初的答案是使用屬性動畫,被人好好的鄙視了一番,說多了,好了拔劍吧

  1. offsetLeftAndRight(offsetX) or offsetTopAndBottom(offsetY)
  2. layout方法
  3. 動態設定margin
  4. 動態設定pading(專門試了一下可以使用)
  5. 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;
    }