Bild nach oben schieben mit Official Support Library 23.x.+ bottomSheet wie Google Maps

Lesezeit: 13 Minuten

Benutzer-Avatar
MiguelHincapieC

Aktualisieren

Ich möchte das gleiche Verhalten erreichen, das Google Maps hat mit Support Library 23.x.+ und ohne JEDE dritte Bibliothek

HINWEIS: Dies ist keine doppelte Frage, weil:

  1. Ich möchte Behaviors, Support Library und ohne JEDE Bibliothek von Drittanbietern verwenden (ich habe es im Titel der Frage und in der obigen Beschreibung hinzugefügt).
  2. ich wollte ALLE Verhaltensweisen die Sie im nächsten GIF sehen, die anderen Fragen fragen nach ein oder zwei Verhaltensweisen und verwenden sie trotzdem, um sie zu erreichen.

    wie Sie in diesem GIF sehen können

Ich habe bereits das offizielle BottomSheet, das funktioniert (sogar innerhalb eines Registerkarten- und Ansichtspagers).

Was macht mich verrückt Wie erreicht man das Bildverhalten, das vom BottomSheet kommt, wenn man mit dem offiziellen BottomSheet nach oben rutscht?.

Ich habe versucht, Anker wie FAB ohne Erfolg zu verwenden.
Ich habe etwas über die Verwendung eines Scroll-Listeners gelesen, aber Leute sagten, es sei nicht reibungslos und schneller wie Google Maps.

Mein XML (ich glaube nicht, dass es helfen wird, aber trotzdem):

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.MasterActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay"
            app:layout_scrollFlags="scroll|enterAlways|snap">

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                style="?android:attr/borderlessButtonStyle"
                android:text="Departure"
                android:layout_gravity="center"
                android:id="@+id/buttonToolBar"
                />


        </android.support.v7.widget.Toolbar>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabBackground="@android:color/white"
            app:tabTextColor="@color/colorAccent"
            app:tabSelectedTextColor="@color/colorAccent"/>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
    
    
    <android.support.v4.widget.NestedScrollView
        android:id="@+id/asdf"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:behavior_peekHeight="100dp"
        android:fitsSystemWindows="true"
            app:layout_behavior="android.support.design.widget.BottomSheetBehavior">

        <LinearLayout
            android:id="@+id/qwert"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:paddingBottom="16dp"
            android:background="@android:color/white"
            android:padding="15dp">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="BOOTOMSHEET TITLE"
                    android:textAppearance="@style/TextAppearance.AppCompat.Title" />

            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Button1"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="text 2"
                android:layout_margin="10dp"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="text 3"
                android:layout_margin="10dp"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="text 4"
                android:layout_margin="10dp"/>


            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="320dp"
                android:background="@color/colorAccent">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:text="Your remaining content here"
                    android:textColor="@android:color/white" />

            </FrameLayout>
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>


    <android.support.design.widget.FloatingActionButton
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        app:layout_anchor="@id/asdf"
        app:layout_anchorGravity="top|right|end"
        android:src="@drawable/abc_ic_search_api_mtrl_alpha_copy"
        android:layout_margin="@dimen/fab_margin"
        android:clickable="true"/>

</android.support.design.widget.CoordinatorLayout>

  • Ich werde nur das erste fragen, was mir in den Sinn kam – haben Sie versucht, es zu verwenden? android:animateLayoutChanges="true" ? Wenn das Sinn macht.

    – AL.

    20. Mai 2016 um 2:13 Uhr

  • Nö, habe ich nicht probiert. Morgen werde ich mir ansehen, was du gesagt hast, und ich werde dir ein Feedback geben.

    – MiguelHincapieC

    20. Mai 2016 um 3:35 Uhr

  • @McAwesomville, es scheint, als sollten Sie es in der Liste verwenden, aber ich habe keine Ahnung (übrigens niemand), ob sie es mit dem Collapsing- und Coordinator-Layout erreichen oder ob sie das verwendet haben, was Sie vorschlagen. Das einzige, was ich herausgefunden habe, ist, dass es kein einzelnes Bild ist, sondern ein AppBarLayout mit Koordinator und Bild darin.

    – MiguelHincapieC

    22. Mai 2016 um 0:36 Uhr

  • haha, ich habe mich über dasselbe gewundert (der Bild-Slide-up-Teil – ich hatte Bottomsheet + Coordinatorlayout mit CollapsingToolbarLayout, das einige Parallaxen verursacht, aber auf andere Weise als bei Google Maps) – dann habe ich Ihren Code auf Github gefunden, der funktioniert, und diese Frage

    – glücklich

    14. November 2016 um 9:31 Uhr

Benutzer-Avatar
MiguelHincapieC

Wenn Sie es mit Support Library 23.4.0.+ erreichen möchten, werde ich Ihnen sagen, wie ich es bekommen habe und wie es funktioniert.

Soweit ich sehen kann, hat diese Aktivität/Fragment die folgenden Verhaltensweisen:

  1. 2 Symbolleisten mit Animationen, die auf die Bewegungen des unteren Blatts reagieren.
  2. Ein FAB, das sich versteckt, wenn es sich in der Nähe der “modalen Symbolleiste” befindet (die erscheint, wenn Sie nach oben gleiten).
  3. Ein Hintergrundbild hinter dem unteren Blatt mit einer Art Parallax-Effekt.
  4. Ein Titel (TextView) in der Symbolleiste, der angezeigt wird, wenn das unterste Blatt ihn erreicht.
  5. Die Benachrichtigungsstatusleiste kann ihren Hintergrund transparent oder vollfarbig machen.
  6. Ein benutzerdefiniertes unteres Blattverhalten mit einem „Anker“-Zustand.

Anmerkung 2: Diese Antwort spricht über 6 Dinge, nicht über 1 oder 2 wie bei anderen Fragen. kannst du jetzt den unterschied sehen?

Ok, jetzt lass uns eins auf Wiedersehen überprüfen:

Symbolleisten

Wenn Sie diese Ansicht in Google Maps öffnen, sehen Sie eine Symbolleiste, in der Sie suchen können. Es ist die einzige, die ich nicht wie Google Maps mache, weil ich es allgemeiner machen wollte. Jedenfalls das ToolBar ist in einem AppBarLayout und es wurde ausgeblendet, wenn Sie mit dem Ziehen des BottomSheet beginnen, und es wird wieder angezeigt, wenn das BottomSheet das erreicht COLLAPSED Zustand.
Um es zu erreichen, benötigen Sie:

  • ein … kreieren Behavior und verlängern Sie es von AppBarLayout.ScrollingViewBehavior
  • überschreiben layoutDependsOn und onDependentViewChanged Methoden. Dabei hören Sie auf Bewegungen von bottomSheet.
  • Erstellen Sie einige Methoden zum Ein- und Ausblenden des AppBarLayout/ToolBar mit Animationen.

So habe ich es für die erste Symbolleiste oder ActionBar gemacht:

@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
    return dependency instanceof NestedScrollView;
}

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
                                      View dependency) {

    if (mChild == null) {
        initValues(child, dependency);
        return false;
    }

    float dVerticalScroll = dependency.getY() - mPreviousY;
    mPreviousY = dependency.getY();

    //going up
    if (dVerticalScroll <= 0 && !hidden) {
        dismissAppBar(child);
        return true;
    }

    return false;
}

private void initValues(final View child, View dependency) {

    mChild = child;
    mInitialY = child.getY();

    BottomSheetBehaviorGoogleMapsLike bottomSheetBehavior = BottomSheetBehaviorGoogleMapsLike.from(dependency);
    bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehaviorGoogleMapsLike.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, @BottomSheetBehaviorGoogleMapsLike.State int newState) {
            if (newState == BottomSheetBehaviorGoogleMapsLike.STATE_COLLAPSED ||
                    newState == BottomSheetBehaviorGoogleMapsLike.STATE_HIDDEN)
                showAppBar(child);
        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {

        }
    });
}

private void dismissAppBar(View child){
    hidden = true;
    AppBarLayout appBarLayout = (AppBarLayout)child;
    mToolbarAnimation = appBarLayout.animate().setDuration(mContext.getResources().getInteger(android.R.integer.config_shortAnimTime));
    mToolbarAnimation.y(-(mChild.getHeight()+25)).start();
}

private void showAppBar(View child) {
    hidden = false;
    AppBarLayout appBarLayout = (AppBarLayout)child;
    mToolbarAnimation = appBarLayout.animate().setDuration(mContext.getResources().getInteger(android.R.integer.config_mediumAnimTime));
    mToolbarAnimation.y(mInitialY).start();
}

die vollständige Datei, wenn Sie es brauchen

Die zweite Symbolleiste oder “modale” Symbolleiste:
Sie müssen einige Methoden überschreiben, aber in dieser müssen Sie sich um mehr Verhalten kümmern:

  • Symbolleiste mit Animationen ein-/ausblenden
  • Farbe/Hintergrund der Statusleiste ändern
  • Anzeigen/Verbergen des BottomSheet-Titels in der Symbolleiste
  • Schließen Sie das bottomSheet oder senden Sie es in einen reduzierten Zustand

Der Code für diesen ist ein wenig umfangreich, also lasse ich es die Verbindung

Das FAB

Dies ist ebenfalls ein benutzerdefiniertes Verhalten, erstreckt sich jedoch von FloatingActionButton.Behavior. Im onDependentViewChanged Sie müssen schauen, wann es den “offSet” oder Punkt erreicht, an dem Sie es verstecken möchten. In meinem Fall möchte ich es ausblenden, wenn es sich in der Nähe der zweiten Symbolleiste befindet, also suche ich im FAB-Elternteil (einem CoordiantorLayout) nach dem AppBarLayout, das die ToolBar enthält, und verwende dann die ToolBar-Position wie OffSet:

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {

    if (offset == 0)
        setOffsetValue(parent);

    if (dependency.getY() <=0)
        return false;

    if (child.getY() <= (offset + child.getHeight()) && child.getVisibility() == View.VISIBLE)
        child.hide();
    else if (child.getY() > offset && child.getVisibility() != View.VISIBLE)
        child.show();

    return false;
}

Vervollständigen Sie den Link zum benutzerdefinierten FAB-Verhalten

Das Bild hinter dem BottomSheet mit Parallax-Effekt:
Wie bei den anderen ist es ein benutzerdefiniertes Verhalten, das einzig “Komplizierte” an diesem ist der kleine Algorithmus, der das Bild am BottomSheet verankert hält und das Zusammenbrechen des Bildes wie beim Standard-Parallaxeneffekt vermeidet:

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
                                      View dependency) {

    if (mYmultiplier == 0) {
        initValues(child, dependency);
        return true;
    }

    float dVerticalScroll = dependency.getY() - mPreviousY;
    mPreviousY = dependency.getY();

    //going up
    if (dVerticalScroll <= 0 && child.getY() <= 0) {
        child.setY(0);
        return true;
    }

    //going down
    if (dVerticalScroll >= 0 && dependency.getY() <= mImageHeight)
        return false;

    child.setY( (int)(child.getY() + (dVerticalScroll * mYmultiplier) ) );

    return true;
}

[complete file for backdrop Image with parallax effect][4]

Nun zum Schluss: Das benutzerdefinierte BottomSheet-Verhalten

Um die 3 Schritte zu erreichen, müssen Sie zuerst verstehen, dass das Standard-BottomSheetBehavior 5 Zustände hat: STATE_DRAGGING, STATE_SETTLING, STATE_EXPANDED, STATE_COLLAPSED, STATE_HIDDENund für das Verhalten von Google Maps müssen Sie einen mittleren Zustand zwischen reduziert und erweitert hinzufügen: STATE_ANCHOR_POINT.
Ich habe versucht, das standardmäßige bottomSheetBehavior ohne Erfolg zu erweitern, also kopiere ich einfach den gesamten Code und ändere, was ich brauche.
Um das zu erreichen, wovon ich spreche, folgen Sie den nächsten Schritten:

  1. Erstellen Sie eine Java-Klasse und erweitern Sie sie von CoordinatorLayout.Behavior<V>

  2. Kopieren Sie den Einfügecode aus dem Standard BottomSheetBehavior Datei zu Ihrer neuen.

  3. Ändern Sie die Methode clampViewPositionVertical mit folgendem Code:

    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
        return constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
    }
    int constrain(int amount, int low, int high) {
        return amount < low ? low : (amount > high ? high : amount);
    }
    
  4. Fügen Sie einen neuen Zustand hinzu

    öffentlich statisch final int STATE_ANCHOR_POINT = X;

  5. Ändern Sie die nächsten Methoden: onLayoutChild, onStopNestedScroll, BottomSheetBehavior<V> from(V view) und setState (Optional)

public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
    // First let the parent lay it out
    if (mState != STATE_DRAGGING && mState != STATE_SETTLING) {
        if (ViewCompat.getFitsSystemWindows(parent) &&
                !ViewCompat.getFitsSystemWindows(child)) {
            ViewCompat.setFitsSystemWindows(child, true);
        }
        parent.onLayoutChild(child, layoutDirection);
    }
    // Offset the bottom sheet
    mParentHeight = parent.getHeight();
    mMinOffset = Math.max(0, mParentHeight - child.getHeight());
    mMaxOffset = Math.max(mParentHeight - mPeekHeight, mMinOffset);

    //if (mState == STATE_EXPANDED) {
    //    ViewCompat.offsetTopAndBottom(child, mMinOffset);
    //} else if (mHideable && mState == STATE_HIDDEN...
    if (mState == STATE_ANCHOR_POINT) {
        ViewCompat.offsetTopAndBottom(child, mAnchorPoint);
    } else if (mState == STATE_EXPANDED) {
        ViewCompat.offsetTopAndBottom(child, mMinOffset);
    } else if (mHideable && mState == STATE_HIDDEN) {
        ViewCompat.offsetTopAndBottom(child, mParentHeight);
    } else if (mState == STATE_COLLAPSED) {
        ViewCompat.offsetTopAndBottom(child, mMaxOffset);
    }
    if (mViewDragHelper == null) {
        mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
    }
    mViewRef = new WeakReference<>(child);
    mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
    return true;
}


public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
    if (child.getTop() == mMinOffset) {
        setStateInternal(STATE_EXPANDED);
        return;
    }
    if (target != mNestedScrollingChildRef.get() || !mNestedScrolled) {
        return;
    }
    int top;
    int targetState;
    if (mLastNestedScrollDy > 0) {
        //top = mMinOffset;
        //targetState = STATE_EXPANDED;
        int currentTop = child.getTop();
        if (currentTop > mAnchorPoint) {
            top = mAnchorPoint;
            targetState = STATE_ANCHOR_POINT;
        }
        else {
            top = mMinOffset;
            targetState = STATE_EXPANDED;
        }
    } else if (mHideable && shouldHide(child, getYVelocity())) {
        top = mParentHeight;
        targetState = STATE_HIDDEN;
    } else if (mLastNestedScrollDy == 0) {
        int currentTop = child.getTop();
        if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) {
            top = mMinOffset;
            targetState = STATE_EXPANDED;
        } else {
            top = mMaxOffset;
            targetState = STATE_COLLAPSED;
        }
    } else {
        //top = mMaxOffset;
        //targetState = STATE_COLLAPSED;
        int currentTop = child.getTop();
        if (currentTop > mAnchorPoint) {
            top = mMaxOffset;
            targetState = STATE_COLLAPSED;
        }
        else {
            top = mAnchorPoint;
            targetState = STATE_ANCHOR_POINT;
        }
    }
    if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
        setStateInternal(STATE_SETTLING);
        ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState));
    } else {
        setStateInternal(targetState);
    }
    mNestedScrolled = false;
}

public final void setState(@State int state) {
    if (state == mState) {
        return;
    }
    if (mViewRef == null) {
        // The view is not laid out yet; modify mState and let onLayoutChild handle it later
        /**
         * New behavior (added: state == STATE_ANCHOR_POINT ||)
         */
        if (state == STATE_COLLAPSED || state == STATE_EXPANDED ||
                state == STATE_ANCHOR_POINT ||
                (mHideable && state == STATE_HIDDEN)) {
            mState = state;
        }
        return;
    }
    V child = mViewRef.get();
    if (child == null) {
        return;
    }
    int top;
    if (state == STATE_COLLAPSED) {
        top = mMaxOffset;
    } else if (state == STATE_ANCHOR_POINT) {
        top = mAnchorPoint;
    } else if (state == STATE_EXPANDED) {
        top = mMinOffset;
    } else if (mHideable && state == STATE_HIDDEN) {
        top = mParentHeight;
    } else {
        throw new IllegalArgumentException("Illegal state argument: " + state);
    }
    setStateInternal(STATE_SETTLING);
    if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
        ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
    }
}


public static <V extends View> BottomSheetBehaviorGoogleMapsLike<V> from(V view) {
    ViewGroup.LayoutParams params = view.getLayoutParams();
    if (!(params instanceof CoordinatorLayout.LayoutParams)) {
        throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
    }
    CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
            .getBehavior();
    if (!(behavior instanceof BottomSheetBehaviorGoogleMapsLike)) {
        throw new IllegalArgumentException(
                "The view is not associated with BottomSheetBehaviorGoogleMapsLike");
    }
    return (BottomSheetBehaviorGoogleMapsLike<V>) behavior;
}

Link zum Lochprojekt in dem Sie alle benutzerdefinierten Verhalten sehen können

Anmerkung 3: Fügen Sie beim nächsten Mal einen Kommentar hinzu, in dem Sie höflich um eine Änderung der Antwort bitten, oder fragen Sie, warum diese Antwort EINIGES Gleiches enthält als andere Antworten von mir zum selben Thema, BEVOR Sie sie schließen oder als doppelt markieren.

Und so sieht es aus
[CustomBottomSheetBehavior]

  • Manchmal bekomme ich eine transparente Benachrichtigungsleiste, und es sieht schrecklich aus. Irgendeine Idee, wie man es repariert? Bildschirmfoto: imgur.com/a/ng311

    – Taha Rushain

    3. Dezember 2016 um 12:49 Uhr

  • Wir arbeiten daran, es zu beheben (ich habe das gleiche Problem). Bleiben Sie dran mit github.

    – MiguelHincapieC

    3. Dezember 2016 um 16:47 Uhr

  • @David Ty für das Melden des defekten Links, ich habe ihn repariert. Sagen Sie mir, wenn Sie noch etwas brauchen.

    – MiguelHincapieC

    28. Dezember 2016 um 18:26 Uhr


  • @TahaRushain Ich habe es behoben, überprüfe es in GitHub: D

    – MiguelHincapieC

    11. Januar 2017 um 20:07 Uhr

  • @AlexBerdnikov Hallo. Google Maps hat zwei Ansichtsmodi, einen, wenn Sie einen Ort ausgewählt haben, und einen anderen, wenn Sie einfach auf eine leere Stelle klicken (diejenige, über die Sie sprechen). Dies kann ausgehend vom Projekt auf GitHub erfolgen, wobei fast alle Verhaltensweisen entfernt werden (Sie finden sie leicht in getrennten Dateien in dieser Link). Der “schwierigste” Teil besteht darin, die STAATEN zu entfernen BottomSheetBehaviorGoogleMapsLike.java

    – MiguelHincapieC

    31. Mai 2017 um 17:09 Uhr

Benutzer-Avatar
Glenford Fernandes

Sie können den Effekt mit einem Koordinator-Layout-Verhalten erzielen. Sie müssen eine CoordinatorLayout.Behaviour-Klasse erweitern und eine Abhängigkeit über eine der Ansichten im Koordinator-Layout schreiben, wobei Ihr Bild, das die Ansicht enthält, als untergeordnetes Element beibehalten wird. Um es einfach zu machen, müssen Sie das benutzerdefinierte geschriebene Verhalten an das Bild anhängen, das die Ansicht enthält. Für Unterstützung beim Schreiben benutzerdefinierter Verhaltensweisen folgen Sie bitte dem Link
Schreiben von benutzerdefinierten Verhaltensweisen

  • Sieht so aus, als ob Sie für den richtigen Weg sind, ich habe nur schnell auf den Link geschaut, morgen werde ich ihn gründlich lesen. Aber wenn Sie die “akzeptierte Antwort” wollen, sollten Sie ein gut erklärtes Beispiel oder einen Codeausschnitt geben oder ergänzen, was ich habe 🙂

    – MiguelHincapieC

    20. Mai 2016 um 3:34 Uhr


  • Der bereitgestellte Link enthält viel mehr und viele Codeschnipsel, die alles im Detail erklären. Schauen Sie es sich an, es ist leicht zu verstehen.

    – Glenford Fernandes

    20. Mai 2016 um 3:45 Uhr

  • Ja, aber wie SO rulez sagte, sollten wir eine vollständige Antwort anstelle eines Links veröffentlichen, da ein Link irgendwann sterben kann.

    – MiguelHincapieC

    20. Mai 2016 um 5:50 Uhr

  • Der obige Link gibt mir einige Hinweise, wie ich erreichen kann, was ich will, aber es ist weit davon entfernt, die Antwort / Anleitung dafür zu sein. Tatsächlich hat heute niemand die Antwort darauf xD

    – MiguelHincapieC

    22. Mai 2016 um 0:28 Uhr

1146050cookie-checkBild nach oben schieben mit Official Support Library 23.x.+ bottomSheet wie Google Maps

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy