Unter Android wird das Scrollen in der Regel mit der
ScrollView
Klasse erreicht. Verschachteln Sie jedes Standardlayout, das über die Grenzen seines
Containers hinausgeht, in einem ScrollView, um eine scrollbare Ansicht bereitzustellen, die vom
Framework verwaltet wird. Die Implementierung eines benutzerdefinierten Scrollers ist nur in besonderen
Fällen erforderlich. In diesem Dokument wird beschrieben, wie Sie mit Scrollern einen Scrolling-Effekt als Reaktion
auf Touch-Gesten anzeigen.
Ihre App kann
Scroller (Scroller
oder
OverScroller) verwenden, um
die Daten zu erfassen, die für die Erstellung einer Scrolling-Animation als Reaktion auf ein Touch
Ereignis erforderlich sind. Sie sind ähnlich, aber OverScroller enthält auch Methoden, mit denen Nutzer darauf hingewiesen werden, wenn sie nach einer Schwenk- oder Wischgeste die Inhaltsränder erreichen.
- Ab Android 12 (API-Level 31) werden die visuellen Elemente bei einem Ziehen gedehnt und springen zurück. Bei einer Wischgeste werden sie ebenfalls gedehnt und springen zurück.
- Unter Android 11 (API-Level 30) und niedriger wird an den Rändern nach einer Zieh- oder Wischgeste ein Leuchteffekt angezeigt.
Im InteractiveChart Beispiel in diesem Dokument wird die
EdgeEffect
Klasse verwendet, um diese Overscroll-Effekte anzuzeigen.
Mit einem Scroller können Sie das Scrollen im Zeitverlauf animieren und dabei die standardmäßige Scrolling-Physik der Plattform verwenden, z. B. Reibung, Geschwindigkeit und andere Eigenschaften. Der Scroller selbst zeichnet nichts. Scroller verfolgen Scroll Offsets im Zeitverlauf, wenden diese Positionen aber nicht automatisch auf Ihre Ansicht an. Sie müssen neue Koordinaten in einer Geschwindigkeit abrufen und anwenden, die die Scrolling-Animation flüssig aussehen lässt.
Begriffe zum Scrollen
Scrollen kann unter Android je nach Kontext unterschiedliche Bedeutungen haben.
Scrollen ist der allgemeine Vorgang, den Viewport zu bewegen, also
das "Fenster" mit den Inhalten, die Sie sich ansehen. Wenn das Scrollen sowohl auf der
x- als auch auf der y-Achse erfolgt, wird es als Schwenken bezeichnet. Die
InteractiveChart Beispiel-App in diesem Dokument veranschaulicht zwei
verschiedene Arten des Scrollens: Ziehen und Wischen:
- Ziehen: Diese Art des Scrollens tritt auf, wenn ein Nutzer
mit dem Finger über den Touchscreen zieht. Sie können das Ziehen implementieren, indem Sie
überschreiben
onScroll()inGestureDetector.OnGestureListener. Weitere Informationen zum Ziehen finden Sie unter Ziehen und Skalieren. - Wischen:Diese Art des Scrollens tritt auf, wenn ein Nutzer
mit dem Finger schnell zieht und ihn dann anhebt. Nachdem der Nutzer den Finger angehoben hat, sollte der Viewport in der Regel weiter bewegt werden, aber die Geschwindigkeit sollte abnehmen, bis der
Viewport zum Stillstand kommt. Sie können das Wischen implementieren, indem Sie
onFling()inGestureDetector.OnGestureListenerüberschreiben und ein Scroller Objekt verwenden. - Schwenken: Das gleichzeitige Scrollen entlang der x- und der y-Achse wird als Schwenken bezeichnet.
Scroller-Objekte werden häufig in Verbindung mit einer Wischgeste verwendet, aber
Sie können sie in jedem Kontext verwenden, in dem die UI als Reaktion auf ein Touch-Ereignis scrollen soll. Sie können beispielsweise
onTouchEvent()
überschreiben, um Touch-Ereignisse direkt zu verarbeiten und als Reaktion auf diese Touch-Ereignisse einen Scrolling-Effekt oder eine
"Animation zum Einrasten auf einer Seite" zu erzeugen.
Komponenten mit integrierten Scrolling-Implementierungen
Die folgenden Android-Komponenten enthalten eine integrierte Unterstützung für das Scrollen und Overscroll-Verhalten:
GridViewHorizontalScrollViewListViewNestedScrollViewRecyclerViewScrollViewViewPagerViewPager2
Wenn Ihre App das Scrollen und Overscrollen in einer anderen Komponente unterstützen muss, führen Sie die folgenden Schritte aus:
- Erstellen Sie eine benutzerdefinierte Touch-basierte Scrolling Implementierung.
- Implementieren Sie den Stretch-Overscroll-Effekt, um Geräte mit Android 12 und höher zu unterstützen. implement the stretch overscroll effect.
Benutzerdefinierte Touch-basierte Scrolling-Implementierung erstellen
In diesem Abschnitt wird beschrieben, wie Sie einen eigenen Scroller erstellen, wenn Ihre App eine Komponente verwendet, die keine integrierte Unterstützung für das Scrollen und Overscrollen enthält.
Das folgende Snippet stammt aus dem
InteractiveChart
Beispiel. Es verwendet einen
GestureDetector
und überschreibt die
GestureDetector.SimpleOnGestureListener
Methode onFling(). OverScroller wird verwendet, um die
Wischgeste zu verfolgen. Wenn der Nutzer nach der
Wischgeste die Inhaltsränder erreicht, gibt der Container an, wann der Nutzer das Ende des
Inhalts erreicht. Die Angabe hängt von der Android-Version ab, die auf einem Gerät
ausgeführt wird:
- Unter Android 12 und höher werden die visuellen Elemente gedehnt und springen zurück.
- Unter Android 11 und niedriger wird für die visuellen Elemente ein Leuchteffekt angezeigt.
Der erste Teil des folgenden Snippets zeigt die Implementierung von
onFling():
Kotlin
// Viewport extremes. See currentViewport for a discussion of the viewport. private val AXIS_X_MIN = -1f private val AXIS_X_MAX = 1f private val AXIS_Y_MIN = -1f private val AXIS_Y_MAX = 1f // The current viewport. This rectangle represents the visible chart // domain and range. The viewport is the part of the app that the // user manipulates via touch gestures. private val currentViewport = 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 must be drawn. private lateinit var contentRect: Rect private lateinit var scroller: OverScroller private lateinit var scrollerStartViewport: RectF ... private val gestureListener = object : GestureDetector.SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { // Initiates the decay phase of any active edge effects. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { releaseEdgeEffects() } scrollerStartViewport.set(currentViewport) // Aborts any active scroll animations and invalidates. scroller.forceFinished(true) ViewCompat.postInvalidateOnAnimation(this@InteractiveLineGraphView) return true } ... override fun onFling( e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { fling((-velocityX).toInt(), (-velocityY).toInt()) return true } } private fun fling(velocityX: Int, velocityY: Int) { // Initiates the decay phase of any active edge effects. // On Android 12 and later, the edge effect (stretch) must // continue. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { releaseEdgeEffects() } // Flings use math in pixels, as opposed to math based on the viewport. val surfaceSize: Point = computeScrollSurfaceSize() val (startX: Int, startY: Int) = scrollerStartViewport.run { set(currentViewport) (surfaceSize.x * (left - AXIS_X_MIN) / (AXIS_X_MAX - AXIS_X_MIN)).toInt() to (surfaceSize.y * (AXIS_Y_MAX - bottom) / (AXIS_Y_MAX - AXIS_Y_MIN)).toInt() } // Before flinging, stops the current animation. scroller.forceFinished(true) // Begins the animation. scroller.fling( // Current scroll position. startX, startY, velocityX, velocityY, /* * Minimum and maximum scroll positions. The minimum scroll * position is generally 0 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 is 800 pixels. */ 0, surfaceSize.x - contentRect.width(), 0, surfaceSize.y - contentRect.height(), // The edges of the content. This comes into play when using // the EdgeEffect class to draw "glow" overlays. contentRect.width() / 2, contentRect.height() / 2 ) // Invalidates to trigger computeScroll(). ViewCompat.postInvalidateOnAnimation(this) }
Java
// Viewport extremes. See currentViewport for a discussion of the viewport. private static final float AXIS_X_MIN = -1f; private static final float AXIS_X_MAX = 1f; private static final float AXIS_Y_MIN = -1f; private static final float AXIS_Y_MAX = 1f; // The current viewport. This rectangle represents the visible chart // domain and range. The viewport is the part of the app that the // user manipulates via touch gestures. private RectF currentViewport = 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 must be drawn. private final Rect contentRect = new Rect(); private final OverScroller scroller; private final RectF scrollerStartViewport = new RectF(); // Used only for zooms and flings. ... private final GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDown(MotionEvent e) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { releaseEdgeEffects(); } scrollerStartViewport.set(currentViewport); scroller.forceFinished(true); ViewCompat.postInvalidateOnAnimation(InteractiveLineGraphView.this); return true; } ... @Override public 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. // On Android 12 and later, the edge effect (stretch) must // continue. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { releaseEdgeEffects(); } // Flings use math in pixels, as opposed to math based on the viewport. Point surfaceSize = computeScrollSurfaceSize(); scrollerStartViewport.set(currentViewport); int startX = (int) (surfaceSize.x * (scrollerStartViewport.left - AXIS_X_MIN) / ( AXIS_X_MAX - AXIS_X_MIN)); int startY = (int) (surfaceSize.y * (AXIS_Y_MAX - scrollerStartViewport.bottom) / ( AXIS_Y_MAX - AXIS_Y_MIN)); // Before flinging, stops the current animation. scroller.forceFinished(true); // Begins the animation. scroller.fling( // Current scroll position. startX, startY, velocityX, velocityY, /* * Minimum and maximum scroll positions. The minimum scroll * position is generally 0 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 is 800 pixels. */ 0, surfaceSize.x - contentRect.width(), 0, surfaceSize.y - contentRect.height(), // The edges of the content. This comes into play when using // the EdgeEffect class to draw "glow" overlays. contentRect.width() / 2, contentRect.height() / 2); // Invalidates to trigger computeScroll(). ViewCompat.postInvalidateOnAnimation(this); }
Wenn onFling() aufruft
postInvalidateOnAnimation(),
wird
computeScroll()
ausgelöst, um die Werte für x und y zu aktualisieren. Dies geschieht in der Regel, wenn ein
untergeordnetes Element einer Ansicht einen Scrollvorgang mit einem Scroller-Objekt animiert, wie im vorherigen
Beispiel gezeigt.
Die meisten Ansichten übergeben die x - und y -Position des Scroller-Objekts direkt
an
scrollTo().
Die folgende Implementierung von computeScroll() verfolgt einen anderen
Ansatz: Sie ruft
computeScrollOffset()
auf, um die aktuelle Position von x und y abzurufen. Wenn die Kriterien für
die Anzeige eines Overscroll-Leuchteffekts erfüllt sind, d. h. die Anzeige
ist vergrößert, x oder y liegt außerhalb der Grenzen und die App zeigt noch keinen Overscroll-Effekt an, wird der Overscroll-Leuchteffekt eingerichtet und
aufgerufen, um eine Aktualisierung der
Ansicht auszulösen.postInvalidateOnAnimation()
Kotlin
// Edge effect/overscroll tracking objects. private lateinit var edgeEffectTop: EdgeEffect private lateinit var edgeEffectBottom: EdgeEffect private lateinit var edgeEffectLeft: EdgeEffect private lateinit var edgeEffectRight: EdgeEffect private var edgeEffectTopActive: Boolean = false private var edgeEffectBottomActive: Boolean = false private var edgeEffectLeftActive: Boolean = false private var edgeEffectRightActive: Boolean = false override fun computeScroll() { super.computeScroll() var needsInvalidate = false // The scroller isn't finished, meaning a fling or // programmatic pan operation is active. if (scroller.computeScrollOffset()) { val surfaceSize: Point = computeScrollSurfaceSize() val currX: Int = scroller.currX val currY: Int = scroller.currY val (canScrollX: Boolean, canScrollY: Boolean) = currentViewport.run { (left > AXIS_X_MIN || right < AXIS_X_MAX) to (top > AXIS_Y_MIN || bottom < AXIS_Y_MAX) } /* * If you are zoomed in, currX or currY is * outside of bounds, and you aren't already * showing overscroll, then render the overscroll * glow edge effect. */ if (canScrollX && currX < 0 && edgeEffectLeft.isFinished && !edgeEffectLeftActive) { edgeEffectLeft.onAbsorb(scroller.currVelocity.toInt()) edgeEffectLeftActive = true needsInvalidate = true } else if (canScrollX && currX > surfaceSize.x - contentRect.width() && edgeEffectRight.isFinished && !edgeEffectRightActive) { edgeEffectRight.onAbsorb(scroller.currVelocity.toInt()) edgeEffectRightActive = true needsInvalidate = true } if (canScrollY && currY < 0 && edgeEffectTop.isFinished && !edgeEffectTopActive) { edgeEffectTop.onAbsorb(scroller.currVelocity.toInt()) edgeEffectTopActive = true needsInvalidate = true } else if (canScrollY && currY > surfaceSize.y - contentRect.height() && edgeEffectBottom.isFinished && !edgeEffectBottomActive) { edgeEffectBottom.onAbsorb(scroller.currVelocity.toInt()) edgeEffectBottomActive = true needsInvalidate = true } ... } }
Java
// Edge effect/overscroll tracking objects. private EdgeEffectCompat edgeEffectTop; private EdgeEffectCompat edgeEffectBottom; private EdgeEffectCompat edgeEffectLeft; private EdgeEffectCompat edgeEffectRight; private boolean edgeEffectTopActive; private boolean edgeEffectBottomActive; private boolean edgeEffectLeftActive; private boolean edgeEffectRightActive; @Override public void computeScroll() { super.computeScroll(); boolean needsInvalidate = false; // The scroller isn't finished, meaning a fling or // programmatic pan operation is active. if (scroller.computeScrollOffset()) { Point surfaceSize = computeScrollSurfaceSize(); int currX = scroller.getCurrX(); int currY = scroller.getCurrY(); boolean canScrollX = (currentViewport.left > AXIS_X_MIN || currentViewport.right < AXIS_X_MAX); boolean canScrollY = (currentViewport.top > AXIS_Y_MIN || currentViewport.bottom < AXIS_Y_MAX); /* * If you are zoomed in, currX or currY is * outside of bounds, and you aren't already * showing overscroll, then render the overscroll * glow edge effect. */ if (canScrollX && currX < 0 && edgeEffectLeft.isFinished() && !edgeEffectLeftActive) { edgeEffectLeft.onAbsorb((int)mScroller.getCurrVelocity()); edgeEffectLeftActive = true; needsInvalidate = true; } else if (canScrollX && currX > (surfaceSize.x - contentRect.width()) && edgeEffectRight.isFinished() && !edgeEffectRightActive) { edgeEffectRight.onAbsorb((int)mScroller.getCurrVelocity()); edgeEffectRightActive = true; needsInvalidate = true; } if (canScrollY && currY < 0 && edgeEffectTop.isFinished() && !edgeEffectTopActive) { edgeEffectRight.onAbsorb((int)mScroller.getCurrVelocity()); edgeEffectTopActive = true; needsInvalidate = true; } else if (canScrollY && currY > (surfaceSize.y - contentRect.height()) && edgeEffectBottom.isFinished() && !edgeEffectBottomActive) { edgeEffectRight.onAbsorb((int)mScroller.getCurrVelocity()); edgeEffectBottomActive = true; needsInvalidate = true; } ... }
Hier ist der Teil des Codes, der den eigentlichen Zoomvorgang ausführt:
Kotlin
lateinit var zoomer: Zoomer val zoomFocalPoint = PointF() ... // If a zoom is in progress—either programmatically // or through double touch—this performs the zoom. if (zoomer.computeZoom()) { val newWidth: Float = (1f - zoomer.currZoom) * scrollerStartViewport.width() val newHeight: Float = (1f - zoomer.currZoom) * scrollerStartViewport.height() val pointWithinViewportX: Float = (zoomFocalPoint.x - scrollerStartViewport.left) / scrollerStartViewport.width() val pointWithinViewportY: Float = (zoomFocalPoint.y - scrollerStartViewport.top) / scrollerStartViewport.height() currentViewport.set( zoomFocalPoint.x - newWidth * pointWithinViewportX, zoomFocalPoint.y - newHeight * pointWithinViewportY, zoomFocalPoint.x + newWidth * (1 - pointWithinViewportX), zoomFocalPoint.y + newHeight * (1 - pointWithinViewportY) ) constrainViewport() needsInvalidate = true } if (needsInvalidate) { ViewCompat.postInvalidateOnAnimation(this) }
Java
// Custom object that is functionally similar to Scroller. Zoomer zoomer; private PointF zoomFocalPoint = new PointF(); ... // If a zoom is in progress—either programmatically // or through double touch—this performs the zoom. if (zoomer.computeZoom()) { float newWidth = (1f - zoomer.getCurrZoom()) * scrollerStartViewport.width(); float newHeight = (1f - zoomer.getCurrZoom()) * scrollerStartViewport.height(); float pointWithinViewportX = (zoomFocalPoint.x - scrollerStartViewport.left) / scrollerStartViewport.width(); float pointWithinViewportY = (zoomFocalPoint.y - scrollerStartViewport.top) / scrollerStartViewport.height(); currentViewport.set( zoomFocalPoint.x - newWidth * pointWithinViewportX, zoomFocalPoint.y - newHeight * pointWithinViewportY, zoomFocalPoint.x + newWidth * (1 - pointWithinViewportX), zoomFocalPoint.y + newHeight * (1 - pointWithinViewportY)); constrainViewport(); needsInvalidate = true; } if (needsInvalidate) { ViewCompat.postInvalidateOnAnimation(this); }
Dies ist die Methode computeScrollSurfaceSize(), die in
dem vorherigen Snippet aufgerufen wird. Sie berechnet die aktuelle Größe der scrollbaren Oberfläche in
Pixel. Wenn beispielsweise der gesamte Diagrammbereich sichtbar ist, entspricht dies der aktuellen
Größe von mContentRect. Wenn das Diagramm in beiden
Richtungen um 200% vergrößert ist, ist die zurückgegebene Größe horizontal und vertikal doppelt so groß.
Kotlin
private fun computeScrollSurfaceSize(): Point { return Point( (contentRect.width() * (AXIS_X_MAX - AXIS_X_MIN) / currentViewport.width()).toInt(), (contentRect.height() * (AXIS_Y_MAX - AXIS_Y_MIN) / currentViewport.height()).toInt() ) }
Java
private Point computeScrollSurfaceSize() { return new Point( (int) (contentRect.width() * (AXIS_X_MAX - AXIS_X_MIN) / currentViewport.width()), (int) (contentRect.height() * (AXIS_Y_MAX - AXIS_Y_MIN) / currentViewport.height())); }
Ein weiteres Beispiel für die Verwendung von Scrollern finden Sie im
Quellcode
für die ViewPager Klasse. Sie scrollt als Reaktion auf Wischgesten und verwendet
das Scrollen, um die "Einrasten auf einer Seite"-Animation zu implementieren.
Stretch-Overscroll-Effekt implementieren
Ab Android 12 werden in EdgeEffect die
folgenden APIs zum Implementieren des Stretch-Overscroll-Effekts hinzugefügt:
getDistance()onPullDistance()
So sorgen Sie für eine optimale Nutzererfahrung mit dem Stretch-Overscroll-Effekt:
- Wenn die Stretch-Animation aktiv ist, wenn der Nutzer die Inhalte berührt, registrieren Sie die Berührung als „Catch“. Der Nutzer beendet die Animation und beginnt, die Dehnung wieder zu manipulieren.
- Wenn der Nutzer den Finger in die entgegengesetzte Richtung der Dehnung bewegt, lassen Sie die Dehnung los, bis sie vollständig verschwunden ist, und beginnen Sie dann mit dem Scrollen.
- Wenn der Nutzer während einer Dehnung wischt, wischen Sie den
EdgeEffect, um den Dehnungseffekt zu verstärken.
Animation abfangen
Wenn ein Nutzer eine aktive Stretch-Animation abfängt,
EdgeEffect.getDistance() gibt 0 zurück. Diese Bedingung
gibt an, dass die Dehnung durch die Touch-Bewegung manipuliert werden muss. In den meisten
Containern wird der Catch in onInterceptTouchEvent() erkannt, wie
im folgenden Code-Snippet gezeigt:
Kotlin
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { ... when (action and MotionEvent.ACTION_MASK) { MotionEvent.ACTION_DOWN -> ... isBeingDragged = EdgeEffectCompat.getDistance(edgeEffectBottom) > 0f || EdgeEffectCompat.getDistance(edgeEffectTop) > 0f ... } return isBeingDragged }
Java
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { ... switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: ... isBeingDragged = EdgeEffectCompat.getDistance(edgeEffectBottom) > 0 || EdgeEffectCompat.getDistance(edgeEffectTop) > 0; ... } }
Im vorherigen Beispiel gibt onInterceptTouchEvent() zurück
true wenn mIsBeingDragged true ist. Es
reicht also aus, das Ereignis zu verarbeiten, bevor das untergeordnete Element die Möglichkeit dazu hat,
es zu verarbeiten.
Overscroll-Effekt freigeben
Es ist wichtig, den Stretch-Effekt vor dem Scrollen freizugeben, damit die Dehnung nicht auf den scrollenden Inhalt angewendet wird. Im folgenden Code beispiel wird diese Best Practice angewendet:
Kotlin
override fun onTouchEvent(ev: MotionEvent): Boolean { val activePointerIndex = ev.actionIndex when (ev.getActionMasked()) { MotionEvent.ACTION_MOVE -> val x = ev.getX(activePointerIndex) val y = ev.getY(activePointerIndex) var deltaY = y - lastMotionY val pullDistance = deltaY / height val displacement = x / width if (deltaY < 0f && EdgeEffectCompat.getDistance(edgeEffectTop) > 0f) { deltaY -= height * EdgeEffectCompat.onPullDistance(edgeEffectTop, pullDistance, displacement); } if (deltaY > 0f && EdgeEffectCompat.getDistance(edgeEffectBottom) > 0f) { deltaY += height * EdgeEffectCompat.onPullDistance(edgeEffectBottom, -pullDistance, 1 - displacement); } ... }
Java
@Override public boolean onTouchEvent(MotionEvent ev) { final int actionMasked = ev.getActionMasked(); switch (actionMasked) { case MotionEvent.ACTION_MOVE: final float x = ev.getX(activePointerIndex); final float y = ev.getY(activePointerIndex); float deltaY = y - lastMotionY; float pullDistance = deltaY / getHeight(); float displacement = x / getWidth(); if (deltaY < 0 && EdgeEffectCompat.getDistance(edgeEffectTop) > 0) { deltaY -= getHeight() * EdgeEffectCompat.onPullDistance(edgeEffectTop, pullDistance, displacement); } if (deltaY > 0 && EdgeEffectCompat.getDistance(edgeEffectBottom) > 0) { deltaY += getHeight() * EdgeEffectCompat.onPullDistance(edgeEffectBottom, -pullDistance, 1 - displacement); } ...
Wenn der Nutzer zieht, verarbeiten Sie den EdgeEffect Ziehabstand
bevor Sie das Touch-Ereignis an einen verschachtelten Scrolling-Container übergeben oder den
Scrollvorgang ziehen. Im vorherigen Codebeispiel gibt getDistance() einen
positiven Wert zurück, wenn ein Kanteneffekt angezeigt wird und durch
Bewegung freigegeben werden kann. Wenn der Stretch-Effekt durch das Touch-Ereignis freigegeben wird, wird er zuerst von der
EdgeEffect verarbeitet, damit er vollständig freigegeben wird, bevor andere Effekte,
wie das verschachtelte Scrollen, angezeigt werden. Mit getDistance()
können Sie herausfinden, wie viel Ziehabstand erforderlich ist, um den aktuellen Effekt freizugeben.
Im Gegensatz zu onPull(), gibt onPullDistance() den
verarbeiteten Betrag des übergebenen Deltas zurück. Ab Android 12 ändert sich der Stretch-Effekt nicht, wenn
onPull() oder onPullDistance() negative
deltaDistance Werte übergeben werden, wenn getDistance() ist
0, the stretch effect doesn't change. Unter Android 11
und niedriger können mit onPull() negative Werte für den Gesamtabstand
Leuchteffekte anzeigen.
Overscroll deaktivieren
Sie können Overscroll in Ihrer Layoutdatei oder programmatisch deaktivieren.
Wenn Sie Overscroll in Ihrer Layoutdatei deaktivieren möchten, legen Sie android:overScrollMode wie
im folgenden Beispiel fest:
<MyCustomView android:overScrollMode="never"> ... </MyCustomView>
Wenn Sie Overscroll programmatisch deaktivieren möchten, verwenden Sie Code wie den folgenden:
Kotlin
customView.overScrollMode = View.OVER_SCROLL_NEVER
Java
customView.setOverScrollMode(View.OVER_SCROLL_NEVER);
Zusätzliche Ressourcen
Weitere Informationen finden Sie in den folgenden verwandten Ressourcen:
- Übersicht über Eingabeereignisse
- Sensoren – Übersicht
- Benutzerdefinierte Ansicht interaktiv gestalten