本当に簡単なことをしようとしています。
FABをTabLayoutの1つのタブにのみ表示し、別のタブに移動するときに非表示にしたいです。たとえば、1つのタブでは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アプリでは、アプリの最初のページにフローティングアクションボタンが表示されます。これは、ビューページャーの他のページにスワイプすると消えます:
彼らは次のコードを通じてこれを行いました-これは、ビューページャーを保持するアクティビティのコードです。ページがスクロールされるたびにイベントをポストするイベントバスを含むonPageScrolledメソッドの下で、コードの関連部分を確認できます。イベントには、0から1までの整数値であるpositionOffsetと呼ばれる1つの変数のみが含まれます。スクロールしてページが2つのビューページの中間にある場合、positionOffsetは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));
}
}
});
イベントは、次のコードを含むフラグメントで取得されます。このイベントは、ページがスクロールされたときに、positionOffsetによって決定されたページがビューからスクロールされる距離に従って、FABを垂直方向にアニメーション化するtranslationYメソッドを起動します。
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>
ねえ、あなたとまったく同じ問題がありました。
私に役立つ2つの方法を見つけました。
方法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;
}
}
そして、カスタムfabの動作の中に、次のコードを追加します。
if (dyConsunmed > 0 && child.getVisibility() == View.VISIBLE ) {
child.hide();
} else if (dyConsunmed < 0 && child.getVisibility() != View.VISIBLE && MainActivity.fabVisible) {
child.show();
}
このメソッドのポイントは、hide&showメソッドを実装する前に、fabが表示されていることを確認することです。
方法2:
MainActivity
に「fabVisible」のようなフラグを追加する必要はもうありません。このメソッドでは、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();
}
}
このメソッドの重要なポイントは、必要なフラグメントの内側にいるときにのみ表示および非表示メソッドを作成することです(私の場合はフラグメント1なので、currenItem == 0です)。もちろん、2番目のフラグメントのfabを削除するために、viewPagerリスナー内でそれを非表示にする必要があります。
それでも実装について混乱している場合は、GitHubのリポジトリを確認して、コードを試してみてください。アドレスは次のとおりです https://github.com/Anthonyeef/FanfouDaily
フィードのコンテンツはすべて中国語ですが、コードはすべて英語です。
ViewPager.onPageListenerを実装し、onPageSelectedをオーバーライドし、要件に応じてタブの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();
詳細については this も確認してください。
アクティビティに静的ブール値を作成し(下記の_YourActivity.isFABinCurrentTabVisible
_を参照)、現在のタブにfabがあるかどうかに応じて、ViewPagerから変更します。しかし、汚い修正かもしれません...そして、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();
}
}
}
_
次のタブにスワイプすると、プログラムで実行できます。
FloatingActionButton fab = (FloatingActionButton) view.findViewByID(R.id.fab)
fab.setVisibility(View.GONE);
そして、スワイプして戻るときに、表示をView.VISIBLE
に設定します。
間違った角度からアプローチしているようです...
たとえば、あるタブではFABに新しいアイテムを追加できますが、次のタブではアイテムを追加できません。
ホスティングFragment
/Fragment
ではなく、FABを最初のページのActivity
に配置します。これにより、最初のページフラグメントとともに自動的に非表示になります-一緒にアニメーション化することもできます。他のページやタブとはまったく関係がないので、それも属します。
ホスティングFragment
/Activity
でクリックイベントを本当に処理する必要がある場合は、最初のページフラグメントをホスティングFragment
/Activity
にコールバックします。そのクリックが発生します。