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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android官方开发文档Training系列课程中文版:手势处理之滚动动画及Scroller

發(fā)布時(shí)間:2024/7/5 Android 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android官方开发文档Training系列课程中文版:手势处理之滚动动画及Scroller 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址:http://android.xsoftlab.net/training/gestures/scroll.html

在Android中,滑動(dòng)經(jīng)常由ScrollView類來(lái)實(shí)現(xiàn)。任何超出容器邊界的布局都應(yīng)該將自己內(nèi)嵌在ScrollView中,以便提供可滾動(dòng)的視圖效果。自定義滾動(dòng)只有在特定的場(chǎng)景下才會(huì)被用到。這節(jié)課將會(huì)描述這樣一種場(chǎng)景:使用scroller顯示一種可滾動(dòng)的效果。

你可以使用Scroller或者OverScroller來(lái)收集一些滑動(dòng)動(dòng)畫所需要的數(shù)據(jù)。這兩個(gè)類很相似,但是OverScroller包含了一些用于指示已經(jīng)到達(dá)布局邊界的方法。示例InteractiveChart在這里使用了類EdgeEffect(實(shí)際上是類EdgeEffectCompat),在用戶到達(dá)布局邊界時(shí)會(huì)顯示一種”glow“的效果。

Note: 我們推薦使用OverScroller。這個(gè)類提供了良好的向后兼容性。還應(yīng)該注意,通常只有在實(shí)現(xiàn)滑動(dòng)自己內(nèi)部的時(shí)候,才需要使用到scroller類。如果你將布局嵌入到ScrollView或HorizontalScrollView中的話,那么它們會(huì)將滾動(dòng)的相關(guān)事宜做好。

Scroller用于在時(shí)間軸上做動(dòng)畫滾動(dòng)效果,它使用了標(biāo)準(zhǔn)的滾動(dòng)物理學(xué)(摩擦力、速度等等)。Scroller本身不會(huì)繪制任何東西。Scroller會(huì)隨著時(shí)間的變化追蹤移動(dòng)的偏移量,但是它們不會(huì)自動(dòng)的將這些值應(yīng)用在你的View上。你需要自己獲取這些值并使用,這樣才會(huì)使滑動(dòng)的效果更流暢。

了解滑動(dòng)術(shù)語(yǔ)

“Scrolling”這個(gè)詞在Android中可被翻譯為各種不同的意思,這取決于具體的上下文。

Scrolling是一種viewport(viewport的意思是,你所看到的內(nèi)容的窗口)移動(dòng)的通用處理過(guò)程。當(dāng)scrolling處于x軸及y軸上時(shí),這被稱為“平移(panning)”。示例程序提供了相關(guān)的類:InteractiveChart,演示了滑動(dòng)的兩種不同類型,dragging(拖動(dòng))及flinging(滑動(dòng)):

  • Dragging 該滾動(dòng)類型在這種情況下發(fā)生:當(dāng)用戶的手指在屏幕上來(lái)回滑動(dòng)時(shí)。簡(jiǎn)單的Dragging由GestureDetector.OnGestureListener接口的onScroll()方法實(shí)現(xiàn)。
  • Flinging 該滾動(dòng)類型在這種情況下發(fā)生:當(dāng)用戶快速在屏幕上滑動(dòng)并離開屏幕時(shí)。在用戶離開了屏幕之后,常理上應(yīng)該保持滾動(dòng)狀態(tài),并隨之慢慢減速,直到viewport停止移動(dòng)。Flinging由GestureDetector.OnGestureListener接口的onFling()方法及scroller對(duì)象所實(shí)現(xiàn)。

將scroller對(duì)象與滑動(dòng)手勢(shì)結(jié)合使用是一種共通的方法。你可以重寫onTouchEvent()方法直接處理觸摸事件,并降低滑動(dòng)的速度來(lái)響應(yīng)相應(yīng)的觸摸事件。

實(shí)現(xiàn)基礎(chǔ)滾動(dòng)

這部分章節(jié)將會(huì)描述如何使用scroller。下面的代碼段摘自示例應(yīng)用InteractiveChart。它在這里使用了一個(gè)GestureDetector對(duì)象,重寫了GestureDetector.SimpleOnGestureListener的onFling()方法。它使用了OverScroller來(lái)追蹤滑動(dòng)中的手勢(shì)。如果用戶在滑動(dòng)之后到達(dá)了內(nèi)容的邊緣,那么APP會(huì)顯示一個(gè)”glow”的效果。

Note: 示例APP InteractiveChart 展示了一個(gè)圖表,這個(gè)圖標(biāo)可以縮放、平移、滾動(dòng)等等。在下面的代碼段中,mContentRect代表了矩形的坐標(biāo)點(diǎn),而繪制圖表的View則居于其中。在給定的時(shí)間內(nèi),一個(gè)總表的子集將會(huì)被繪制到這塊區(qū)域內(nèi)。mCurrentViewport代表了屏幕中當(dāng)前可視的部分圖表。因?yàn)橄袼氐钠屏客ǔ1划?dāng)做整型,所以mContentRect的類型是Rect。因?yàn)閳D形的數(shù)據(jù)范圍是小數(shù)類型,所以mCurrentViewport的類型是RectF。

代碼段的第一部分展示了onFling()方法的實(shí)現(xiàn):

// The current viewport. This rectangle represents the currently visible // chart domain and range. The viewport is the part of the app that the // user manipulates via touch gestures. private RectF mCurrentViewport = new RectF(AXIS_X_MIN, AXIS_Y_MIN, AXIS_X_MAX, AXIS_Y_MAX); // The current destination rectangle (in pixel coordinates) into which the // chart data should be drawn. private Rect mContentRect; private OverScroller mScroller; private RectF mScrollerStartViewport; ... private final GestureDetector.SimpleOnGestureListener mGestureListener= new GestureDetector.SimpleOnGestureListener() {@Overridepublic boolean onDown(MotionEvent e) {// Initiates the decay phase of any active edge effects.releaseEdgeEffects();mScrollerStartViewport.set(mCurrentViewport);// Aborts any active scroll animations and invalidates.mScroller.forceFinished(true);ViewCompat.postInvalidateOnAnimation(InteractiveLineGraphView.this);return true;}...@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {fling((int) -velocityX, (int) -velocityY);return true;} }; private void fling(int velocityX, int velocityY) {// Initiates the decay phase of any active edge effects.releaseEdgeEffects();// Flings use math in pixels (as opposed to math based on the viewport).Point surfaceSize = computeScrollSurfaceSize();mScrollerStartViewport.set(mCurrentViewport);int startX = (int) (surfaceSize.x * (mScrollerStartViewport.left - AXIS_X_MIN) / (AXIS_X_MAX - AXIS_X_MIN));int startY = (int) (surfaceSize.y * (AXIS_Y_MAX - mScrollerStartViewport.bottom) / (AXIS_Y_MAX - AXIS_Y_MIN));// Before flinging, aborts the current animation.mScroller.forceFinished(true);// Begins the animationmScroller.fling(// Current scroll positionstartX,startY,velocityX,velocityY,/** Minimum and maximum scroll positions. The minimum scroll * position is generally zero and the maximum scroll position * is generally the content size less the screen size. So if the * content width is 1000 pixels and the screen width is 200 * pixels, the maximum scroll offset should be 800 pixels.*/0, surfaceSize.x - mContentRect.width(),0, surfaceSize.y - mContentRect.height(),// The edges of the content. This comes into play when using// the EdgeEffect class to draw "glow" overlays.mContentRect.width() / 2,mContentRect.height() / 2);// Invalidates to trigger computeScroll()ViewCompat.postInvalidateOnAnimation(this); }

當(dāng)onFling()方法調(diào)用postInvalidateOnAnimation()方法時(shí),它會(huì)調(diào)用computeScroll()來(lái)更新x及y的值。

大多數(shù)View會(huì)將scroller對(duì)象的x及y的屬性值直接設(shè)置給方法scrollTo()。而下面的computeScroll()則采用了不同的方法:它調(diào)用computeScrollOffset()來(lái)獲取x及y的當(dāng)前坐標(biāo)。當(dāng)顯示的區(qū)域到達(dá)邊界時(shí),這里就會(huì)展示一個(gè)”glow”的效果,代碼會(huì)設(shè)置一個(gè)越過(guò)邊緣的效果,并會(huì)調(diào)用postInvalidateOnAnimation()來(lái)使View重新繪制。

// Edge effect / overscroll tracking objects. private EdgeEffectCompat mEdgeEffectTop; private EdgeEffectCompat mEdgeEffectBottom; private EdgeEffectCompat mEdgeEffectLeft; private EdgeEffectCompat mEdgeEffectRight; private boolean mEdgeEffectTopActive; private boolean mEdgeEffectBottomActive; private boolean mEdgeEffectLeftActive; private boolean mEdgeEffectRightActive; @Override public void computeScroll() {super.computeScroll();boolean needsInvalidate = false;// The scroller isn't finished, meaning a fling or programmatic pan // operation is currently active.if (mScroller.computeScrollOffset()) {Point surfaceSize = computeScrollSurfaceSize();int currX = mScroller.getCurrX();int currY = mScroller.getCurrY();boolean canScrollX = (mCurrentViewport.left > AXIS_X_MIN|| mCurrentViewport.right < AXIS_X_MAX);boolean canScrollY = (mCurrentViewport.top > AXIS_Y_MIN|| mCurrentViewport.bottom < AXIS_Y_MAX);/* * If you are zoomed in and currX or currY is* outside of bounds and you're not already* showing overscroll, then render the overscroll* glow edge effect.*/if (canScrollX&& currX < 0&& mEdgeEffectLeft.isFinished()&& !mEdgeEffectLeftActive) {mEdgeEffectLeft.onAbsorb((int) OverScrollerCompat.getCurrVelocity(mScroller));mEdgeEffectLeftActive = true;needsInvalidate = true;} else if (canScrollX&& currX > (surfaceSize.x - mContentRect.width())&& mEdgeEffectRight.isFinished()&& !mEdgeEffectRightActive) {mEdgeEffectRight.onAbsorb((int) OverScrollerCompat.getCurrVelocity(mScroller));mEdgeEffectRightActive = true;needsInvalidate = true;}if (canScrollY&& currY < 0&& mEdgeEffectTop.isFinished()&& !mEdgeEffectTopActive) {mEdgeEffectTop.onAbsorb((int) OverScrollerCompat.getCurrVelocity(mScroller));mEdgeEffectTopActive = true;needsInvalidate = true;} else if (canScrollY&& currY > (surfaceSize.y - mContentRect.height())&& mEdgeEffectBottom.isFinished()&& !mEdgeEffectBottomActive) {mEdgeEffectBottom.onAbsorb((int) OverScrollerCompat.getCurrVelocity(mScroller));mEdgeEffectBottomActive = true;needsInvalidate = true;}...}

下面是執(zhí)行實(shí)際放大的代碼:

// Custom object that is functionally similar to Scroller Zoomer mZoomer; private PointF mZoomFocalPoint = new PointF(); ... // If a zoom is in progress (either programmatically or via double // touch), performs the zoom. if (mZoomer.computeZoom()) {float newWidth = (1f - mZoomer.getCurrZoom()) * mScrollerStartViewport.width();float newHeight = (1f - mZoomer.getCurrZoom()) * mScrollerStartViewport.height();float pointWithinViewportX = (mZoomFocalPoint.x - mScrollerStartViewport.left)/ mScrollerStartViewport.width();float pointWithinViewportY = (mZoomFocalPoint.y - mScrollerStartViewport.top)/ mScrollerStartViewport.height();mCurrentViewport.set(mZoomFocalPoint.x - newWidth * pointWithinViewportX,mZoomFocalPoint.y - newHeight * pointWithinViewportY,mZoomFocalPoint.x + newWidth * (1 - pointWithinViewportX),mZoomFocalPoint.y + newHeight * (1 - pointWithinViewportY));constrainViewport();needsInvalidate = true; } if (needsInvalidate) {ViewCompat.postInvalidateOnAnimation(this); }

下面是computeScrollSurfaceSize()方法的內(nèi)容。它計(jì)算了當(dāng)前可滑動(dòng)的界面的尺寸,以像素為單位。舉個(gè)例子,如果整個(gè)圖表區(qū)域是可見的,那么它的值就等于mContentRect。如果圖標(biāo)被放大了200%,那么返回的值就是水平及垂直方向值的兩倍。

private Point computeScrollSurfaceSize() {return new Point((int) (mContentRect.width() * (AXIS_X_MAX - AXIS_X_MIN)/ mCurrentViewport.width()),(int) (mContentRect.height() * (AXIS_Y_MAX - AXIS_Y_MIN)/ mCurrentViewport.height())); }

總結(jié)

以上是生活随笔為你收集整理的Android官方开发文档Training系列课程中文版:手势处理之滚动动画及Scroller的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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