android學(xué)習(xí)筆記之View的滑動
前言
其實不管是哪種滑動方式,基本思想都是類似的:當(dāng)點擊事件傳遞到View時,系統(tǒng)記下觸摸點的坐標(biāo),手指移動的時候,系統(tǒng)記下移動后的坐標(biāo),并計算出偏移量,并通過偏移量來修改View的坐標(biāo)。
下面我們來講下幾種滑動方法:
1.layout方法
大家知道,繪制View的時候會調(diào)用onlayout方法來設(shè)置要顯示的位置。因此我們也可以通過修改view的left,top,right,bottom這4個屬性來控制view的坐標(biāo)。接下來我們來自定義一個View,通過layout方法來實現(xiàn)滑動:
package com.example.myapplication.views import android.content.Context import android.util.AttributeSet import android.view.MotionEvent import android.view.View class CustomView @JvmOverloads constructor( context: Context, attrs:AttributeSet? = null, defStyleAttr:Int= 0 ) :View( context,attrs,defStyleAttr){ private var lastX:Int = 0 private var lastY:Int = 0 override fun onTouchEvent(event: MotionEvent): Boolean { //獲取手指觸摸點的橫坐標(biāo)和縱坐標(biāo) val x = event.x.toInt() val y = event.y.toInt() when(event.action) { MotionEvent.ACTION_DOWN -> { lastX = x lastY = y } MotionEvent.ACTION_MOVE -> { //計算移動距離 val offsetX = x -lastX val offsetY = y -lastY //調(diào)用layout方法來重新放置他的位置 layout(left+offsetX,top+offsetY,right + offsetX, bottom + offsetY) } } return true } }
然后我們把他放到XML里去使用:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.example.myapplication.views.CustomView android:id="@+id/view_my" android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center_horizontal" android:background="@mipmap/cai"/> </LinearLayout>
看下效果:
這個移動的效果實現(xiàn)。
2.接下來,我們看看offsetLeftAndRight()與offsetTopAndBottom()方法
這兩種方法和layout方法差不多,我們稍加修改就可以。我們替換下ACTION_MOVE中的代碼塊:
MotionEvent.ACTION_MOVE -> { //計算移動距離 val offsetX = x -lastX val offsetY = y -lastY //對left和right進(jìn)行偏移 offsetLeftAndRight(offsetX) //對top和bottom進(jìn)行偏移 offsetTopAndBottom(offsetY) // //調(diào)用layout方法來重新放置他的位置 // layout(left+offsetX,top+offsetY,right + offsetX, bottom + offsetY) }
仍然能夠?qū)崿F(xiàn)。
3.第三個方法:LayoutParams(改變布局參數(shù))
LayoutParams主要保存了一個View的布局參數(shù),因此我們可以通過LayoutParams來改變View的布局參數(shù)。從而達(dá)到改變View位置的效果。我們同樣替換下ACTION_MOVE中的代碼塊:
MotionEvent.ACTION_MOVE -> { //計算移動距離 val offsetX = x -lastX val offsetY = y -lastY val layoutParams = layoutParams as LinearLayout.LayoutParams layoutParams.leftMargin = left + offsetX layoutParams.topMargin = top + offsetY setLayoutParams(layoutParams) // //對left和right進(jìn)行偏移 // offsetLeftAndRight(offsetX) // //對top和bottom進(jìn)行偏移 // offsetTopAndBottom(offsetY) // //調(diào)用layout方法來重新放置他的位置 // layout(left+offsetX,top+offsetY,right + offsetX, bottom + offsetY) } }
不過經(jīng)過我實驗,這個有挺大的偏差,總是靠右邊。什么原因?
4.接下來,看看使用第四種方法,使用動畫來滑動。
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true"> <translate android:fromXDelta="0" android:toXDelta="300" /> </set>
使用代碼調(diào)用:
findViewById<View>(R.id.view_my).animation = AnimationUtils.loadAnimation(this,R.anim.translate)
需要注意的是,view動畫,并不能改變view的位置參數(shù)。所以我們點擊Button并不會觸發(fā),因為他的負(fù)控件要先判斷點擊事件是否在子view的位置參數(shù)范圍內(nèi)才會分發(fā)給他,當(dāng)我們點擊原來的位置的時候,才會響應(yīng)。如果我們想讓他在移動后的位置響應(yīng),也就是說更改view的位置參數(shù),那么可以使用屬性動畫。
val customView = findViewById<View>(R.id.view_my) findViewById<Button>(R.id.btn_move).setOnClickListener { ObjectAnimator.ofFloat(customView,"translationX",0f,300f).setDuration(1000).start() }
5.接下來我們看看第五種方法,scrollTo與ScrollBy
scrollTo(x,y)表示移動到一個具體的坐標(biāo)點,而scrollBy(dx,dy)表示移動的增量為dx,dy,其實我們看源碼就知道scorllBy最終也是計算出最終坐標(biāo),最終調(diào)用scrollTo的。我們可以看下源碼:
public void scrollBy(int x, int y) { scrollTo(mScrollX + x, mScrollY + y); }
需要注意的是,scrollTo和ScrollBy是移動的內(nèi)容。我們?nèi)绻O(shè)置了Bacgroud會發(fā)現(xiàn)看不出效果??梢愿南拢?/p>
<com.example.myapplication.views.CustomView android:id="@+id/view_my" android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center_horizontal" android:foreground="@mipmap/cai"/>
findViewById<Button>(R.id.btn_move).setOnClickListener { customView.scrollBy(50,100) // ObjectAnimator.ofFloat(customView,"translationX",0f,300f).setDuration(1000).start() }
使用foreground。接著看下效果:
最開始是這樣的,然后我們點擊下按鈕,變成了這樣:
是不是發(fā)現(xiàn)了神奇的現(xiàn)象。再點擊一次:
好家伙,快看不到了。什么原因呢?這里有兩個奇怪的現(xiàn)象,第一個是他似乎移動的方向是相反的,第二個是是越來越小。準(zhǔn)確說,是好像并不是縮小,而是只能看到局部。
這是因為參照物的不同導(dǎo)致的。假設(shè),我們把手機(jī)屏幕比喻為放大鏡。下面的內(nèi)容當(dāng)作報紙。我們調(diào)用這個方法,實際是使放大鏡相對于這個view,往下移動了,放大鏡看不到的地方不并是不存在了。所以他才看起來像是往左上移動了。然后,因為我們是內(nèi)容在移動,所以View本身并沒有移動,所以他的前景色就看不到了。
我們?nèi)绻M茏龅诫S手指移動,可以在move方法里這樣修改:
MotionEvent.ACTION_MOVE -> { //計算移動距離 val offsetX = x -lastX val offsetY = y -lastY val parentView = parent as View parentView.scrollBy(-offsetX,-offsetY) }
這里,取相反的值,崗剛說了,是因為參考物,會導(dǎo)致視覺相反。而要取他的parent,是因為這個view就屬于他的parent的內(nèi)容。所以,他就可以進(jìn)行相關(guān)的動作。
6.來看第六種方法Scroller
我們在使用scrollTo/scrollBy方法進(jìn)行滑動的時候,這個過程是瞬間就完成的。所以體驗就不是太好。我們可以使用scroller來實現(xiàn)有過度效果的滑動。但是scroller本身是不能實現(xiàn)View的滑動,它需要與View的computeScroller 方法配合才能實現(xiàn)彈性滑動效果。來看代碼實現(xiàn):
首先,定義個成員變量:
private val mScroller = Scroller(context)
接下來,我們重寫computeScroll方法,系統(tǒng)會繪制View的時候,在draw方法里調(diào)用該方法。
我們先在CustomView里定義個方法:
fun smoothScrollTo(destX:Int, destY:Int){ val scrollX = scrollX val delta = destX - scrollX mScroller.startScroll(scrollX,0,delta,2,2000) invalidate() }
這個方法是提供給外部調(diào)用的,參數(shù)是想偏移的X和Y。
scrollX是目前已經(jīng)滑動值,拿目的要偏移的減去已經(jīng)滑動的,就是還剩下的。調(diào)用scroller.startScroll()方法。設(shè)置一個duration。我們調(diào)用invalidate()就開始重繪。這個時候就會調(diào)用view的computeScroller方法。這里面我們調(diào)用父空間viewGroup的scroollTo方法,來獲取當(dāng)前的一小段滑動值,然后行成小的滑動。接著調(diào)用invalidate()方法不斷的重繪。
override fun computeScroll() { super.computeScroll() if (mScroller.computeScrollOffset()) { (parent as View).scrollTo(mScroller.currX,mScroller.currY) invalidate() } }
最后,我們在activity里調(diào)用:
customView.smoothScrollTo(-400,0)
向右邊平移400。
總結(jié)
到此這篇關(guān)于android學(xué)習(xí)筆記之View的滑動的文章就介紹到這了,更多相關(guān)android View的滑動內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android通訊錄開發(fā)之刪除功能的實現(xiàn)方法
這篇文章主要介紹了Android通訊錄開發(fā)之刪除功能的實現(xiàn)方法,有需要的朋友可以參考一下2014-01-01Android逆向入門之常見Davlik字節(jié)碼解析
Dalvik是Google公司自己設(shè)計用于Android平臺的虛擬機(jī)。Dalvik虛擬機(jī)是Google等廠商合作開發(fā)的Android移動設(shè)備平臺的核心組成部分之一,本篇文章我們來詳細(xì)解釋常見Davlik字節(jié)碼2021-11-11Input系統(tǒng)按鍵事件的分發(fā)處理示例詳解
這篇文章主要為大家介紹了Input系統(tǒng)按鍵事件的分發(fā)處理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Android實現(xiàn)實時滑動ViewPager的2種方式
這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)實時滑動ViewPager的2種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10Android清空編輯框內(nèi)容功能的實現(xiàn)實例代碼
本篇文章主要介紹了Android清空編輯框數(shù)據(jù)功能的實現(xiàn)實例代碼,非常具有實用價值,需要的朋友可以參考下。2017-03-03Flutter 使用Navigator進(jìn)行局部跳轉(zhuǎn)頁面的方法
這篇文章主要介紹了Flutter 使用Navigator進(jìn)行局部跳轉(zhuǎn)頁面的方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05