web-dev-qa-db-de.com

Verwenden von BottomSheetBehavior mit einem inneren CoordinatorLayout

Mit der Design-Support-Bibliothek v. 23.2 Wurde BottomSheetBehavior eingeführt, mit der untergeordnete Elemente eines Koordinators als unterste Blätter fungieren können (Ansichten können vom unteren Bildschirmrand aus gezogen werden).

Was ich tun möchte, ist, als untere Blattansicht die folgende Ansicht zu haben (der typische Koordinator + einklappende Elemente):

<CoordinatorLayout
    app:layout_behavior=“@string/bottom_sheet_behavior”>

   <AppBarLayout>
        <CollapsingToolbarLayout>
           <ImageView />
        </CollapsingToolbarLayout>
    </AppBarLayout>

    <NestedScrollView>
        <LinearLayout>
            < Content ... />
        </LinearLayout>
    </NestedScrollView>

</CoordinatorLayout>

Leider sollten unterste Blattansichten einen verschachtelten Bildlauf implementieren, oder sie erhalten keine Bildlaufereignisse. Wenn Sie es mit einer Hauptaktivität versuchen und diese Ansicht dann als unteres Blatt laden, werden Sie feststellen, dass Bildlaufereignisse nur auf dem "Blatt" Papier mit einem merkwürdigen Verhalten ablaufen, wie Sie sehen können, wenn Sie weiterlesen.

Ich bin mir ziemlich sicher, dass dies durch Unterklassen von CoordinatorLayout oder noch besser durch Unterklassen von BottomSheetBehavior gehandhabt werden kann. Hast du einen Tipp?

Einige Gedanken

  • requestDisallowInterceptTouchEvent() sollte verwendet werden, um unter bestimmten Bedingungen Ereignisse vom übergeordneten Element zu stehlen:

    • wenn der Versatz AppBarLayout> 0 ist
    • wenn der AppBarLayout -Offset == 0 ist, aber wir rollen nach oben (denken Sie eine Sekunde darüber nach und Sie werden sehen)
  • die erste Bedingung erhalten Sie, indem Sie in der inneren App-Leiste ein OnOffsetChanged setzen.

  • die zweite erfordert eine Ereignisbehandlung, zum Beispiel:

    switch (MotionEventCompat.getActionMasked(event)) {
        case MotionEvent.ACTION_DOWN:
            startY = event.getY();
            lastY = startY;
            userIsScrollingUp = false;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            userIsScrollingUp = false;
            break;
        case MotionEvent.ACTION_MOVE:
            lastY = event.getY();
            float yDeltaTotal = startY - lastY;
            if (yDeltaTotal > touchSlop) { // Moving the finger up.
                userIsScrollingUp = true;
            }
            break;
    }
    

Probleme

Unnötig zu erwähnen, dass ich das momentan nicht schaffen kann. Ich kann die Ereignisse nicht erfassen, wenn die Bedingungen erfüllt sind, und in anderen Fällen nicht erfassen. Im Bild unten sehen Sie, was mit einem Standard-CoordinatorLayout passiert:

  • Das Blatt wird geschlossen, wenn Sie in der App-Leiste nach unten scrollen, nicht jedoch, wenn Sie im verschachtelten Inhalt nach unten scrollen. Es scheint, dass verschachtelte Bildlaufereignisse nicht an das Verhalten des Koordinators weitergegeben werden.

  • Es gibt auch ein Problem mit der inneren App-Leiste: Der verschachtelte Bildlaufinhalt folgt nicht der App-Leiste, wenn sie reduziert wird.

enter image description here

Ich habe ein Beispielprojekt auf Github eingerichtet, das diese Probleme zeigt.

Nur um klar zu sein, ist gewünschtes Verhalten:

  • Korrektes Verhalten von Appbars/Scroll-Ansichten im Arbeitsblatt;

  • Wenn ein Blatt erweitert wird, kann es beim Scrollen nach unten minimiert werden, aber nur, wenn die innere App-Leiste ebenfalls vollständig erweitert ist . Im Moment wird es ohne Rücksicht auf den Status der App-Leiste ausgeblendet, und nur, wenn Sie die App-Leiste ziehen.

  • Wenn das Blatt reduziert ist, wird es durch Scrollen mit den Gesten nach oben erweitert (ohne Auswirkung auf die innere App-Leiste).

Ein Beispiel aus der Kontakte-App (die wahrscheinlich kein BottomSheetBehavior verwendet, aber das ist, was ich will):

enter image description here

54
natario

Ich habe endlich meine Implementierung freigegeben. Finde es auf Github oder direkt von jcenter:

compile 'com.otaliastudios:bottomsheetcoordinatorlayout:1.0.0’

Sie müssen nur BottomSheetCoordinatorLayout als Stammansicht für Ihr unteres Blatt verwenden. Es wird automatisch ein Arbeitsverhalten für sich aufblasen, machen Sie sich also keine Sorgen.

Ich verwende dies seit langer Zeit und es sollte keine Scroll-Probleme geben, unterstützt das Ziehen auf der ABL usw.

5
natario

Ich habe gerade die Art und Weise befolgt, wie Sie die obige Frage gestellt haben, und eine Lösung gefunden, die möglicherweise näher erläutert werden muss. Bitte folgen Sie Ihrem Beispielcode und integrieren Sie den zusätzlichen Teil in Ihre XML-Datei, damit er sich wie BottomSheeet verhält

<CoordinatorLayout>
   <AppBarLayout>
        <Toolbar
            app:layout_collapseMode="pin">
        </Toolbar>
    </AppBarLayout>
    <NestedScrollView
         app:layout_behavior=“@string/bottom_sheet_behavior” >
        <include layout="@layout/items" />
    </NestedScrollView>

    <!-- Bottom Sheet -->

     <BottomSheetCoordinatorLayout>
        <AppBarLayout
            <CollapsingToolbarLayout">
             <ImageView />
                <Toolbar />
            </CollapsingToolbarLayout>
        </AppBarLayout>
        <NestedScrollView">
            <include layout="@layout/items" />
        </NestedScrollView>
    </BottomSheetCoordinatorLayout>
</CoordinatorLayout>

Hinweis: Die für mich funktionierende Lösung wurde bereits im letzten Kommentar Ihrer Frage erläutert

Bessere Erklärung: https://github.com/laenger/BottomSheetCoordinatorLayout

1

Versuchen Sie, NestedScrollView nicht mit LinearLayout zu verwenden, da dies auch in meiner App Probleme verursacht hat. Verwenden Sie stattdessen nur LinearLayout.

Versuchen Sie Folgendes:

<CoordinatorLayout
app:layout_behavior=“@string/bottom_sheet_behavior”>

<AppBarLayout>
    <CollapsingToolbarLayout>
       <ImageView />
    </CollapsingToolbarLayout>
</AppBarLayout>

<LinearLayout>
     <!--don't forget to addd this line-->
     app:layout_behavior="@string/appbar_scrolling_view_behavior">

        < Content ... />
</LinearLayout>
0
rahul

ich habe Laengers erstes Github-Testprojekt in Bezug auf dieses Problem verfolgt, und ich freue mich, Ihnen eine Lösung für einige seiner Probleme mitzuteilen, da ich dieses Verhalten auch in meiner App brauchte.

dies ist eine Lösung für sein Problem: ❌ Die Symbolleiste wird manchmal zu früh ausgeblendet

um dies zu verhindern, müssen Sie Ihren benutzerdefinierten AppBarLayout.Behavior erstellen, da der AppBarLayout.behavior die Bildlaufbewegung erhält, wenn Sie nach oben scrollen, während Sie noch ziehen. Wir müssen erkennen, ob es sich in STATE_DRAGGING befindet, und einfach zurückkehren, um zu vermeiden, dass die Symbolleiste vorzeitig ausgeblendet oder ausgeblendet wird.

public class CustomAppBarLayoutBehavior extends AppBarLayout.Behavior {

    private CoordinatorLayoutBottomSheetBehavior behavior;

    public CustomAppBarLayoutBehavior() {
    }

    public CustomAppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
        behavior = CoordinatorLayoutBottomSheetBehavior.from(parent);
        return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
        if(behavior.getState() == CoordinatorLayoutBottomSheetBehavior.STATE_DRAGGING){
            return;
        }else {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        }
    }

    @Override
    public void setDragCallback(@Nullable DragCallback callback) {
        super.setDragCallback(callback);
    }
}

dies könnte ein guter Anfang sein, um die anderen Probleme zu lösen:

❌ Die Symbolleiste kann nicht durch Ziehen reduziert werden

❌ Hauptkoordinator-Layout verbraucht etwas Scroll

eigentlich bin ich keine gute UI/Animation-Person, aber harte Arbeit zahlt sich manchmal aus, den Code zu verstehen und die richtige Callback/Override-Funktion für die Implementierung zu finden.

setze dies als Verhalten auf appbarlayout

<Android.support.design.widget.AppBarLayout
    Android:id="@+id/bottom_sheet_appbar"
    style="@style/BottomSheetAppBarStyle"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    app:layout_behavior="your.package.CustomAppBarLayoutBehavior">
0
user3115201

Wenn das erste Kind nestedscroll ist, treten einige andere Probleme auf. Diese Lösung ist behoben, mein Problem, ich hoffe, auch Ihr Problem zu beheben.

<CoordinatorLayout
    app:layout_behavior=“@string/bottom_sheet_behavior”>

   <AppBarLayout>
        <CollapsingToolbarLayout>
           <ImageView />
        </CollapsingToolbarLayout>
    </AppBarLayout>
</LinearLayout>
    <NestedScrollView>
        <LinearLayout>
            < Content ... />
        </LinearLayout>
    </NestedScrollView>
</LinearLayout>
</CoordinatorLayout>
0
Eren Utku