Задний план
Мне поручено создать пользовательский интерфейс, который ведет себя аналогично тому, как Google Maps показывает нижний лист для найденного результата.
Он состоит из трех этапов:
- Нижнее содержимое. Верхняя область по-прежнему доступна для прикосновения, а внизу ничего не прокручивается.
- Полноэкранный контент, а в верхней части - большой заголовок.
- Полноэкранное содержимое, а в верхней части находится только панель инструментов.
Вот о чем я говорю на Google Maps:
Эта проблема
Дело в том, что нижний лист еще не является частью библиотеки дизайна (хотя он был запрошен здесь ).
Более того, пользовательский интерфейс кажется довольно сложным и требует обработки панели инструментов на нескольких этапах.
Что я пробовал
Я нашел хорошую (достаточно) библиотеку для нижнего листа ( здесь ) и добавил контент в образец фрагмента, чтобы иметь примерно те же представления, что и в образцах дизайна материалов (например, здесь ), чтобы иметь CollapsingToolbarLayout, который позаботится фаз 2 + 3.
В приложении, которое я создаю, мне также нужно перемещать значок при прокрутке, но я думаю, что если у меня получится с остальным, это будет легко. Вот код:
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);
}
});
}
}
Почти хорошо работает. Единственная проблема - это переход с №3 обратно на №2:
Вопрос
Что не так с кодом? Что я могу сделать, чтобы добиться требуемого поведения?
CoordinatorLayout
на 2-м экране использовали?Ответы:
Примечание . Прочтите правки внизу
Хорошо, я нашел способ сделать это, но мне пришлось изменить код нескольких классов, чтобы нижний лист знал о состоянии appBarLayout (развернутый или нет) и игнорировал прокрутку вверх, если это не раскрывается:
BottomSheetLayout.java
Добавлены поля:
init () - добавил это:
Добавлена функция для установки appBarLayout:
onDetachedFromWindow () - добавил это:
onTouchEvent () - добавил это:
Это были основные изменения. Теперь о том, что их устанавливает:
MyFragment.java
onCreateView () - добавил это:
Я также добавил эту функцию:
Вот как действие сообщает фрагменту о appBarLayout:
Проект теперь доступен на GitHub:
https://github.com/AndroidDeveloperLB/ThreePhasesBottomSheet
Надеюсь, в нем нет ошибок.
К сожалению, решение содержит ошибки, поэтому я не буду отмечать этот ответ как правильный:
Если кто-то может помочь с этим, пожалуйста.
Для проблемы №1 я попытался добавить исправление, установив для видимости значение НЕВИДИМО, когда нижний лист еще не просматривается, но это не всегда работает, особенно если отображается клавиатура.
Что касается проблемы №1, я нашел, как ее исправить, просто обернув (в "fragment_my.xml") CoordinatorLayout любым представлением, которое вы хотите использовать (я использовал FrameLayout), а также поместил полноразмерное представление в он (я просто поставил "Просмотр") как таковой:
Вероятно, это сбило с толку bottomSheet, когда у меня был CoordinatorLayout в качестве его представления. Я обновил проект, но все же, если есть способ найти более приятное решение, я хотел бы знать об этом.
В последние месяцы Google опубликовал свой собственный класс bottomSheet, но, как я обнаружил, у него много проблем, поэтому я даже не могу его попробовать.
источник
БОЛЬШОЕ ОБНОВЛЕНИЕ
Потому что было около 4 или 5 вопросов по одной и той же теме, НО с РАЗНЫМИ требованиями, и я попытался ответить на все из них, но невежливый администратор удалил / закрыл их, заставив меня создать заявку для каждого и изменить их на Избегайте «копировать и вставлять». Я дам вам ссылку на полный ответ, где вы можете найти все объяснения о том, как добиться полного поведения, такого как Карты Google.
Отвечая на ваш вопрос
С помощью библиотеки поддержки 23.x.x + вы можете сделать это, изменив значение по умолчанию
BottomSheetBehavior
, добавив еще один стат, выполнив следующие действия:CoordinatorLayout.Behavior<V>
BottomSheetBehavior
файла по умолчанию в новый.Измените метод
clampViewPositionVertical
с помощью следующего кода:Добавить новое состояние:
Измените следующие методы:
onLayoutChild
,onStopNestedScroll
,BottomSheetBehavior<V> from(V view)
иsetState
(необязательно)Я собираюсь добавить эти модифицированные методы и ссылку на пример проекта .
А вот как это выглядит:
источник
CoordinatorLayout
дюймаactivity_main.xml
. Думаю, у вас есть хороший опыт работы с макетом координатора, в противном случае взгляните на эту ссылку, которую я нашелВы пробовали это? http://android-developers.blogspot.in/2016/02/android-support-library-232.html?m=1 Здесь говорится, что мы можем просто указать поведение макета нижнего листа.
ОБНОВИТЬ:
В основном ссылка гласит:
Прикрепив BottomSheetBehavior к дочернему View CoordinatorLayout (т.е. добавив app: layout_behavior = "android.support.design.widget.BottomSheetBehavior"), вы автоматически получите соответствующее обнаружение касания для перехода между пятью состояниями:
Если вы хотите получать обратные вызовы изменений состояния, вы можете добавить BottomSheetCallback:
Хотя BottomSheetBehavior фиксирует постоянный регистр нижнего листа, этот выпуск также предоставляет BottomSheetDialog и BottomSheetDialogFragment для заполнения варианта использования модальных нижних листов. Просто замените AppCompatDialog или AppCompatDialogFragment их эквивалентами нижнего листа, чтобы ваш диалог был стилизован как нижний лист.
источник
Мне также пришлось реализовать представление, подобное тому, как Google Maps показывает нижний лист для найденного результата.
Вот как выглядит мой:
Сначала я определил нижний лист с заголовком и прокручиваемым содержимым, но layout_height, похоже, не обернул содержимое ни заголовок, ни прокручиваемое содержимое, несмотря на указание
wrap_content
.Эта проблема ушла , когда я
LinearLayout
вместо того , чтобыConstraintLayout
дляCoordinatorLayout
расположения детского «s (и для своих детей).activity_main.xml
MainActivity.java
Приложение / build.gradle
источник