web-dev-qa-db-ja.com

Android-ビューページャーの異なるフラグメント間を移動するときに非表示にするFAB

本当に簡単なことをしようとしています。

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が下にスワイプしても依然として見えるようになる理由を誰かが知っていますか?

12
Simon

これはアプリに実装したいものにはなりませんでしたが、wordpress =アプリ。

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>
7
Simon

ねえ、あなたとまったく同じ問題がありました。

私に役立つ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」のようなフラグを追加する必要はもうありません。このメソッドでは、viewPagerMainActivityで静的に設定する必要がありますが、カスタム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

フィードのコンテンツはすべて中国語ですが、コードはすべて英語です。

4
Anthonyeef

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 も確認してください。

1
Juni

アクティビティに静的ブール値を作成し(下記の_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();
    }
}
}
_
1
kphil

次のタブにスワイプすると、プログラムで実行できます。

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

そして、スワイプして戻るときに、表示をView.VISIBLEに設定します。

1
adao7000

間違った角度からアプローチしているようです...

たとえば、あるタブではFABに新しいアイテムを追加できますが、次のタブではアイテムを追加できません。

ホスティングFragment/Fragmentではなく、FABを最初のページのActivityに配置します。これにより、最初のページフラグメントとともに自動的に非表示になります-一緒にアニメーション化することもできます。他のページやタブとはまったく関係がないので、それも属します。

ホスティングFragment/Activityでクリックイベントを本当に処理する必要がある場合は、最初のページフラグメントをホスティングFragment/Activityにコールバックします。そのクリックが発生します。

0
Nicklas