Unter Android wird das Scrollen in der Regel mit der Klasse ScrollView
durchgeführt. Nesten Sie jedes Standardlayout, das über die Grenzen seines Containers hinausgeht, in einem ScrollView
, um eine vom Framework verwaltete scrollbare Ansicht bereitzustellen. Die Implementierung eines benutzerdefinierten Scroller ist nur bei speziellen
Szenarien durchführen. In diesem Dokument wird beschrieben, wie ein Scrolleffekt als Reaktion darauf angezeigt wird.
um Touch-Gesten mit Scrollen zu berühren.
Deine App kann Folgendes verwenden:
Scrollers: Scroller
oder
OverScroller
– bis
Sie sammeln die Daten, die zum Erstellen einer Scroll-Animation als Reaktion auf eine Berührung erforderlich sind.
. Sie sind ähnlich, aber OverScroller
enthält auch Methoden zum
Hinweis für Nutzer, wenn sie die Inhaltsränder nach einem Schwenken oder Wischen erreichen
Touch-Geste.
- Ab Android 12 (API-Level 31) dehnen sich die visuellen Elemente aus auf ein Drag-Event zurück.
- Unter Android 11 (API-Level 30) und niedriger wird nach einer Wisch- oder Werg-Geste zum Rand ein „Glühen“ angezeigt.
Im Beispiel InteractiveChart
in diesem Dokument wird die Methode
EdgeEffect
, um diese Overscroll-Effekte anzuzeigen.
Mit einem Scroller können Sie das Scrollen im Zeitverlauf animieren. Dabei werden die standardmäßigen Scroll-Physikeigenschaften der Plattform wie Reibung, Geschwindigkeit und andere Eigenschaften verwendet. Der Scroller selbst zeichnet nichts. Scroller erfassen Scrollen im Laufe der Zeit für Sie, aber sie werden diese Positionen nicht automatisch auf Ihre Ansicht anpassen. Sie müssen neue Koordinaten mit einer Geschwindigkeit abrufen und anwenden, die die Scrollanimation flüssig erscheinen lässt.
Terminologie für das Scrollen
Scrollen kann in Android unterschiedliche Bedeutungen haben. Kontext.
Beim Scrollen wird der Darstellungsbereich in der Regel verschoben, d. h.
das „Fenster“ des Inhalts, den Sie sich ansehen. Wenn das Scrollen sowohl in der x- als auch in der y-Achse erfolgt, wird dies als Schwenken bezeichnet. Die
In diesem Dokument sind zwei Beispiele für InteractiveChart
-Beispiel-Apps zu sehen:
verschiedene Arten von Scrollen, Ziehen und Ziehen:
- Ziehen: Diese Art des Scrollens wird verwendet, wenn ein Nutzer seinen Finger über den Touchscreen zieht. Sie können das Ziehen implementieren, indem Sie
wird überschrieben
onScroll()
inGestureDetector.OnGestureListener
. Weitere Informationen zum Ziehen finden Sie unter Ziehen und skalieren. - Flingen:Dies ist die Art von Scrollen, bei der ein Nutzer
und hebt den Finger schnell an. Nachdem der Nutzer den Finger vom Display genommen hat, sollten Sie den Darstellungsbereich in der Regel weiter bewegen, aber die Geschwindigkeit so weit verringern, bis er stehen bleibt. Sie können Wischaktionen implementieren, indem Sie
onFling()
inGestureDetector.OnGestureListener
überschreiben und ein Scrollobjekt verwenden. - Schwenken: Scrollen Sie gleichzeitig auf dem x- und Eine y-Achse wird als Schwenken bezeichnet.
Scroller-Objekte werden häufig in Verbindung mit einer Wischgeste verwendet. Sie können sie jedoch in jedem Kontext verwenden, in dem die Benutzeroberfläche in Reaktion auf ein Touch-Ereignis scrollen soll. So können Sie zum Beispiel
onTouchEvent()
um Touch-Ereignisse direkt zu verarbeiten und einen Scrolleffekt oder einen
"An Seite ausrichten" als Reaktion auf diese Touch-Ereignisse.
Komponenten mit integrierten Scrolling-Implementierungen
Die folgenden Android-Komponenten enthalten eine integrierte Unterstützung für das Scrollen und Überscrollen:
GridView
HorizontalScrollView
ListView
NestedScrollView
RecyclerView
ScrollView
ViewPager
ViewPager2
Wenn Ihre App das Scrollen und Overscrolling innerhalb einer anderen Komponente führen Sie die folgenden Schritte aus:
- Benutzerdefinierte Touch-basierte Scrollfunktion implementieren
- Wenn Sie Geräte mit Android 12 und höher unterstützen möchten, die Stretch-Overscroll-Funktion .
Benutzerdefinierte Implementierung für berührungsbasiertes Scrollen erstellen
In diesem Abschnitt wird beschrieben, wie Sie Ihren eigenen Scroller erstellen, wenn Ihre App einen Komponente, die nicht integrierte Unterstützung für und Overscrolling.
Das folgende Snippet stammt aus der
InteractiveChart
Beispiel. Dabei wird ein
GestureDetector
und überschreibt die
GestureDetector.SimpleOnGestureListener
onFling()
-Methode. OverScroller
wird verwendet, um
Fingergeste. Wenn der Nutzer nach der Wischgeste den Rand des Inhalts erreicht, zeigt der Container an, dass er am Ende des Inhalts angelangt ist. Die Anzeige hängt von der Android-Version ab, auf der ein Gerät
ausgeführt:
- Unter Android 12 und höher werden die visuellen Elemente reflektieren können.
- Unter Android 11 und niedriger werden die visuellen Elemente leuchtend hervorgehoben. Effekt.
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()
anruft
postInvalidateOnAnimation()
,
es wird ausgelöst
computeScroll()
um die Werte für x und y zu aktualisieren. Dies geschieht in der Regel, wenn ein untergeordnetes Element der Ansicht ein Scrollen mit einem Scroller-Objekt animiert, wie im vorherigen Beispiel gezeigt.
Bei den meisten Ansichten wird die x- und y-Position des Scroller-Objekts direkt übergeben.
bis
scrollTo()
Die folgende Implementierung von computeScroll()
ändert sich
Ansatz: Es ruft
computeScrollOffset()
um den aktuellen Standort von x und y zu ermitteln. Wenn die Kriterien für die Anzeige eines „Glühens“ am Rand bei Überscrollen erfüllt sind, d. h. das Display ist herangezoomt, x oder y liegt außerhalb des Bereichs und in der App wird bereits ein Überscrollen angezeigt, richtet der Code den Überscroll-Glüheneffekt ein und ruft postInvalidateOnAnimation()
auf, um eine Ungültigmachung der Ansicht auszulösen.
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; } ... }
Dies ist der Abschnitt des Codes, der den tatsächlichen Zoom durchfü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
aus dem vorherigen Snippet. Hier wird die aktuelle Größe der scrollbaren Oberfläche in Pixeln berechnet. Ist beispielsweise der gesamte Diagrammbereich sichtbar, ist dies der aktuelle Bereich
Größe von mContentRect
. Wenn das Diagramm in beiden Richtungen um 200 % herangezoomt 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 Scroller finden Sie auf der
Quellcode
ViewPager
. Sie scrollt als Reaktion auf Wischbewegungen und verwendet das Scrollen, um die „Snap-to-Page“-Animation zu implementieren.
Stretch-Overscroll-Effekt implementieren
Ab Android 12 fügt EdgeEffect
den Parameter
folgenden APIs zur Implementierung des Overscroll-Effekts:
getDistance()
onPullDistance()
So sorgen Sie für eine optimale Nutzererfahrung mit dem Stretch-Overscroll:
- Wenn die Dehnungsanimation aktiv ist, wenn der Nutzer den Inhalt berührt, registrieren Sie die Berührung als „Auffangen“. Der Nutzer stoppt die Animation und beginnt noch einmal, die Dehnung zu manipulieren.
- Wenn Nutzende ihren Finger in die entgegengesetzte Richtung der Dehnung bewegen, lassen Sie sie los, bis sie ganz weg ist, und fangen Sie dann an zu scrollen.
- Wenn der Nutzer während eines Streckens wischt, wischen Sie mit dem Finger auf das
EdgeEffect
, um den Streckeneffekt zu verstärken.
Animation erfassen
Wenn ein Nutzer eine aktive Dehnungsanimation sieht, gibt EdgeEffect.getDistance()
den Wert 0
zurück. Diese Bedingung
gibt an, dass die Dehnung durch die Berührungsbewegung beeinflusst werden muss. In den meisten Containern wird die Ausnahme 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()
true
, wenn mIsBeingDragged
gleich true
ist, also
reicht es aus, das Ereignis zu verarbeiten, bevor das Kind die Möglichkeit hat,
konsumieren.
Overscroll-Effekt loslassen
Es ist wichtig, den Dehnungseffekt vor dem Scrollen aufzuheben, damit er nicht auf die gescrollten Inhalte angewendet wird. Im folgenden Codebeispiel 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); } ...
Beim Ziehen durch den Nutzer die Pull-Entfernung von EdgeEffect
nutzen
bevor Sie das Touch-Ereignis an einen verschachtelten scrollbaren Container übergeben oder die
Scrollen. Im vorherigen Codebeispiel gibt getDistance()
den Fehlerwert
positiver Wert, wenn ein Randeffekt angezeigt wird und dieser mit
Bewegung. Wenn das Touch-Ereignis das Dehnen beendet, wird es zuerst von der EdgeEffect
verwendet, sodass es vollständig freigegeben wird, bevor andere Effekte wie verschachteltes Scrollen angezeigt werden. Mit getDistance()
kannst du herausfinden, wie weit du den Auslöser ziehen musst, um den aktuellen Effekt zu aktivieren.
Im Gegensatz zu onPull()
gibt onPullDistance()
den verbrauchten Betrag des übergebenen Deltas zurück. Ab Android 12 werden für onPull()
oder onPullDistance()
keine negativen deltaDistance
-Werte übergeben, wenn getDistance()
= 0
ist. Unter Android 11 und niedriger können mit onPull()
negative Werte für die Gesamtdistanz zu Glühen führen.
Overscroll deaktivieren
Sie können Overscroll in Ihrer Layoutdatei oder programmatisch deaktivieren.
Wenn Sie die Funktion in Ihrer Layoutdatei deaktivieren möchten, legen Sie android:overScrollMode
wie im folgenden Beispiel gezeigt fest:
<MyCustomView android:overScrollMode="never"> ... </MyCustomView>
Zur programmatischen Deaktivierung verwenden Sie Code wie den folgenden:
Kotlin
customView.overScrollMode = View.OVER_SCROLL_NEVER
Java
customView.setOverScrollMode(View.OVER_SCROLL_NEVER);
Weitere Informationen
Weitere Informationen finden Sie unter den folgenden Links: