Intereting Posts
Где я могу поместить папку «assets» в Android Studio? Не удается установить пример проекта ApiDemos на Android-эмуляторе Android Не удалось создать экземпляр активности: не нашел класс на пути Измерение кампании с помощью собственного BroadcastReceiver Skype начинает набор номера и разворачивается через 2 секунды – Android Каков наилучший способ обновления базовых данных адаптера? Android обнаруживает или блокирует плавающие / накладывающиеся приложения ProgressDialog: как предотвратить утечку окна В чем разница между «новыми A ()» и «A.newInstance ()»? Ресурсы $ NotFoundException: ресурс не является Drawable (цвет или путь)? Как удалить строку правого поля в Android Studio (Intellij)? Пользовательская служба загрузки Android – предоставление строки уведомления о ходе выполнения для каждого файла Установить границы карты с различными дополнениями Android GCM: тот же идентификатор отправителя для большего количества приложений Программный доступ к темам / стилям / attrs в android

Как имитировать поведение 3-х фазовых карт Google Maps?

Задний план

Мне присваивается пользовательский интерфейс, который ведет себя аналогично тому, как Google Maps показывает нижний лист для найденного результата.

Он имеет три разных этапа:

  1. Нижнее содержание. Верхняя область по-прежнему осязаема и не будет прокручивать что-либо внизу
  2. Полноэкранный контент, а верхняя область имеет большой заголовок.
  3. Полноэкранный контент, в то время как верхняя область имеет только панель инструментов.

Вот что я говорю на Картах Google:

Введите описание изображения здесь

Проблема

Дело в том, что нижний лист еще не входит в библиотеку дизайна (хотя он был запрошен здесь ).

Не только это, но интерфейс кажется довольно сложным и требует обработки панели инструментов на нескольких этапах.

Что я пробовал

Я нашел хорошую (достаточную) библиотеку для нижнего листа ( здесь ) и добавил контент к образцу фрагмента, чтобы иметь о тех же представлениях, что и на примерах материального дизайна (например, здесь ), чтобы иметь 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:

Введите описание изображения здесь

Вопрос

Что не так с кодом? Что я могу сделать для достижения требуемого поведения?

Solutions Collecting From Web of "Как имитировать поведение 3-х фазовых карт Google Maps?"

Примечание : прочитайте изменения внизу


Хорошо, я нашел способ сделать это, но мне пришлось изменить код нескольких классов, чтобы нижний лист знал о состоянии appBarLayout (расширенном или нет) и игнорировал прокрутку вверх, если это Не расширен:

BottomSheetLayout.java

Добавленные поля:

 private AppBarLayout mAppBarLayout; private OnOffsetChangedListener mOnOffsetChangedListener; private int mAppBarLayoutOffset; 

Init () – добавлено:

  mOnOffsetChangedListener = new OnOffsetChangedListener() { @Override public void onOffsetChanged(final AppBarLayout appBarLayout, final int verticalOffset) { mAppBarLayoutOffset = verticalOffset; } }; 

Добавлена ​​функция для установки appBarLayout:

 public void setAppBarLayout(final AppBarLayout appBarLayout) { if (mAppBarLayout == appBarLayout) return; if (mAppBarLayout != null) mAppBarLayout.removeOnOffsetChangedListener(mOnOffsetChangedListener); mAppBarLayout = appBarLayout; mAppBarLayout.addOnOffsetChangedListener(mOnOffsetChangedListener); } 

OnDetachedFromWindow () – добавлено:

  if (mAppBarLayout != null) mAppBarLayout.removeOnOffsetChangedListener(mOnOffsetChangedListener); 

OnTouchEvent () – добавлено:

  ... if (bottomSheetOwnsTouch) { if (state == State.EXPANDED && scrollingDown && mAppBarLayout != null && mAppBarLayoutOffset != 0) { event.offsetLocation(0, sheetTranslation - getHeight()); getSheetView().dispatchTouchEvent(event); return true; } ... 

Это были основные изменения. Теперь для того, что их устанавливает:

MyFragment.java

OnCreateView () – добавлено:

  mBottomSheetLayout.setAppBarLayout((AppBarLayout) view.findViewById(R.id.appbar)); 

Я также добавил эту функцию:

  public void setBottomSheetLayout(final BottomSheetLayout bottomSheetLayout) { mBottomSheetLayout = bottomSheetLayout; } 

Теперь это то, как активность сообщает фрагменту о appBarLayout:

  final MyFragment myFragment = new MyFragment(); myFragment.setBottomSheetLayout(bottomSheetLayout); myFragment.show(getSupportFragmentManager(), R.id.bottomsheet); 

Проект теперь доступен на GitHub:

https://github.com/AndroidDeveloperLB/ThreePhasesBottomSheet

Надеюсь, у него нет никаких ошибок.


У решения есть ошибки, к сожалению, поэтому я не буду отмечать этот ответ как правильный:

  1. Он работает только на Android 6 и выше. У других есть странное поведение, показывающее, что нижний лист расширяется на крошечную долю времени, каждый раз при его показе.
  2. Изменения ориентации не сохраняют состояние прокрутки вообще, поэтому я отключил его.
  3. Редкий вопрос о возможности прокрутки содержимого нижнего листа, пока он все еще рухнул (внизу)
  4. Если раньше клавиатура была показана, нижний лист мог бы быть полноэкранным, когда вы пытались заглянуть.

Если кто-то может помочь с этим, пожалуйста.


Для проблемы №1 я попытался добавить исправление, установив видимость на INVISIBLE, когда нижний лист еще не заглянул, но он не всегда работает, особенно если отображается клавиатура.


Для проблемы №1 я нашел, как ее исправить, просто обернув (в «fragment_my.xml») координаторLayout с любым видом, который вы хотите использовать (я использовал FrameLayout), а также поместил полноразмерный вид в Это (я просто положил «Вид»), как таковой:

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!--This full sized view, together with the FrameLayout above, are used to handle some weird UI issues on pre-Android-6 --> <View android:layout_width="match_parent" android:layout_height="match_parent"/> <...CollapsingToolbarLayout ... 

Вероятно, это смутило нижний лист, когда у меня был координаторLayout. Я обновил проект, но все же, если есть способ получить более приятное решение, я хотел бы узнать об этом.


В последние месяцы Google опубликовал свой собственный класс bottomSheet, но, как я обнаружил, у него много проблем, поэтому я даже не могу его попробовать.

БОЛЬШОЕ ОБНОВЛЕНИЕ

Потому что было около 4 или 5 вопросов по одной и той же теме, но с РАЗЛИЧНЫМИ требованиями, и я пытался ответить на все из них, но не вежливый администратор удалил / закрыл их, заставив меня создать билет для каждого из них и изменить их на Избегайте «copy paste». Я дам вам ссылку на полный ответ, где вы найдете все объяснения о том, как получить полное поведение, такое как Google Maps.


Отвечая на ваш вопрос

Как имитировать поведение 3-х фазовых карт Google Maps?

В библиотеке поддержки 23.x.x + вы можете сделать это, изменив значение BottomSheetBehavior по умолчанию, добавив еще один stat со следующими шагами:

  1. Создайте класс Java и расширьте его из CoordinatorLayout.Behavior<V>
  2. Скопируйте код вставки из файла BottomSheetBehavior умолчанию в новый.
  3. Измените метод clampViewPositionVertical следующим кодом:
  4. Добавить новое состояние:

     public static final int STATE_ANCHOR_POINT = X; 
  5. Измените следующие методы: onLayoutChild , onStopNestedScroll , BottomSheetBehavior<V> from(V view) и setState (необязательно)

Я собираюсь добавить эти измененные методы и ссылку на пример проекта .

И вот как это выглядит:
[ CustomBottomSheetBehavior ]

Вы попробовали это? http://android-developers.blogspot.in/2016/02/android-support-library-232.html?m=1 Здесь говорится, что мы можем просто указать поведение макета нижнего листа.

ОБНОВИТЬ:

В основном,

Присоединив BottomSheetBehavior к дочернему объекту View of CoordinatorLayout (то есть добавив app: layout_behavior = "android.support.design.widget.BottomSheetBehavior"), вы автоматически получите соответствующее сенсорное обнаружение для перехода между пятью состояниями:

 STATE_COLLAPSED: this collapsed state is the default and shows just a portion of the layout along the bottom. The height can be controlled with the app:behavior_peekHeight attribute (defaults to 0) STATE_DRAGGING: the intermediate state while the user is directly dragging the bottom sheet up or down STATE_SETTLING: that brief time between when the View is released and settling into its final position STATE_EXPANDED: the fully expanded state of the bottom sheet, where either the whole bottom sheet is visible (if its height is less than the containing CoordinatorLayout) or the entire CoordinatorLayout is filled STATE_HIDDEN: disabled by default (and enabled with the app:behavior_hideable attribute), enabling this allows users to swipe down on the bottom sheet to completely hide the bottom sheet Keep in mind that scrolling containers in your bottom sheet must support nested scrolling (for example, NestedScrollView, RecyclerView, or ListView/ScrollView on API 21+). 

Если вы хотите получать обратные вызовы изменений состояния, вы можете добавить BottomSheetCallback:

 // The View with the BottomSheetBehavior View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet); BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); behavior.setBottomSheetCallback(new BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { // React to state change } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { // React to dragging events } }); 

В то время как BottomSheetBehavior фиксирует стойкий нижний регистр, этот выпуск также предоставляет BottomSheetDialog и BottomSheetDialogFragment для заполнения случая использования модальных нижних листов. Просто замените AppCompatDialog или AppCompatDialogFragment своими эквивалентами нижнего листа, чтобы ваш диалог был оформлен как нижний лист.