記錄Android中實(shí)現(xiàn)滑動的幾種方法

一、layou方法

代碼示例如下宫患,自定義一個view,在onTouchEvent()方法中計算手指滑動時的偏移量哩掺,調(diào)用view的layout()方法检眯,在當(dāng)前l(fā)eft厘擂、top、right锰瘸、bottom上加上偏移量刽严,實(shí)現(xiàn)view的滑動。

public class TestView extends View {
    private static final String TAG = "TestView";
    public TestView(Context context) {
        super(context);
    }

    public TestView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
       
    }

    public TestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    float startX;
    float startY;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //記錄初始觸摸點(diǎn)坐標(biāo)
                startX = event.getRawX();
                startY = event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                //手指滑動過程中經(jīng)過的點(diǎn)坐標(biāo)
                float lastX = event.getRawX();
                float lastY = event.getRawY();
                //計算偏移量
                int offsetX = (int) (lastX - startX);
                int offsetY = (int) (lastY - startY);
                //在當(dāng)前的left获茬、top港庄、right、bottom上加上偏移量
                layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
                Log.e(TAG, "onTouchEvent: layout: " + offsetX + "/" + offsetY);
                //重新設(shè)置初始坐標(biāo) 恕曲,這一步很重要            
                startX = lastX;
                startY = lastY;
            break;
          }
        return true;
    }
 }

二鹏氧、offsetLeftAndRight()與offsetTopAndBottom()方法

這兩個方法相當(dāng)于系統(tǒng)提供的一個對左右、上下移動的API的封裝佩谣。使用方法同樣先在onTouchEvent()方法中計算出手指滑動的偏移量把还,然后將偏移量作為方法參數(shù)傳入。關(guān)鍵代碼如下:

    float startX;
    float startY;
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //記錄初始觸摸點(diǎn)坐標(biāo)
                startX = event.getRawX();
                startY = event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                //手指滑動過程中經(jīng)過的點(diǎn)坐標(biāo)
                float lastX = event.getRawX();
                float lastY = event.getRawY();
                //計算偏移量
                int offsetX = (int) (lastX - startX);
                int offsetY = (int) (lastY - startY);
                //調(diào)用方法,參數(shù)為計算出的偏移量
                offsetLeftAndRight(offsetX);
                offsetTopAndBottom(offsetY);
                Log.e(TAG, "onTouchEvent: offsetLeftAndRight_offsetTopAndBottom: " + offsetX + "/" + offsetY);
                //重新設(shè)置初始坐標(biāo) 吊履,這一步很重要   
                startX = lastX;
                startY = lastY;
                break;
              }
        return true;
    }

三安皱、修改view的LayoutParams

LayoutParams保存著一個View的布局參數(shù)⊥а祝可以通過改變LayoutParams來動態(tài)修改一個View的位置參數(shù)酌伊,以此達(dá)到改變View位置的效果。關(guān)鍵代碼如下:

    float startX;
    float startY;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //記錄初始觸摸點(diǎn)坐標(biāo)
                startX = event.getRawX();
                startY = event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                //手指滑動過程中經(jīng)過的點(diǎn)坐標(biāo)
                float lastX = event.getRawX();
                float lastY = event.getRawY();
                //計算偏移量
                int offsetX = (int) (lastX - startX);
                int offsetY = (int) (lastY - startY);
                //修改LayoutParams參數(shù)缀踪,這里要改變位置主要是修改LayoutParams的margin屬性居砖,因此這里直接使用
                // ViewGroup.MarginLayoutParams以求方便,不必考慮view的父布局類型驴娃。在一般應(yīng)用中奏候,如若有需要
                // 修改LayoutParams的其他屬性,要注意getLayoutParams()必須獲取的是父布局類型的LayoutParams唇敞。
                ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
                layoutParams.leftMargin = getLeft() + offsetX;
                layoutParams.topMargin = getTop() + offsetY;
                setLayoutParams(layoutParams);
                Log.e(TAG, "onTouchEvent: layoutParams: " + offsetX + "/" + offsetY);
                //重新設(shè)置初始坐標(biāo)蔗草,這一步很重要
                startX = lastX;
                startY = lastY;
                break;
               }
        return true;
    }

四、scrollTo與scrollBy

1.scrollTo(int x,int y):移動到一個坐標(biāo)點(diǎn)
2.scrollBy(int x,int y):按照x軸增量x疆柔,y軸增量y的方式移動
這兩個方法實(shí)質(zhì)上移動的是調(diào)用方法的對象所包含的內(nèi)容咒精。即:如果對一個ViewGroup(如LinearLayout)調(diào)用這兩個方法,會發(fā)現(xiàn)其內(nèi)部所有的子view會一起發(fā)生移動婆硬;而如果對一個view(如TextView)調(diào)用狠轻,則會發(fā)現(xiàn)看不到移動的效果。要對view使用這兩個方法彬犯,實(shí)際上是需要對該view 的parent使用向楼。代碼示例如下:
1.在ViewGroup中,可以直接調(diào)用

float startX;
float startY;
@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startX = event.getRawX();
            startY = event.getRawY();
            break;
        case MotionEvent.ACTION_MOVE:
            float lastX = event.getRawX();
            float lastY = event.getRawY();
            int offsetX = (int) (lastX - startX);
            int offsetY = (int) (lastY - startY);
            //注意這里的參數(shù)要變成相反數(shù)谐区。由于作用對象是parent湖蜕,所以實(shí)際發(fā)生
            //移動的應(yīng)該是parent,但我們的目標(biāo)是子view宋列。因此昭抒,以相對視圖關(guān)系
            //來看,要讓子view產(chǎn)生所期望的移動效果炼杖,parent應(yīng)該要向反方向移動灭返。
            scrollBy(-offsetX, -offsetY);
            startX = lastX;
            startY = lastY;
            break;
    }
    return true;
}

2.在view中,需要由view的parent來調(diào)用

 ((View) getParent()).scrollBy(-offsetX, -offsetY);

五坤邪、使用Scroller實(shí)現(xiàn)帶過度動畫的滑動

使用前面幾種方法實(shí)現(xiàn)view位置的改變熙含,如果不是通過手指觸摸事件,而是通過如按鈕點(diǎn)擊事件調(diào)用艇纺,view的位置變化是瞬間完成的怎静。如果要讓位置變化有一個過渡動畫的過程邮弹,可以使用Scroller來實(shí)現(xiàn)。Scroller的使用可以分為3步驟:
1.初始化Scroller: Scroller scroller=new Scroller(context);
2.重寫computeScroll()方法蚓聘,實(shí)現(xiàn)模擬滑動

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

3.startScroll()方法開啟模擬過程腌乡。可以在自定義view內(nèi)部合適的位置調(diào)用下列方法夜牡,也可以在自定義view內(nèi)部聲明一個調(diào)用該方法的方法与纽,然后在外部Activity等需要調(diào)用的位置調(diào)用。

scroller.startScroll(startX, startY, dx, dy, duration);

代碼示例:

自定義View
public class TestView extends View {
private static final String TAG = "TestView";
private Scroller mScroller;

public TestView(Context context) {
    super(context);
}

public TestView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    mScroller = new Scroller(context);
}

public TestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

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

public void scrollAnimation(int startX, int startY, int dx, int dy, int duration) {
    mScroller.startScroll(startX, startY, dx, dy, duration);
    invalidate();
}
}

在Activity中調(diào)用:

 @Override
public void onClick(View v) {
    mTestView.scrollAnimation(0,0,-300,-400,2000);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末氯材,一起剝皮案震驚了整個濱河市渣锦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌氢哮,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件型檀,死亡現(xiàn)場離奇詭異冗尤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)胀溺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門裂七,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人仓坞,你說我怎么就攤上這事背零。” “怎么了无埃?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵徙瓶,是天一觀的道長。 經(jīng)常有香客問我嫉称,道長侦镇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任织阅,我火速辦了婚禮壳繁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荔棉。我一直安慰自己闹炉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布润樱。 她就那樣靜靜地躺著渣触,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祥国。 梳的紋絲不亂的頭發(fā)上昵观,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天晾腔,我揣著相機(jī)與錄音,去河邊找鬼啊犬。 笑死灼擂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的觉至。 我是一名探鬼主播剔应,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼语御!你這毒婦竟也來了峻贮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤应闯,失蹤者是張志新(化名)和其女友劉穎纤控,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碉纺,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡船万,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了骨田。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耿导。...
    茶點(diǎn)故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖态贤,靈堂內(nèi)的尸體忽然破棺而出舱呻,到底是詐尸還是另有隱情,我是刑警寧澤悠汽,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布箱吕,位于F島的核電站,受9級特大地震影響介粘,放射性物質(zhì)發(fā)生泄漏殖氏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一姻采、第九天 我趴在偏房一處隱蔽的房頂上張望雅采。 院中可真熱鬧,春花似錦慨亲、人聲如沸婚瓜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽巴刻。三九已至,卻和暖如春蛉签,著一層夾襖步出監(jiān)牢的瞬間胡陪,已是汗流浹背沥寥。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留柠座,地道東北人邑雅。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像妈经,于是被迫代替她去往敵國和親淮野。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容