Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android View移動的3種方式總結

Android View移動的3種方式總結

編輯:關於Android編程

前言

在Android開發中,View一直是Android開發人員的一塊心病,一方面想要進階,一方面又害怕進階,可以說Android的View是進階路上的最大絆腳石,因為它涉及的東西太多了,比如本次我們此次要寫的View移動,另外還包括View的觸摸事件的傳遞,創建自定義View,這些都是極其重要且不得不面對的難題。但是無論如何,現在不克服的困難將來就會被困難克服。

在此之前,我們還是先了解Android坐標系的定義規則以及View的一些位置參數。

Android坐標系

View的位置及大小是由四個參數決定,即left、top、right、bottom,並且這四個參數都是相對於其父View的。

int width = right-left;
 int height = bottom-top;

在Activity中布局完成後,我們可以通過View一些方法獲取這些參數信息:

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

另外Android 3.0以後加入x,y,translationX,translationY等參數。(x,y)表示為View在ViewGroup中左上角的x,y的值,translationX,translationY在用於平移一個View。默認是都為0,在調用了View的setTranslationX()/setTranslationY()之後發生改變。

//x,y,translationX,translationY參數的獲取
 int x = getX();
 int y = getY();
 int translationX = getTranslationX();
 int translationY = getTranslationY();

PS:調用View的setTranslationX()setTranslationY()方法雖然可以使得View平移指定距離,但是這一過程是瞬間完成的。為了使View的移動使得更為平滑,因此可以使用View的屬性動畫來指定translationX和translationY。

ObjectAnimator valueAnimator = ObjectAnimator.ofFloat(textView, "translationX", 200);
 valueAnimator.setDuration(2000);
 valueAnimator.start();

另外,如果給View設置setTranslationX()setTranslationY()後,如果設置的值沒有發生變化,那麼其只會移動一次,即首次指定的移動距離。查看源碼後我們發現原因:原來在設置值之後其會將設置進去的值和當前的translationX,translationY進行對比,不一致時才進行移動。

了解了View的一些基本參數之後,我們看關於View的三種移動方式。

一、使用Android系統提供的scrollTo()/scrollBy()方法實現View的移動。

不管是scrollTo()還是scrollBy()其移動的本質都是View/ViewGroup中的內容。並且其移動的過程是瞬間完成的,因此,為了實現更好的移動效果,他需要與Scroller類結合使用。另外,它不同於上面的Translation,移動的是View本身,這一點需要好好理解一下。

scrollTo()scrollBy()都是View中的方法, 不是Scroller中的方法 ,但是控制View的平滑移動與Scroller類密不可分。

scrollTo() :指是的移動的絕對位置,如果位置沒有變化,多次調用則不會起作用。

scrollTo移動過程示意圖

scrollBy() :其本質依然是調用的scrollTo() ,指的的移動當前位置的相對距離(每次都是先將當前的位置和設置的距離相加之和調用scrollTo(),這樣如果你多次調用,你就會發現其每次都會移動一段距離,這是和scrollTo()的本質區別)

scrollBy移動過程示意圖

PS:關於上面兩張圖,其實一直以來,我自己都沒完全搞明白什麼相對絕對,所以兩張手圖可能會讓人更容易理解。還有就是scrollTo()scrollBy()移動方向問題,上面我們已經畫過Android的坐標系,x軸左→右為正,y軸從上→下為正。但是這並不適用於scrollTo和scrollBy,scrollTo和scrollBy剛好相反,即x軸左→右為負,y軸從上→下為負,簡直是有點坑爹啊。

Scroller類分析:而為什麼使用Scroller類中的方法可以對View/ViewGroup的內容進行移動呢?下面我們試著分析一下。

首先

我們創建一個Scroller類的對象mScroller。

然後

要使View在規定的時間中移動到指定的位置,我們會調用startScroll()方法,startScroll()Scroller類中的方法,另外Scroller類中還有一個filing()方法也是很常用的,它主要是處理平滑的移動,一般營造滑動之後的慣性效果,使得View的移動更逼真。下面我們看startScroll()的源碼:

//其接收四個/五個參數。如果duration不設置,則為默認。這四個參數都不難理解,這裡不再做解釋。
 public void startScroll(int startX, int startY, int dx, int dy, int duration) { 
 ...
 }

而一般我們調用這個方法後都要去調View的 invalidate() ,這個方法可以觸發View的draw()方法。而draw()中調用了 computeScroll() ,源碼中我們發現computeScroll()是個空方法,這也是為什麼我們需要重寫 computeScroll()方法的原因。因為正在的移動操作就是在computeScroll()中進行的。

@Override
 public void computeScroll() {
 if (mScroller.computeScrollOffset()) {
  scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
  //必須調用View的postInvalidate()/invalidate(),如果不加會導致View的移動只會第一幀。
  postInvalidate();
 }
 super.computeScroll();
 }

上面我們看到Scroller類中還有一個computeScrollOffset()方法,它又是干啥的呢?它的主要作用就是判斷mCurrX,和mCurrY是否有改變,有則返回true,無則返回false。通過這個方法的判斷可以指點是否需要持續的調用scrollTo()去移動View。這裡再給出一個示例,使用scrollTo()讓View跟著手指移動:

public class CuView extends LinearLayout {

 private float mStartX;
 private float mStartY;
 private Scroller mScroller;
 /**
 * 第一次滑動是否完成
 */
 private boolean isFirstFinish;

 public CuView(Context context) {
 super(context);
 init(context);
 }

 public CuView(Context context, AttributeSet attrs) {
 super(context, attrs);
 init(context);
 }

 private void init(Context context) {
 mScroller = new Scroller(context);
 }

 public CuView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context);
 }

 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public CuView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
 super(context, attrs, defStyleAttr, defStyleRes);
 init(context);
 }


 /**
 * 讓View跟著你的手指走吧
 * @param event
 * @return
 */
 @Override
 public boolean onTouchEvent(MotionEvent event) {
 int action = event.getAction();
 switch (action) {
  case MotionEvent.ACTION_DOWN:
  /**
   * 第一次移動完成後,我們不需要再去拿開始的位置了,否則造成View重新移動的最起始的位置。
   */
  if (!isFirstFinish) {
   mStartX = event.getRawX();
   mStartY = event.getRawY();
  }
  break;
  case MotionEvent.ACTION_MOVE:
  scrollTo((int) (mStartX - event.getRawX()), (int) (mStartY - event.getRawY()));
  break;
  case MotionEvent.ACTION_UP:
  //第一次移動完成
  isFirstFinish = true;
  break;
 }
 return true;
 }

 /**
 * 測試startScroll
 */
 public void startScroll() {
 /**
  * 注意Scroller移動方向,
  */
 mScroller.startScroll(20, 20, -500, -500, 5000);
 invalidate();
 }

 @Override
 public void computeScroll() {
 if (mScroller.computeScrollOffset()) {
  scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
  invalidate();
 }
 super.computeScroll();
 }
}

二、使用動畫實現View的移動。

這裡包括View的Tween Animation/Frame Animation,以及3.0之後加入的Property Animation。其移動的是View的一個映像,View本身的位置及大小並沒有發生任何改變。

三、設置View的LayoutParams來移動View

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

總結

以上就是總結Android View移動的3種方式的全部內容了,希望本文的內容對大家開發Android的時候能有所幫助,如果有疑問大家可以留言交流。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved