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;
    }

猜你喜欢

转载自blog.csdn.net/yangyasong/article/details/68067422
今日推荐