最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android實(shí)現(xiàn)View滑動(dòng)的幾種方式

 更新時(shí)間:2020年04月16日 16:28:49   作者:absfree  
Android中的View類(lèi)是所有UI控件的基類(lèi)(Base class),也就是說(shuō)我們平時(shí)所有到的各種UI控件,比如Button、ImagView等等都繼承自View類(lèi)。這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)View滑動(dòng)的幾種方式,需要的朋友可以參考下

什么是View?實(shí)現(xiàn)View滑動(dòng)的方式有哪些?

1. 關(guān)于View我們需要知道的

(1)什么是View?

Android中的View類(lèi)是所有UI控件的基類(lèi)(Base class),也就是說(shuō)我們平時(shí)所有到的各種UI控件,比如Button、ImagView等等都繼承自View類(lèi)。LinearLayout、FrameLayout等布局管理器的直接父類(lèi)是ViewGroup,而ViewGroup也有View類(lèi)派生??偟膩?lái)說(shuō),View是對(duì)UI控件的抽象,它代表了屏幕上的一個(gè)矩形區(qū)域。通過(guò)繼承View,并重寫(xiě)相應(yīng)方法,我們就能夠?qū)崿F(xiàn)具有各種外觀(guān)及行為的UI控件。Button等控件我們之所以能夠直接拿來(lái)即用,是因?yàn)镚oogle已經(jīng)幫我們完成了繼承View并重寫(xiě)方法的工作。

(2)View的位置

View在屏幕上的位置由它的以下四個(gè)參數(shù)所決定:

top:View的左上角的縱坐標(biāo),對(duì)應(yīng)著View類(lèi)中的成員變量mTop,可由getTop方法獲得;
left:View的左上角的橫坐標(biāo),對(duì)應(yīng)著View類(lèi)中的成員變量mLeft,可由getLeft方法獲得;
bottom:View的右下角的縱坐標(biāo),對(duì)應(yīng)著View類(lèi)中的成員變量mBottom,可由getBottom方法獲得;
right:View的右下角的橫坐標(biāo),對(duì)應(yīng)著View類(lèi)中的成員變量mRight,可由getRight方法獲得。

注意,以上的坐標(biāo)都是相對(duì)于父View來(lái)說(shuō)的,也就是說(shuō),坐標(biāo)都是相對(duì)坐標(biāo),因?yàn)樽覸iew的布局是由父View來(lái)完成的。如下圖所示:

有了這四個(gè)參數(shù),計(jì)算View的寬高就很容易了:width = right - left;height = bottom - top。關(guān)于View還有兩個(gè)參數(shù)需要我們注意:translationX代表View平移的水平距離,translationY代表View平移的豎直距離;x、y分別為View的左上角的橫縱坐標(biāo)。View若經(jīng)過(guò)了平移,改變的是它的x、y(代表當(dāng)前View的左上角位置),它的四個(gè)位置參數(shù)代表了View的原始位置信息,是始終不變的。View在平移的過(guò)程中始終滿(mǎn)足如下關(guān)系:

x = left + translationX; y = top + translationY。 

2. 實(shí)現(xiàn)View滑動(dòng)的幾種方式

我們?cè)谑褂肰iew的過(guò)程中,經(jīng)常需要實(shí)現(xiàn)View的滑動(dòng)效果。比如ListView、跟隨手指而移動(dòng)的自定義View等等,前者的滑動(dòng)效果是SDK為我們提供的,而對(duì)于我們自定義View的滑動(dòng)效果就需要我們自己來(lái)實(shí)現(xiàn)。下面我們來(lái)詳細(xì)介紹以下實(shí)現(xiàn)View滑動(dòng)的幾種方式。

(1)使用scrollTo/scrollBy實(shí)現(xiàn)View的滑動(dòng)

實(shí)現(xiàn)滑動(dòng)的最樸素直接的方式就是使用View類(lèi)自帶的scrollTo/scrollBy方法了。scrollBy方法是滑動(dòng)指定的位移量,而scrollTo方法是滑動(dòng)到指定位置。這兩個(gè)方法的源碼如下:

/** 
 * Set the scrolled position of your view. This will cause a call to 

 * {@link #onScrollChanged(int, int, int, int)} and the view will be 

 * invalidated. 

 * @param x the x position to scroll to 

 * @param y the y position to scroll to 

 */ 
public void scrollTo(int x, int y) { 
 if (mScrollX != x || mScrollY != y) { 
  int oldX = mScrollX; 
  int oldY = mScrollY; 
  mScrollX = x; 
  mScrollY = y; 
  onScrollChanged(mScrollX, mScrollY, oldX, oldY); 
  if (!awakenScrollBars()) { 
  invalidate(); 
  } 
 } 
} 

/** 
 * Move the scrolled position of your view. This will cause a call to 
 * {@link #onScrollChanged(int, int, int, int)} and the view will be 
 * invalidated. 
 * @param x the amount of pixels to scroll by horizontally 
 * @param y the amount of pixels to scroll by vertically 
*/ 
public void scrollBy(int x, int y) { 
 scrollTo(mScrollX + x, mScrollY + y); 
}

通過(guò)以上代碼的33~35行我們可以看到,scrollBy方法內(nèi)部也是調(diào)用了scrollTo方法來(lái)實(shí)現(xiàn)。以上源碼中我們注意到了mScrollX和mScrollY成員變量,前者是View的左邊緣減去View的內(nèi)容的左邊緣,后者是View的上邊緣減去View的內(nèi)容的上邊緣。示意圖如下:

上圖中,黑色邊框代表View在屏幕上對(duì)應(yīng)的矩形區(qū)域,藍(lán)色邊框代表View的內(nèi)容。在上圖中,我們調(diào)用scrollTo/scrollBy把View向右滾動(dòng)了一定距離。實(shí)際上,調(diào)用scrollBy/scrollTo方法只能實(shí)現(xiàn)View的內(nèi)容的滾動(dòng),而View的四個(gè)位置參數(shù)是保持不變的。想一下我們平常使用ListView時(shí),滾動(dòng)的就是ListView的內(nèi)容,而ListView本身在屏幕上的位置是不變的。上圖中,黑色左邊(即View的左邊緣)減去藍(lán)色左邊(即View的內(nèi)容的左邊緣)即可得到mScrollX。由此我們還可以知道,向右滾動(dòng)時(shí)mScrollX負(fù)的,向左滾動(dòng)時(shí)mScrollX是正的。同理我們可以知道,向下滾動(dòng)時(shí),mScrollY是負(fù)的,向上滾動(dòng)時(shí),mScrollY是正的。

經(jīng)過(guò)以上的分析,我們了解到使用scrollTo/scrollBy方法實(shí)現(xiàn)View的滑動(dòng)是很簡(jiǎn)單直接的,那么簡(jiǎn)單的背后有什么代價(jià)呢?代價(jià)就是滑動(dòng)不是“彈性的”,彈性滑動(dòng)指的是View的滑動(dòng)應(yīng)該是一個(gè)先加速再逐漸減速到停止的過(guò)程,這樣看起來(lái)很平滑,不會(huì)很突兀。scrollTo/scrollBy方法實(shí)現(xiàn)的滑動(dòng)看起來(lái)就會(huì)很突兀,這樣的用戶(hù)體驗(yàn)很不好。在解決這個(gè)問(wèn)題之前,我們先來(lái)看看實(shí)現(xiàn)View滑動(dòng)的其他方法。

(2)使用動(dòng)畫(huà)來(lái)實(shí)現(xiàn)View的滑動(dòng)

使用動(dòng)畫(huà)來(lái)實(shí)現(xiàn)View的滑動(dòng)主要通過(guò)改變View的translationX和translationY參數(shù)來(lái)實(shí)現(xiàn),使用動(dòng)畫(huà)的好處在于滑動(dòng)效果是平滑的。上面我們提到過(guò),View的x、y參數(shù)決定View的當(dāng)前位置,通過(guò)改變translationX和translationY,我們就可以改變View的當(dāng)前位置。我們可以使用屬性動(dòng)畫(huà)或者補(bǔ)間動(dòng)畫(huà)來(lái)實(shí)現(xiàn)View的平移。

首先,我們先來(lái)看一下如何使用補(bǔ)間動(dòng)畫(huà)來(lái)實(shí)現(xiàn)View的平移。補(bǔ)間動(dòng)畫(huà)資源定義如下(anim.xml):

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:fillAfter="true">

 <translate
 android:duration="100"
 android:fromXDelta="0"
 android:fromYDelta="0"
 android:interpolator="@android:anim/linear_interpolator"
 android:toXDelta="100"
 android:toYDelta="100"/>

</set>

然后在onCreat方法中調(diào)用startAnimation方法即可。使用補(bǔ)間動(dòng)畫(huà)實(shí)現(xiàn)View的滑動(dòng)有一個(gè)缺陷,那就是移動(dòng)的知識(shí)View的“影像”,這意味著其實(shí)View并未真正的移動(dòng),只是我們看起來(lái)它移動(dòng)了而已。拿Button來(lái)舉例,假若我們通過(guò)補(bǔ)間動(dòng)畫(huà)移動(dòng)了一個(gè)Button,我們會(huì)發(fā)現(xiàn),在Button的原來(lái)位置點(diǎn)擊屏幕會(huì)出發(fā)點(diǎn)擊事件,而在移動(dòng)后的Button上點(diǎn)擊不會(huì)觸發(fā)點(diǎn)擊事件。

接下來(lái),我們看看如何用屬性動(dòng)畫(huà)來(lái)實(shí)現(xiàn)View的平移。使用屬性動(dòng)畫(huà)實(shí)現(xiàn)View的平移更加簡(jiǎn)單,只需要以下一條語(yǔ)句:

ObjectAnimator.ofFloat(targetView, "translationX", 0, 100).setDuration(100).start(); 

以上代碼即實(shí)現(xiàn)了使用屬性動(dòng)畫(huà)把targetView在100ms內(nèi)向右平移100px。使用屬性動(dòng)畫(huà)的限制在于真正的屬性動(dòng)畫(huà)只可以在Android 3.0+使用(一些第三方庫(kù)實(shí)現(xiàn)的兼容低版本的屬性動(dòng)畫(huà)不是真正的屬性動(dòng)畫(huà)),優(yōu)點(diǎn)就是它可以真正的移動(dòng)View而不是僅僅移動(dòng)View的影像。

經(jīng)過(guò)以上的描述,使用屬性動(dòng)畫(huà)實(shí)現(xiàn)View的滑動(dòng)看起來(lái)是個(gè)不錯(cuò)的選擇,而且一些View的復(fù)雜的滑動(dòng)效果只有通過(guò)動(dòng)畫(huà)才能比較方便的實(shí)現(xiàn)。 

(3)通過(guò)改變布局參數(shù)來(lái)實(shí)現(xiàn)View的滑動(dòng)

通過(guò)改變布局參數(shù)來(lái)實(shí)現(xiàn)View的滑動(dòng)的思想很簡(jiǎn)單:比如向右移動(dòng)一個(gè)View,只需要把它的marginLeft參數(shù)增大,向其它方向移動(dòng)同理,只需改變相應(yīng)的margin參數(shù)。還有一種比較拐彎抹角的方法是在要移動(dòng)的View的旁邊預(yù)先放一個(gè)View(初始寬高設(shè)為0)。然后比如我們要向右移動(dòng)View,只需把預(yù)先放置的那個(gè)View的寬度增大,這樣就把View“擠”到右邊了。代碼示例如下:

MarginLayoutParams params = (MarginLayoutParams) mButton.getLayoutParams();
params.leftMargin += 100;
mButton.requestLayout();

以上代碼即實(shí)現(xiàn)了把mButton向右滑動(dòng)100px。通過(guò)改變布局參數(shù)來(lái)實(shí)現(xiàn)的滑動(dòng)效果也不是平滑的。 

(4)使用Scroller來(lái)實(shí)現(xiàn)彈性滑動(dòng)

上面我們提到了使用scrollTo/scrollBy方法實(shí)現(xiàn)View的滑動(dòng)效果不是平滑的,好消息是我們可以使用Scroller方法來(lái)輔助實(shí)現(xiàn)View的彈性滑動(dòng)。使用Scroller實(shí)現(xiàn)彈性滑動(dòng)的慣用代碼如下:

Scroller scroller = new Scroller(mContext);

private void smoothScrollTo(int dstX, int dstY) {
 int scrollX = getScrollX();
 int delta = dstX - scrollX;
 scroller.startScroll(scrollX, 0, delta, 0, 1000);
 invalidate();
}

@Override
public void computeScroll() {
 if (scroller.computeScrollOffset()) {
 scrollTo(scroller.getCurrX(), scroller.getCurY());
 postInvalidate();
 }
}

我們來(lái)看一下以上的代碼。第4行中,我們獲取到View的mScrollX參數(shù)并存到scrollX變量中。然后在第5行計(jì)算要滑動(dòng)的位移量。第6行調(diào)用了startScroll方法,我們來(lái)看看startScroll方法的源碼:

public void startScroll(int startX, int startY, int dx, int dy, int duration) { 
 mMode = SCROLL_MODE; 
 mFinished = false; 
 mDuration = duration; 
 mStartTime = AnimationUtils.currentAnimationTimeMillis(); 
 mStartX = startX; 
 mStartY = startY; 
 mFinalX = startX + dx; 
 mFinalY = startY + dy; 
 mDeltaX = dx; 
 mDeltaY = dy; 
 mDurationReciprocal = 1.0f / (float) mDuration; 
 
 mViscousFluidScale = 8.0f; 
 
 mViscousFluidNormalize = 1.0f; 
 mViscousFluidNormalize = 1.0f / viscousFluid(1.0f); 
}
 

從以上的源碼我們可以看到,startScroll方法中并沒(méi)有進(jìn)行實(shí)際的滾動(dòng)操作,而是把startX、startY、deltaX、deltaY等參數(shù)都保存了下來(lái)。那么究竟怎么實(shí)現(xiàn)View的滑動(dòng)的呢?我們先回到Scroller慣用代碼。我們看到第7行調(diào)用了invalidate方法,這個(gè)方法會(huì)請(qǐng)求重繪View,這會(huì)導(dǎo)致View的draw的方法被調(diào)用,draw的方法內(nèi)部會(huì)調(diào)用computeScroll方法。我們來(lái)看看第13行,調(diào)用了scrollTo方法,并傳入mScroller.getCurrX()和mScroller.getCurrY()方法作為參數(shù)。那么獲取到的這兩個(gè)參數(shù)是什么呢?這兩個(gè)參數(shù)是在第12行調(diào)用的computeScrollOffset方法中設(shè)置的,我們來(lái)看看這個(gè)方法中設(shè)置這兩個(gè)參數(shù)的相關(guān)代碼:

public boolean computeScrollOffset() {
 ...
 int timePassed = (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime);
 if (timePassed < mDuration) {
 switch (mMode) {
  case SCROLL_MODE:
  final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
  mCurrX = mStartX + Math.round(x * mDeltaX);
  mCurrY = mStartY + Math.rounc(y * mDeltaY);
  break;
 ...
 }
 }
 return true;
}

以上代碼中第8行和第9行設(shè)置的mCurrX和mCurrY即為以上scrollTo的兩個(gè)參數(shù),表示本次滑動(dòng)的目標(biāo)位置。computeScrollOffset方法返回true表示滑動(dòng)過(guò)程還未結(jié)束,否則表示結(jié)束。

通過(guò)以上的分析,我們大概了解了Scroller實(shí)現(xiàn)彈性滑動(dòng)的原理:invaldate方法會(huì)導(dǎo)致View的draw方法被調(diào)用,而draw會(huì)調(diào)用computeScroll方法,因此重寫(xiě)了computeScroll方法,而computeScrollOffset方法會(huì)根據(jù)時(shí)間的流逝動(dòng)態(tài)的計(jì)算出很小的一段時(shí)間應(yīng)該滑動(dòng)多少距離。也就是把一次滑動(dòng)拆分成無(wú)數(shù)次小距離滑動(dòng)從而實(shí)現(xiàn)“彈性滑動(dòng)”。

本文提到的所有三種滑動(dòng)方式的完整demo

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家學(xué)習(xí)Android軟件編程有所幫助。

相關(guān)文章

  • Android 利用三階貝塞爾曲線(xiàn)繪制運(yùn)動(dòng)軌跡的示例

    Android 利用三階貝塞爾曲線(xiàn)繪制運(yùn)動(dòng)軌跡的示例

    本篇文章主要介紹了Android 利用三階貝塞爾曲線(xiàn)繪制運(yùn)動(dòng)軌跡的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • Android開(kāi)發(fā)中的錯(cuò)誤及解決辦法總結(jié)

    Android開(kāi)發(fā)中的錯(cuò)誤及解決辦法總結(jié)

    本文屬于個(gè)人平時(shí)項(xiàng)目開(kāi)發(fā)過(guò)程遇到的一些問(wèn)題,記錄下來(lái)并總結(jié)解決方案,希望能幫到大家解決問(wèn)題,需要的朋友可以參考下
    2022-02-02
  • Android getViewById和getLayoutInflater().inflate()的詳解及比較

    Android getViewById和getLayoutInflater().inflate()的詳解及比較

    這篇文章主要介紹了Android getViewById和getLayoutInflater().inflate()的詳解及比較的相關(guān)資料,這里對(duì)這兩種方法進(jìn)行了詳細(xì)的對(duì)比,對(duì)于開(kāi)始學(xué)習(xí)Android的朋友使用這兩種方法是個(gè)很好的資料,需要的朋友可以參考下
    2016-11-11
  • android 使用XStream解析xml的實(shí)例

    android 使用XStream解析xml的實(shí)例

    下面小編就為大家分享一篇android 使用XStream解析xml的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • Android實(shí)現(xiàn)雷達(dá)View效果的示例代碼

    Android實(shí)現(xiàn)雷達(dá)View效果的示例代碼

    這篇文章主要介紹了Android實(shí)現(xiàn)雷達(dá)View效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Android文件選擇器ExFilePicker的使用方法

    Android文件選擇器ExFilePicker的使用方法

    這篇文章主要為大家詳細(xì)介紹了Android文件選擇器ExFilePicker的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • PopupWindow使用方法詳解

    PopupWindow使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了PopupWindow的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Android OpenGL ES實(shí)現(xiàn)簡(jiǎn)單綠幕摳圖

    Android OpenGL ES實(shí)現(xiàn)簡(jiǎn)單綠幕摳圖

    這篇文章主要為大家介紹了Android OpenGL ES實(shí)現(xiàn)簡(jiǎn)單綠幕摳圖示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 懸浮對(duì)話(huà)框Android代碼實(shí)現(xiàn)

    懸浮對(duì)話(huà)框Android代碼實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了懸浮對(duì)話(huà)框Android代碼實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 基于界面適配華為手機(jī)的虛擬按鍵的解決方法

    基于界面適配華為手機(jī)的虛擬按鍵的解決方法

    下面小編就為大家分享一篇基于界面適配華為手機(jī)的虛擬按鍵的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01

最新評(píng)論

温州市| 六枝特区| 武定县| 陆丰市| 乌海市| 津市市| 岳池县| 庄河市| 梨树县| 乡宁县| 博客| 泊头市| 大丰市| 哈尔滨市| 达州市| 常德市| 延吉市| 紫云| 云龙县| 道孚县| 庆云县| 磐石市| 清水县| 林周县| 东兴市| 黑龙江省| 岫岩| 云南省| 汪清县| 安乡县| 娄烦县| 永新县| 富源县| 杭锦后旗| 忻城县| 平谷区| 泗阳县| 巫溪县| 满洲里市| 郑州市| 石渠县|