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

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