View的移动方式

View的移动方式

常见的View的移动方式有setX()/setY()、setTranslationX()/setTranslationY()、动画、scrollTo/scrollBy等。因为View的属性比较多。view使用不同的移动方式,受影响的是那些变量属性已经方法。以及配合使用时会产生何种效果。比如view的getX/Y、getSrollX/Y、getTranslationX/Y、getLeft/top/right/bottom、点击事件触发区域等等,是否会受到影响改变,由哪些所影响?
各个移动方式对属性的验证:
1、getX()、getY()
2、getScrollX() 、getScrollY()
3、getTranslationX() 、getTranslationY()
4、getLeft()、 getTop()、 getRight()、 getBottom()(座标位置是否改变)
5、点击事件触发区域是否改变
6、是否会影响同层级的其他view的位置
7、超过父View是否绘制
在这里插入图片描述

View座标系

view的位置大小由以下参数决定:
1.mLeft、mRight、mTop、mBottom 这四个参数相对于父view
2.mScrollX、mScrollY
3.translationX、translationY
4.getX()、getY()

  • 获取高宽:
public final int getWidth() {
        return mRight - mLeft;
}

 public final int getHeight() {
        return mBottom - mTop;
 }

在Activity中布局完成后,我们可以通过View一些方法获取这些参数信息:

//left,top,right,bottom值的获取
  int left = getLeft();
  int top = getTop();
  int right = getRight();
  int bottom = getBottom();

 public final int getLeft() {
        return mLeft;
    }

scrollTo()/scrollBy()

scrollTo()和scrollBy()都是View中的方法。其移动的本质都是View/ViewGroup中的内容。如果是一个TextView,则移动的是TextView显示的文本内容。如果是一个ViewGroup则移动的是其包含的childview。

  • scrollTo() : 指是的移动的绝对位置,如果位置没有变化,多次调用则不会起作用。
    在这里插入图片描述

  • scrollBy() : 其本质依然是调用的scrollTo(),指的的移动当前位置的相对距离(每次都是先将当前的位置和设置的距离相加之和调用scrollTo(),这样如果你多次调用,你就会发现其每次都会移动一段距离,这是和scrollTo()的本质区别)
    在这里插入图片描述

  • scrollTo()和scrollBy()移动改变的是mScrollX、mScrollY的值。
    所以getX()/getY()不变。getScrollXY 会变。视觉上view的位置会改变但实质上是view的内容改变。所以view的点击事件还是在原位置。

  • 获取mScrollX、mScrollY

public final int getScrollX() {
        return mScrollX;
    }
    
public final int getScrollY() {
        return mScrollY;
    }
    

setTranslationX/Y、setX/setY

  • 在Android3.0以后加入了X、Y、TranslationX、TranslationY;(x,y)表示为View在ViewGroup左上角的x,y的值。translationX,translationY用于平移一个View。默认是都为0,在调用了View的setTranslationX()/setTranslationY()之后发生改变。通过setX()/setY()/setTranslationX()/setTranslationY()都可改变view的位置。(通过属性动画ObjectAnimator可使View的移动使得更为平滑)
    //x,y,translationX,translationY参数的获取
    int x = getX();
    int y = getY();
    int translationX = getTranslationX();
    int translationY = getTranslationY();
 public float getX() {
        return mLeft + getTranslationX();
    }


 public void setX(float x) {
        setTranslationX(x - mLeft);
    }

 
 public void setTranslationX(float translationX) {
        if (translationX != getTranslationX()) {
            invalidateViewProperty(true, false);
            mRenderNode.setTranslationX(translationX);
            invalidateViewProperty(false, true);

            invalidateParentIfNeededAndWasQuickRejected();
            notifySubtreeAccessibilityStateChangedIfNeeded();
        }
    }

public float getTranslationX() {
        return mRenderNode.getTranslationX();
    }
  • View根本就没有x、y的成员变量,不过是根据translationY和mTop的值计算出来的而已。所以:
    getX getY 会变
    getTranslationXY会变
    点击事件的位置也变了但是不会超过父布局

  • 系统对于mTop、mLeft等的修改,仅仅限于在layout方法内部,而layout方法我们都知道,是View在onMeasure测量之后,对自身以及子控件进行位置布局的。translationY开启的属性动画,并不会影响到mTop的值。mTop的值的意义是什么?是告诉父容器,我的控件的位置在哪儿。意义就是,父容器在onMeasure和onLayout的时候,是以mTop的值作为基准的。所以会超过边界到同级View的区域去(被覆盖或者覆盖别人)https://blog.csdn.net/cc_lova_wxf/article/details/72676830

  • 执行setTranslationY,mTop等于0,translationY和y都等于300,并且能够在300的地方响应点击事件,这就说明了系统点击事件的范围判断是根据translationY来判断的,而不是通过mTop。

  • 如果想要改变View对于父容器的影响,那么影响的是mLeft、mTop、width、height等属于父容器的属性(mLeft、mTop、width、height等都是父容器的属性,而不属于本View)。

  • 如果想要改变View自身的影响,比如添加监听器,添加动画等等,那么影响的是translationX、translationY等属于自身的属性。

使用平移动画或者属性动画

android动画分三类:一是View 动画,又叫Tween动画,二是frame 动画(帧动画),又叫drawable 动画,三是属性动画,即property animation.

  • View动画,包名android.view.animation,基类为Animation,核心子类为TranslateAnimation,ScaleAnimation,AlphaAnimation,RotateAnimation及AnimationSet。

  • Property动画,包名android.animation,基类为Animator,核心子类为AnimatorSet,ValueAnimator,ObjectAnimator,TimeAnimator。

  • 使用平移动画点击事件还是在原位置。(属性动画没有此问题)

  • 使用平移动画如果setFillAfter位置保留 但是其他任何座标位置没有改变 再次点击从原位置重新开始移动

设置View的LayoutParams来移动View

LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) textView.getLayoutParams();
layoutParams.leftMargin = 50;
textView.requestLayout();

使用setLayoutParams和requestLayout如果多次执行性能很差。

在这里插入图片描述

layout()

如果你将滑动后的目标位置的座标传递给layout(),这样子就会把view的位置给重新布置了一下,在视觉上就是view的一个滑动的效果。

public class DragView extends View{
  private int lastX;
  private int lastY;
  public DragView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }
  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 offX = x - lastX;
        int offY = y - lastY;
        //调用layout方法来重新放置它的位置
        layout(getLeft()+offX, getTop()+offY,
          getRight()+offX  , getBottom()+offY);
      break;
    }
    return true;
  }
}

学习资料: https://www.jianshu.com/p/a4072dd6816b

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章