日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android Scroll分析

發(fā)布時間:2025/3/21 Android 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android Scroll分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

概述

相對于Android2.x版本中常見的長按、點擊操作,滑動的方式具有更友好的用戶體驗性。因此從4.x的版本開始,滑動操作大量出現(xiàn)在Android系統(tǒng)中。

我們在這里主要闡述兩個問題

  • 發(fā)生滑動的效果的原因
  • 如何處理、實現(xiàn)滑動效果

  • 滑動效果分析

    滑動一個View,本質(zhì)上就是移動一個View。

    改變其當前所處的位置,它的原理和動畫效果的實現(xiàn)非常相似,都是通過不斷的改變View的坐標來實現(xiàn)這一個效果。

    所以要實現(xiàn)View的滑動,必須要監(jiān)聽用戶的觸摸事件,并根據(jù)事件傳入的坐標,動態(tài)且不斷的改變View的坐標,從而實現(xiàn)View跟隨用戶觸摸的滑動而滑動。

    在此之前,我們需要先了解下Android中的窗口坐標體系和屏幕的觸控事件MotionEvent。


    Android坐標系

    所謂滑動,正是相對于參考系的運動。

    在Android中,將屏幕最左上角的頂點作為Android坐標系的原點,從這個點向右是X軸的正方向,從這個點向下是Y軸的正方向。

    系統(tǒng)提供了getLocationOnScreen(int location[])這樣的方法來獲取Android坐標系中點的位置,即該視圖左上角在Android坐標系中的坐標。

    另外在觸控事件中使用 getRawX(),getRawY()方法所獲得的坐標同樣是Android坐標系中的坐標。


    視圖坐標系

    Android還有一個視圖坐標系,它描述的是子視圖在父視圖中的位置關系。

    和上面的Android坐標系相輔相成。

    和Android坐標系類似,視圖坐標系同樣是以原點方向向右為X軸正方向,以原點向下為Y軸正方向,只是這個原點不再是Android坐標系中屏幕的左上角,而是父視圖左上角為坐標原點。

    在觸摸事件中,通過getX()和getY()所獲得的坐標就是視圖坐標系中的坐標。


    觸控事件-MotionEvent

    觸控事件MotionEvent在用戶交互中,占據(jù)著舉足輕重的位置。

    首先我們來看下MotionEvent中封裝的一些常用的事件變量,它定義了觸控事件的不同的類型。

    // 單點觸摸按下動作 public static final int ACTION_DOWN = 0 ; // 單點觸摸離開動作 public static final int ACTION_UP = 1 ; // 觸摸點移動動作 public static final int ACTION_MOVE = 2// 觸摸動作取消 public static final int ACTION_CANCEL = 3 ; // 觸摸動作超出邊界 public static final int ACTION_OUTSIDE = 4 ; // 多點觸摸按下動作 public static final int ACTION_POINTER_DOWN = 5 ; // 多點離開動作 public static final int ACTION_POINTER_UP = 6 ;

    通常情況下,我們會在onTouchEvent(MotionEvnet event)方法中通過event.getAction()方法來獲取觸控事件的類型,并使用switch-case方法來進行篩選,這個代碼的模式基本固定,如下

    @Override public boolean onTouchEvent(MotionEvent envnt){// 獲取當前輸入點的X、Y坐標(視圖坐標)int x = (int)event.getX();int y = (int)event.getY();switch(event.getAction()){case MotionEvent.ACTION_DOWN://處理輸入的按下事件break;case MotionEvent.ACTION_MOVE:// 處理輸入的移動事件break;case MotionEvent.ACTION_UP:// 處理輸入的離開事件break;}return true ; }

    在不涉及多點操作的情況下,通常可以使用以上代碼來完成觸控事件的監(jiān)聽,上述僅僅是一個代碼模板~

    在Android中提供了很多獲取坐標值,相對舉例的方法,我們來梳理一下。

    View 提供的獲取坐標的方法

    getTop():獲取到的是View自身的頂邊到其父布局頂邊的距離
    getLeft():獲取到的是View自身的左邊到其父布局左邊的距離
    getRight():獲取到的是View自身的右邊到其父布局左邊的距離
    getBottom():獲取到的是View自身的底邊到其父布局頂邊的距離

    MotionEvent 提供的方法

    getX():獲取點擊事件距離控件左邊的距離,即視圖坐標
    getY():獲取點擊事件距離控件頂邊的距離,即視圖坐標
    getRawX():獲取點擊事件距離整個屏幕左邊的距離,即絕對坐標
    getRawY():獲取點擊事件距離整個屏幕頂邊的距離,即絕對坐標


    實現(xiàn)滑動的七種方法

    不管使用何種方法,其實現(xiàn)的基本思路是一致的:當觸摸View時,系統(tǒng)記下當前觸摸點坐標,當手指移動時,系統(tǒng)記下移動后的觸摸點坐標,從而獲取到相對于前一次坐標點的偏移量,并通過偏移量來修改View的坐標,這樣不斷地重復,從而實現(xiàn)滑動的過程。

    下面我們通過例子來看看Android是如何實現(xiàn)滑動效果的。

    首先我們自定義一個View,置于布局文件中,實現(xiàn)一個簡單的布局。

    <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><com.turing.base.android_hero.chapter5_Scroll.DragView android:layout_width="100dp"android:layout_height="100dp"/></RelativeLayout>

    layout方法

    概述

    在View繪制時,會調(diào)用onLayout()方法來設置顯示的位置。

    同樣,可以通過修改View的 left top right bottom四個屬性來控制View的坐標。

    在每次回調(diào)onTouchEvent方法的時候,我們都來獲取一下觸摸點的坐標。

    Code

    自定義DragView,重寫onTouchEvent方法

    package com.turing.base.android_hero.chapter5_Scroll;import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View;/*** MyApp** @author Mr.Yang on 2016-04-09 21:11.* @version 1.0* 自定義View*/ public class DragView extends View {// 定義上次觸摸的位置private int lastX;private int lastY;/*** 構(gòu)造函數(shù)中調(diào)用 initViewColor方法** @param context*/public DragView(Context context) {super(context);initViewBackGroundColor();}public DragView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initViewBackGroundColor();}public DragView(Context context, AttributeSet attrs) {super(context, attrs);initViewBackGroundColor();}public void initViewBackGroundColor() {// 給View設置背景顏色,便于觀察setBackgroundColor(Color.BLUE);}/*** 重寫 onTouchEvent方法** @param event* @return*/@Overridepublic boolean onTouchEvent(MotionEvent event) {int x = (int) event.getX();int y = (int) event.getY();int rawx = (int) event.getRawX();int rawy = (int) event.getRawY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 按下的時候 記錄觸摸點坐標 scrollByXY // lastX = x; // lastY = y ;lastX = rawx;lastY = rawy;break;case MotionEvent.ACTION_MOVE:// scrollByXY(x,y);scrollyByRawXY(rawx, rawy);break;}return true;}/*** 使用Android坐標系 絕對坐標來計算偏移量,并移動View* 使用絕對坐標系,在每次執(zhí)行完ACTION_MOVE的邏輯后一定要重新設置初始坐標,* 這樣才能準確的獲取到偏移量* @param rawx* @param rawy*/public void scrollyByRawXY(int rawx, int rawy) {// 計算偏移量int offsetX = rawx - lastX;int offsetY = rawy - lastY;// 增加偏移量layout(getLeft() + offsetX,getTop() + offsetY,getRight() + offsetX,getBottom() + offsetY);// 重新設置初坐標lastX = rawx;lastY = rawy;}/*** 使用視圖坐標系 計算偏移量,并移動View*/public void scrollByXY(int x, int y) {// 計算偏移量int offsetX = x - lastX;int offsetY = y - lastY;// 在當前l(fā)eft right top bottom的基礎上增加偏移量layout(getLeft() + offsetX,getTop() + offsetY,getRight() + offsetX,getBottom() + offsetY);} }

    Scroll_Layout

    package com.turing.base.android_hero.chapter5_Scroll;import android.os.Bundle; import android.support.v7.app.AppCompatActivity;import com.turing.base.R;public class Scroll_Layout extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_scroll__layout);} }

    效果圖


    offsetLeftAndRight 和 offsetTopAndBottom

    這個方法相當于系統(tǒng)提供了一個對左右和上下移動的API的封裝。

    當計算出偏移量之后,只需要使用如下代碼完成View的重新布局,效果和使用layout方法一樣

    // 同時對left和right進行偏移 offsetLeftAndRigth(offsetX); // 同時對top和bottom進行偏移 offsetTopAndBottom(offsetY);

    效果同layout 就不貼代碼和運行效果圖了。


    LayoutParams

    概述

    LayoutParams保存了一個View的布局參數(shù)。因此可以通過改變LayoutParms來動態(tài)的修改一個 布局的位置參數(shù),從而達到改變View位置的效果。

    我們可以通過getLayoutParams()來獲取一個View的LayoutParams. 當然了計算偏移量和Layout方法中計算offset也是一樣的,當獲取到偏移量之后,就可以通過setLayoutParams來改變LayoutParams.

    代碼如下:

    // 獲取偏移量int offsetX = x - lastX;int offsetY = y - lastY;RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();layoutParams.leftMargin = getLeft() + offsetX;layoutParams.topMargin = getTop() + offsetY;setLayoutParams(layoutParams);

    注意事項:

    • 通過getLayoutParams獲取LayoutParams時,需要根據(jù)View在父布局中的類型來設置不同的類型,比如這里我們把View放到了RelativeLayout中,那么就是RelativeLayout.LayoutParams ,同樣的道理 如果放到了LinearLayout中,則為LinearLayout.LayoutParams
    • 通過getLayoutParams的方式獲取布局參數(shù),前提是必須要有一個父布局,否則系統(tǒng)無法獲取。

    Code

    關鍵自定義類

    package com.turing.base.android_hero.chapter5_Scroll;import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.RelativeLayout;/*** MyApp** @author Mr.Yang on 2016-04-10 10:23.* @version 1.0* @desc*/ public class DragView_LayoutParams extends View {private int lastX, lastY;public DragView_LayoutParams(Context context) {super(context);initViewBackgroudCoclor();}public DragView_LayoutParams(Context context, AttributeSet attrs) {super(context, attrs);initViewBackgroudCoclor();}public DragView_LayoutParams(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initViewBackgroudCoclor();}private void initViewBackgroudCoclor() {// 給View設置背景顏色,便于觀察setBackgroundColor(Color.BLUE);}@Overridepublic 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 offsetX = x - lastX;int offsetY = y - lastY;RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();layoutParams.leftMargin = getLeft() + offsetX;layoutParams.topMargin = getTop() + offsetY;setLayoutParams(layoutParams);break;default:break;}return true;} }

    效果圖

    效果圖同上~

    方法二-ViewGroup.MarginLayoutParams

    在通過LayoutParams來改變一個變量的位置的時候,通常改變的是這個View的margin屬性,所以除了使用布局的LayoutParams之外,我們還可以使用ViewGroup.MarginLaoutParams來實現(xiàn)同樣的功能。

    // 計算偏移量int offsetX = x - lastX;int offsetY = y - lastY;ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();layoutParams.leftMargin = getLeft() + offsetX;layoutParams.topMargin = getTop() + offsetY;setLayoutParams(layoutParams);break;

    使用ViewGroup.MarginLayoutParams更加方便,不需要考慮父布局的類型,當然了這兩者的本質(zhì)都是一樣的。


    scrollTo和scrollBy

    概述

    在一個View中,系統(tǒng)提供了scrollTo 、scrollBy兩種方式來改變一個View的位置。

    顧名思義,

    • scrollTo(x,y)表示移動到一個具體的坐標點 (x,y).
    • scrollBy(dx,dy)表示移動的增量為dx,dy.

    需要注意的是:

    • scrollTo和scrollBy方法移動的是View的content,即讓View中的內(nèi)容移動,如果在ViewGroup中使用scrollTo和scrollBy方法,那么移動的將是所有的子View,但如果在View中使用,那么移動的將是View的內(nèi)容,比如TextView,content就是它的文本,ImageView,content就是它的Drawable對象。
    • 要實現(xiàn)跟隨手指移動而滑動的效果,必須將偏移量設置為負值。
    • 如果將scrollBy中的參數(shù)dx和dy設置為正數(shù),那么content將向坐標的負方向移動,設置為負數(shù),content將向坐標軸的正方向移動。
    • 在使用絕對坐標系時,也可以通過scrollTo來實現(xiàn)相同的效果

    Code

    關鍵自定義View

    package com.turing.base.android_hero.chapter5_Scroll;import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View;/*** MyApp** @author Mr.Yang on 2016-04-10 12:32.* @version 1.0* @desc*/ public class DragView_scrollToscrollBy extends View {private int lastX;private int lastY;public DragView_scrollToscrollBy(Context context) {super(context);initViewBackgroundColor();}public DragView_scrollToscrollBy(Context context, AttributeSet attrs) {super(context, attrs);initViewBackgroundColor();}public DragView_scrollToscrollBy(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initViewBackgroundColor();}private void initViewBackgroundColor() {setBackgroundColor(Color.BLUE);}@Overridepublic 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 offsetX = x - lastX;int offsetY = y - lastY;((View) getParent()).scrollBy(-offsetX,-offsetY);break;}return true;} }

    效果圖同上~


    Scroller

    概述

    上面說到了scrollTo、scrollby方法,就不得不提一下Scroller類。

    總體來講,scrollTo scrollBy方法,子View的移動都是瞬間的,在事件執(zhí)行的時候平移已經(jīng)完成了,而Scroller類可以實現(xiàn)平滑移動的效果,而不是在瞬間完成的移動。

    演示:
    子View隨著手指的滑動而滑動,在手指離開屏幕時,讓子View平滑的移動到初始位置,即屏幕的左上角。

    使用Scroller一般需要三個步驟:

  • 初始化Scroller
  • 重寫computerScrol方法,實現(xiàn)模擬滑動
  • startScroll開啟模擬過程
  • Code

    package com.turing.base.android_hero.chapter5_Scroll;import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.Scroller;/*** MyApp** @author Mr.Yang on 2016-04-10 13:15.* @version 1.0* @desc*/ public class DragViewScroller extends View {private int lastX;private int lastY;private Scroller mScroller;public DragViewScroller(Context context) {super(context);ininView(context);}public DragViewScroller(Context context, AttributeSet attrs) {super(context, attrs);ininView(context);}public DragViewScroller(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);ininView(context);}private void ininView(Context context) {setBackgroundColor(Color.BLUE);// 初始化ScrollermScroller = new Scroller(context);}@Overridepublic void computeScroll() {super.computeScroll();// 判斷Scroller是否執(zhí)行完畢if (mScroller.computeScrollOffset()) {((View) getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());// 通過重繪來不斷調(diào)用computeScrollinvalidate();}}@Overridepublic boolean onTouchEvent(MotionEvent event) {int x = (int) event.getX();int y = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:lastX = (int) event.getX();lastY = (int) event.getY();break;case MotionEvent.ACTION_MOVE:int offsetX = x - lastX;int offsetY = y - lastY;((View) getParent()).scrollBy(-offsetX, -offsetY);break;case MotionEvent.ACTION_UP:// 手指離開時,執(zhí)行滑動過程View viewGroup = ((View) getParent());mScroller.startScroll(viewGroup.getScrollX(),viewGroup.getScrollY(),-viewGroup.getScrollX(),-viewGroup.getScrollY());invalidate();break;}return true;} }

    效果圖


    屬性動畫

    待出一篇博客詳述~


    ViewDragHelper

    概述

    步驟:

    • 初始化ViewDragHelper
    • 攔截事件
    • 處理computerScroll
    • 處理回調(diào)Callback

    Code

    請移步 本人Github-DragViewGroup

    效果圖


    總結(jié)

    以上是生活随笔為你收集整理的Android Scroll分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。