Android – FAB, чтобы скрыть при навигации между различными фрагментами в viewpager

Я пытаюсь сделать что-то очень простое.

Я бы хотел, чтобы FAB отображался только на одной вкладке в моей вкладке TabLayout и скрывался при переходе на другую вкладку. Так, например, одна вкладка позволит вам добавлять новые элементы в FAB, но следующая вкладка не позволит вам добавлять элементы.

Я следовал «типовой» схеме дизайна XML:

<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/container" xmlns:tools="http://schemas.android.com/tools" > <android.support.design.widget.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_scrollFlags="scroll|enterAlways"> <LinearLayout android:id="@+id/search_container" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="horizontal"> <EditText android:id="@+id/search_view" android:layout_width="0dp" android:layout_height="?attr/actionBarSize" android:layout_weight="1" android:background="@android:color/transparent" android:gravity="center_vertical" android:hint="Search" android:imeOptions="actionSearch" android:inputType="text" android:maxLines="1" android:paddingLeft="2dp" android:singleLine="true" android:textColor="#ffffff" android:textColorHint="#b3ffffff" /> <ImageView android:id="@+id/search_clear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:paddingLeft="16dp" android:paddingRight="16dp" android:src="@drawable/ic_action_cancel" /> </LinearLayout> </android.support.v7.widget.Toolbar> <android.support.design.widget.TabLayout android:id="@+id/sliding_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" app:tabMode="scrollable" /> </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="com.example.simon.behaviours.PatchedScrollingViewBehavior"/> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" app:borderWidth="0dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_action_new" android:layout_margin="16dp" android:layout_gravity="bottom|right" app:layout_anchor="@+id/viewPager" app:layout_anchorGravity="bottom|right|end" app:layout_behavior="com.example.simon.behaviours.ScrollingFABBehavior" android:visibility="gone" app:fabSize="normal"> </android.support.design.widget.FloatingActionButton> </android.support.design.widget.CoordinatorLayout> 

Я использовал следующее поведение для FAB. Это приводит к любым подъемам, чтобы FAB исчезал и возвращался обратно на экран вниз:

 public class ScrollingFABBehavior extends FloatingActionButton.Behavior { private int toolbarHeight; public ScrollingFABBehavior(Context context, AttributeSet attrs) { super(); this.toolbarHeight = getToolbarHeight(context); } @Override public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton fab, View dependency) { return super.layoutDependsOn(parent, fab, dependency) || (dependency instanceof AppBarLayout); } @Override public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton fab, View dependency) { boolean returnValue = super.onDependentViewChanged(parent, fab, dependency); if (dependency instanceof AppBarLayout) { CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams(); int fabBottomMargin = lp.bottomMargin; int distanceToScroll = fab.getHeight() + fabBottomMargin; float ratio = (float)dependency.getY()/(float)toolbarHeight; fab.setTranslationY(-distanceToScroll * ratio); } return returnValue; } public static int getToolbarHeight(Context context) { final TypedArray styledAttributes = context.getTheme().obtainStyledAttributes( new int[]{R.attr.actionBarSize}); int toolbarHeight = (int) styledAttributes.getDimension(0, 0); styledAttributes.recycle(); return toolbarHeight; } } 

Я добавил viewpager addOnPageChangeListener:

 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (position == 0) { FloatingActionButton floatingActionButton = (FloatingActionButton) findViewById(R.id.fab); floatingActionButton.setVisibility(View.VISIBLE); } else { FloatingActionButton floatingActionButton = (FloatingActionButton) findViewById(R.id.fab); floatingActionButton.setVisibility(View.GONE); } } @Override public void onPageScrollStateChanged(int state) { } }); 

Я хочу, чтобы FAB появлялся на первой странице и исчезал на всех других страницах.

Код работает, но когда я прокручиваю страницу на следующей странице, появляется FAB, даже если видимость отключена. Я думаю, что это имеет какое-то отношение к поведению, установленному для FAB. Кто-нибудь знает, почему FAB по-прежнему становится видимым при прокрутке вниз, если видимость должна исчезнуть?

Это не стало тем, что я хочу реализовать в своем приложении, но в конце концов мне удалось найти ответ, с некоторой помощью, просмотрев, как они реализовали одно и то же в приложении WordPress.

В приложении wordpress мы видим кнопку с плавающей кнопкой на первой странице приложения, которая исчезает, если вы нажимаете на любую из других страниц на панели просмотра:

WordPress

Они сделали это через следующий код – это код для Activity, который содержит viewpager. Вы можете увидеть соответствующую часть кода в методе onPageScrolled, который содержит eventbus, который отправляет событие каждый раз, когда прокручивается страница. Событие содержит только одну переменную с именем positionOffset, которая представляет собой целочисленное значение от 0 до 1. Если вы прокручиваете и страница находится на полпути между двумя диспетчерами, позицияOffset равна 0,5, вы получаете идею:

WPMainActivity.java

 mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int position) { AppPrefs.setMainTabIndex(position); switch (position) { case WPMainTabAdapter.TAB_NOTIFS: new UpdateLastSeenTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; } trackLastVisibleTab(position); } @Override public void onPageScrollStateChanged(int state) { // noop } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { // fire event if the "My Site" page is being scrolled so the fragment can // animate its fab to match if (position == WPMainTabAdapter.TAB_MY_SITE) { EventBus.getDefault().post(new MainViewPagerScrolled(positionOffset)); } } }); 

Событие выбирается в фрагменте, который содержит следующий код. Событие запустит метод перевода, который анимирует FAB по вертикали, когда страница прокручивается в зависимости от того, как далеко прокручивается страница вне поля зрения, как определено позициейOffset:

MySiteFragment

 /* * animate the fab as the users scrolls the "My Site" page in the main activity's ViewPager */ @SuppressWarnings("unused") public void onEventMainThread(CoreEvents.MainViewPagerScrolled event) { mFabView.setTranslationY(mFabTargetYTranslation * event.mXOffset); } 

Наконец, макет в файле my_site_fragment.xml показывает вам, что FAB фактически помещается в фрагменты xml вместо активности xml.

 <!-- this coordinator is only here due to https://code.google.com/p/android/issues/detail?id=175330 --> <android.support.design.widget.CoordinatorLayout android:id="@+id/coordinator" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.FloatingActionButton android:id="@+id/fab_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|bottom" android:layout_marginBottom="@dimen/fab_margin" android:layout_marginRight="@dimen/fab_margin" android:src="@drawable/gridicon_create_light" app:borderWidth="0dp" app:rippleColor="@color/fab_pressed" /> </android.support.design.widget.CoordinatorLayout> 

Эй, у меня была такая же проблема, как и вы.

Я нашел два метода, которые работали на меня.

Способ 1:

Добавьте статический флаг в свой MainActivity: public static boolean fabVisible; ,

Я заметил, что у вас есть слушатель, чтобы ваш viewPager обнаружил текущую страницу фрагмента, поэтому вы можете добавить это:

  public void onPageSelected(int position) { switch (position) { case 0: fabVisible = true; mFloatingActionButton.show(); break; default: fabVisible = false; mFloatingActionButton.hide(); break; } } 

И внутри вашего пользовательского поведения, добавьте следующий код:

  if (dyConsunmed > 0 && child.getVisibility() == View.VISIBLE ) { child.hide(); } else if (dyConsunmed < 0 && child.getVisibility() != View.VISIBLE && MainActivity.fabVisible) { child.show(); } 

Точка этого метода заключается в том, чтобы убедиться, что fab должен быть виден до того, как вы реализуете метод hide & show.

Способ 2:

Вам больше не нужно добавлять флаг «fabVisible» в свой MainActivity . Хотя этот метод требует, чтобы вы установили viewPager как статический в свой MainActivity , потому что нам нужно иметь доступ к нему в нашем пользовательском классе поведения fab.

В классе ScrollAwareFABBehavior добавьте следующий код:

  if (MainActivity.viewPager.getCurrentItem() == 0) { if (dyConsunmed > 0 && child.getVisibility() == View.VISIBLE ) { child.hide(); } else if (dyConsunmed < 0 && child.getVisibility() != View.VISIBLE) { child.show(); } } 

Ключевым моментом этого метода является только создание метода show и hide, когда вы находитесь внутри нужного фрагмента (в моем случае это фрагмент один, поэтому currenItem == 0). Конечно, чтобы удалить Fab во втором фрагменте, вам все равно нужно спрятать его в своем слушателе viewPager.

Если вы все еще чувствуете смущение в отношении реализации, не стесняйтесь проверять мой репозиторий на GitHub и играть с кодом. Адрес: https://github.com/Anthonyeef/FanfouDaily

Хотя содержание фидов на китайском языке, код написан на английском языке.

Вы можете сделать это программно, когда вы перейдете к следующей вкладке.

 FloatingActionButton fab = (FloatingActionButton) view.findViewByID(R.id.fab) fab.setVisibility(View.GONE); 

А затем установите видимость на View.VISIBLE когда вы View.VISIBLE назад.

Создайте статическое логическое значение в вашей активности (см. YourActivity.isFABinCurrentTabVisible ниже) и YourActivity.isFABinCurrentTabVisible его с вашего ViewPager, соответственно, если на текущей вкладке должно быть значение fab. Может быть, грязное исправление, хотя … И подумайте об использовании fab.show() и fab.hide() вместо setVisiblity() . Они выполняют анимацию затухания и затухания.

 public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior { public ScrollAwareFABBehavior(Context context, AttributeSet attrs) { super(); } @Override public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child, final View directTargetChild, final View target, final int nestedScrollAxes) { // Ensure we react to vertical scrolling return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); } @Override public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child, final View target, final int dxConsumed, final int dyConsumed, final int dxUnconsumed, final int dyUnconsumed) { super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) { // User scrolled down and the FAB is currently visible -> hide the FAB child.hide(); } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE && YourActivity.isFABinCurrentTabVisible) { // User scrolled up and the FAB is currently not visible -> show the FAB child.show(); } } } 

Внедрите ViewPager.onPageListener и перейдите наPageSelected и покажите или скройте FAB на вкладках в соответствии с вашими требованиями, приведенными ниже: Код примера:

 @Override public void onPageSelected(int position) { //FAB_PAGE is the index of the page on which you want to show FAB if(position == FAB_PAGE) { fab.setVisibility(View.VISIBLE); } else { fab.setVisibility(View.GONE); } } 

Вы также можете использовать fab.show (); И fab.hide ();

Также проверьте это для получения дополнительной информации.

Похоже, вы приближаетесь к этому с неправильного угла …

Так, например, одна вкладка позволит вам добавлять новые элементы в FAB, но следующая вкладка не позволит вам добавлять элементы.

Поместите FAB в Fragment первой страницы вместо хостинга Fragment / Activity . Таким образом, он автоматически исчезнет вместе с фрагментом первой страницы – он будет даже анимировать рядом с ним. Он также будет там, где он принадлежит, поскольку он совсем не связан с другими страницами / вкладками.

Если вам действительно нужно обработать событие click в вашем Fragment / Activity хостинга, сделайте ваш фрагмент фрагмента страницы обратно на хостинг Fragment / Activity когда этот клик произойдет.

Intereting Posts
Как хранить данные mqtt в автономном режиме и отправлять их в режиме онлайн Пользовательская панель поиска (большой размер, цвет и фон) Выполнение не выполнено для задачи ': app: compileDebugNdk' Практика для разработки проектов Android сразу после проверки SVN в Eclipse Разрешение отказа: startActivity запрашивает запуск как пользователь -2, но вызывает от пользователя 0; Это требует android.permission.INTERACT_ACROSS_USERS_FULL Как реализовать OnClickListener на Android Всплывающее окно Android AutoCompleteTextView, перемещающееся после отображения Как заставить ScrollView с RelativeLayout с несколькими дочерними макетами заполнить экран? Изменение размера android datepicker Proguard ParseException с по умолчанию proguard.cfg на Android Обработка сигналов (декодирование кода Морзе) с помощью приложения Android Выбор номера диалогового окна Android Что происходит с eclipse, adt-plugin и android-sdk? OutOfMemoryError Bitmap в Android Android: Как изменить формат даты DatePicker с MM / dd / yyyy на dd / MM / yyyy?