編輯:關於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的時候能有所幫助,如果有疑問大家可以留言交流。
GridView(網格視圖)是按照行列的方式來顯示內容的,一般用於顯示圖片,圖片等內容,比如實現九宮格圖,用GridView是首選,也是最簡單的。主要用於設置Adapte
人人android是人人網推出的一款優秀的手機應用軟件,我們在使用的時候發現他的首頁布局是九宮格模式的,讓人覺得很別致,因為現在很多的 android軟件很少使用這種布局
1.效果圖 2.創建頁面文件(main.xml) 3.創建下拉框的數據源 List list = new A
前言大家都知道網絡操作的響應時間是不定的,所有的網絡操作都應該放在一個異步操作中處理,而且為了模塊解耦,我們希望網絡操作由專門的類來處理。所有網絡數據發送,數據接收都有某