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