tło
Zostałem przydzielony do stworzenia interfejsu użytkownika, który zachowuje się podobnie do tego, jak Mapy Google pokazują dolny arkusz znalezionego wyniku.
Ma trzy różne fazy:
- Dolna treść. Górny obszar jest nadal dotykalny i nie przewija niczego na dole
- Treść pełnoekranowa, podczas gdy górny obszar ma duży nagłówek.
- Treść pełnoekranowa, podczas gdy w górnym obszarze znajduje się tylko pasek narzędzi.
Oto, o czym mówię w Mapach Google:
Problem
Chodzi o to, że dolny arkusz nie jest jeszcze częścią biblioteki projektów (chociaż został o to poproszony tutaj ).
Co więcej, interfejs użytkownika wydaje się dość złożony i wymaga obsługi paska narzędzi w wielu fazach.
Co próbowałem
Znalazłem dobrą (wystarczającą) bibliotekę dla dolnego arkusza ( tutaj ) i dodałem zawartość do jej próbki fragmentu, aby mieć mniej więcej takie same widoki, jak pokazano na przykładach Material Design (jak tutaj ), aby mieć CollapsingToolbarLayout, który zajmie się faz 2 + 3.
W aplikacji, którą tworzę, muszę również przesuwać ikonę podczas przewijania, ale myślę, że jeśli uda mi się z resztą, to powinno być łatwe. Oto kod:
fragment_my.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="@dimen/detail_backdrop_height"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<ImageView
android:id="@+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="24dp">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_margin">
<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Info"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/card_margin"
android:layout_marginLeft="@dimen/card_margin"
android:layout_marginRight="@dimen/card_margin">
<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Friends"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/card_margin"
android:layout_marginLeft="@dimen/card_margin"
android:layout_marginRight="@dimen/card_margin">
<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Related"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
android:clickable="true"
android:src="@android:drawable/ic_menu_send"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>
MyFragment.java
public class MyFragment extends BottomSheetFragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_my, container, false);
view.setMinimumHeight(getResources().getDisplayMetrics().heightPixels);
CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) view.findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle("AAA");
final Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
final AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavUtils.navigateUpFromSameTask(getActivity());
}
});
final ImageView imageView = (ImageView) view.findViewById(R.id.backdrop);
Glide.with(this).load(R.drawable.cheese_1).centerCrop().into(imageView);
return view;
}
}
BottomSheetFragmentActivity.java
public final class BottomSheetFragmentActivity extends AppCompatActivity {
protected BottomSheetLayout bottomSheetLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bottom_sheet_fragment);
bottomSheetLayout = (BottomSheetLayout) findViewById(R.id.bottomsheet);
findViewById(R.id.bottomsheet_fragment_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new MyFragment().show(getSupportFragmentManager(), R.id.bottomsheet);
}
});
bottomSheetLayout.setShouldDimContentView(false);
bottomSheetLayout.setPeekOnDismiss(true);
bottomSheetLayout.setPeekSheetTranslation(200);
bottomSheetLayout.setInterceptContentTouch(false);
bottomSheetLayout.setDefaultViewTransformer(new BaseViewTransformer() {
@Override
public void transformView(final float translation, final float maxTranslation, final float peekedTranslation, final BottomSheetLayout parent, final View view) {
Log.d("AppLog", "translation:" + translation + " maxTranslation:" + maxTranslation + " peekedTranslation:" + peekedTranslation);
}
});
}
}
Prawie działa. Jedynym problemem jest przejście z # 3 z powrotem do # 2:
Pytanie
Co jest nie tak z kodem? Co mogę zrobić, aby osiągnąć wymagane zachowanie?
źródło
CoordinatorLayout
na drugim ekranie?Odpowiedzi:
Uwaga : przeczytaj zmiany na dole
OK, znalazłem sposób, aby to zrobić, ale musiałem zmienić kod wielu klas, aby dolny arkusz wiedział o stanie appBarLayout (rozwinięty lub nie) i zignorować przewijanie w górę, jeśli jest nierozwinięty:
BottomSheetLayout.java
Dodane pola:
init () - dodał:
Dodano funkcję ustawiania appBarLayout:
onDetachedFromWindow () - dodano:
onTouchEvent () - dodano to:
To były główne zmiany. Teraz co je ustawia:
MyFragment.java
onCreateView () - dodał:
Dodałem również tę funkcję:
W ten sposób aktywność informuje fragment o appBarLayout:
Projekt jest już dostępny na GitHub:
https://github.com/AndroidDeveloperLB/ThreePhasesBottomSheet
Mam nadzieję, że nie ma żadnych błędów.
Niestety rozwiązanie zawiera błędy, więc nie oznaczę tej odpowiedzi jako poprawnej:
Jeśli ktoś może w tym pomóc, zrób to.
W przypadku problemu nr 1 próbowałem dodać poprawkę, ustawiając widoczność na INVISIBLE, gdy dolny arkusz nie jest jeszcze podglądany, ale nie zawsze działa, zwłaszcza jeśli jest wyświetlana klawiatura.
W przypadku problemu nr 1 znalazłem, jak to naprawić, po prostu opakowując (w „fragment_my.xml”) układ CoordinatorLayout dowolnym widokiem, którego chcesz użyć (użyłem FrameLayout), a także umieszczając pełnowymiarowy widok w it (po prostu wstawiłem „Widok”), tak jak:
Prawdopodobnie pomylił dolny arkusz, gdy miałem widok CoordinatorLayout. Zaktualizowałem projekt, ale jeśli istnieje sposób na ładniejsze rozwiązanie, to chciałbym się o tym dowiedzieć.
W ostatnich miesiącach Google opublikowało własną klasę bottomSheet, ale jak odkryłem, ma wiele problemów, więc nie mogę jej nawet wypróbować.
źródło
DUŻA AKTUALIZACJA
Ponieważ było 4 lub 5 pytań na ten sam temat, ALE z RÓŻNYMI wymaganiami i próbowałem odpowiedzieć na wszystkie, ale niepoprawny administrator je usunął / zamknął, zmuszając mnie do utworzenia biletu dla każdego i zmiany na unikaj „kopiuj wklej”. Podam link do pełnej odpowiedzi, w której można znaleźć wszystkie wyjaśnienia dotyczące pełnego zachowania, takiego jak Mapy Google.
Odpowiadając na Twoje pytanie
Dzięki obsłudze biblioteki 23.x.x + możesz to zrobić modyfikując domyślne
BottomSheetBehavior
, dodając jeszcze jedną statystykę, wykonując następujące kroki:CoordinatorLayout.Behavior<V>
BottomSheetBehavior
pliku do nowego.Zmodyfikuj metodę
clampViewPositionVertical
za pomocą następującego kodu:Dodaj nowy stan:
Modyfikować następujące metody:
onLayoutChild
,onStopNestedScroll
,BottomSheetBehavior<V> from(V view)
isetState
(opcjonalnie)Zamierzam dodać te zmodyfikowane metody i link do przykładowego projektu .
A oto jak to wygląda:
źródło
CoordinatorLayout
inactivity_main.xml
. Myślę, że masz dobre doświadczenie z układem koordynatora, w przeciwnym razie spójrz na ten link, który znalazłemPróbowałeś tego? http://android-developers.blogspot.in/2016/02/android-support-library-232.html?m=1 Tutaj jest napisane, że możemy po prostu określić zachowanie układu dolnego arkusza.
AKTUALIZACJA:
Zasadniczo łącze stwierdza:
Dołączając BottomSheetBehavior do podrzędnego widoku CoordinatorLayout (tj. Dodając app: layout_behavior = "android.support.design.widget.BottomSheetBehavior") automatycznie uzyskasz odpowiednie wykrywanie dotyku umożliwiające przejście między pięcioma stanami:
Jeśli chcesz otrzymywać wywołania zwrotne zmian stanu, możesz dodać BottomSheetCallback:
Podczas gdy BottomSheetBehavior przechwytuje trwały przypadek dolnego arkusza, ta wersja udostępnia również BottomSheetDialog i BottomSheetDialogFragment do wypełniania modalnego przypadku użycia dolnych arkuszy. Po prostu zastąp AppCompatDialog lub AppCompatDialogFragment ich odpowiednikami w dolnym arkuszu, aby Twoje okno dialogowe było stylizowane na dolny arkusz.
źródło
Musiałem również zaimplementować widok podobny do tego, jak Mapy Google pokazują dolny arkusz znalezionego wyniku.
Oto jak wygląda mój:
Na początku zdefiniowałem dolny arkusz z nagłówkiem i przewijaną treścią, ale layout_height nie wydawał się zawijać zawartości ani nagłówka, ani przewijalnej zawartości pomimo określenia
wrap_content
.Problem odszedł kiedy użyłem
LinearLayout
zamiastConstraintLayout
naCoordinatorLayout
„s układ dzieci (i dla swoich dzieci).activity_main.xml
MainActivity.java
app / build.gradle
źródło