私はそのような効果を達成する方法を探しています https://material-design.storage.googleapis.com/publish/material_v_4/material_ext_publish/0B6Okdz75tqQsVlhxNGJCNTEzNFU/components-buttons-fab-behavior_04_xhdpi_009.webm
Android.support.v4.view.ViewPagerを使用しています
ヒントや助力に感謝します
最初に、フローティングアクションボタンがViewPagerに固定されたレイアウトが必要です。
<Android.support.design.widget.CoordinatorLayout
Android:id="@+id/main_content"
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="wrap_content"
Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<Android.support.v7.widget.Toolbar
Android:id="@+id/action_bar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
<Android.support.design.widget.TabLayout
Android:id="@+id/tabs"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="@Android:color/white"
app:tabGravity="center"
app:tabIndicatorColor="?attr/colorAccent"
app:tabMode="scrollable"
app:tabSelectedTextColor="?attr/colorAccent"
app:tabTextColor="@Android:color/black" />
</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="@string/appbar_scrolling_view_behavior" />
<Android.support.design.widget.FloatingActionButton
Android:id="@+id/fab"
app:layout_anchor="@id/viewpager"
app:layout_anchorGravity="bottom|right|end"
Android:layout_width="56dp"
Android:layout_height="56dp"
Android:src="@drawable/ic_add_white"
app:borderWidth="@dimen/fab_border_width"
app:fabSize="normal" />
</Android.support.design.widget.CoordinatorLayout>
FABをViewPagerに固定したので(注:viewpagerのタブであるフラグメントでこれを試しましたが、適切に動作していないようです)、次のようにViewPagerにOnPageChangeListenerを追加します。
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
switch (position) {
case INDEX_OF_TAB_WITH_FAB:
fab.show();
break;
default:
fab.hide();
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
タブを切り替える際の「ポップ」と「シュリンク」のアニメーションは、サポートライブラリの新しいバージョンで自動的に処理されます。
別の解決策があります。私にとって他の問題は、ViewPagerを含むアクティビティにFABの制御を与えると、コーディングが難しくなることです。
FABアイコンを簡単に変更し、特定のリスナーを設定するには、フラグメントによるFABの多くのコントロールが必要です。
大まかに、手順は次のとおりです。
public void shareFab(FloatingActionButton sharedFab)
;のようなFABを渡すことができるメソッドを作成します。このメソッド内で、各フラグメントはFABアイコンを設定し、必要なリスナーを追加しますViewPager.OnPageChangeListener
アニメーションをトリガーし、shareFab
メソッドを呼び出すViewPagerのリスナー。そのため、フラグメントが表示されるたびに、包含アクティビティは表示されたフラグメントにFABの参照を提供します。次に、フラグメントは、ニーズに合わせてFABをリセット/リサイクルします。
以下に例を示します。
表示するフラグメント
public void Fragment1 extends Fragment {
private FloatingActionButton mSharedFab;
@Override
public void onDestroy() {
super.onDestroy();
mSharedFab = null; // To avoid keeping/leaking the reference of the FAB
}
public void shareFab(FloatingActionButton fab) {
if (fab == null) { // When the FAB is shared to another Fragment
if (mSharedFab != null) {
mSharedFab.setOnClickListener(null);
}
mSharedFab = null;
}
else {
mSharedFab = fab;
mSharedFab.setImageResource(R.drawable.ic_search);
mSharedFab.setOnClickListener((fabView) -> {
// Your code
});
}
}
}
コンテナアクティビティ
public class ActivityMain extends AppCompatActivity {
FloatingActionButton mSharedFab;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSharedFab = (FloatingActionButton) findViewById(R.id.shared_fab);
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
Fragment1 fragment1 = new Fragment1();
Fragment2 fragment2 = new Fragment2();
adapter.addFragment(fragment1, "Fragment1");
adapter.addFragment(fragment2, "Fragment2");
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(adapter);
fragment1.shareFab(mSharedFab); // To init the FAB
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
@Override
public void onPageSelected(int position) { }
@Override
public void onPageScrollStateChanged(int state) {
switch (state) {
case ViewPager.SCROLL_STATE_DRAGGING:
mSharedFab.hide(); // Hide animation
break;
case ViewPager.SCROLL_STATE_IDLE:
switch (viewPager.getCurrentItem()) {
case 0:
fragment2.shareFab(null); // Remove FAB from fragment
fragment1.shareFab(mSharedFab); // Share FAB to new displayed fragment
break;
case 1:
default:
fragment1.shareFab(null); // Remove FAB from fragment
fragment2.shareFab(mSharedFab); // Share FAB to new displayed fragment
break;
}
mSharedFab.show(); // Show animation
break;
}
}
});
}
}
...およびメインアクティビティの古典的なレイアウト
<?xml version="1.0" encoding="utf-8"?>
<Android.support.design.widget.CoordinatorLayout
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:fitsSystemWindows="true">
<Android.support.design.widget.AppBarLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:theme="@style/AppTheme.AppBarOverlay">
<Android.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<Android.support.design.widget.TabLayout
Android:id="@+id/tabs"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill"/>
</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="@string/appbar_scrolling_view_behavior" />
<Android.support.design.widget.FloatingActionButton
Android:id="@+id/shared_fab"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="bottom|end"
Android:layout_margin="@dimen/fab_margin" />
</Android.support.design.widget.CoordinatorLayout>
長所は次のとおりです。
短所は次のとおりです。
かくれんぼの良いアニメーションには、これを使用してください:
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
switch (state){
case ViewPager.SCROLL_STATE_IDLE:
fab.show();
break;
case ViewPager.SCROLL_STATE_DRAGGING:
case ViewPager.SCROLL_STATE_SETTLING:
fab.hide();
break;
}
}
});
私が発見した解決策は次のとおりです。
ViewPager内に表示されるフラグメントは、インターフェイス(私の場合はFloatingActionButtonFragment
)を実装します。このインターフェイスでは、フラグメントにhandleFABClick(View)
メソッドが必要です。
私のViewPager変更リスナーは次のようになります:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
switch (state) {
case ViewPager.SCROLL_STATE_SETTLING:
displayFloatingActionButtonIfNeeded(viewPager.getCurrentItem());
break;
case ViewPager.SCROLL_STATE_IDLE:
displayFloatingActionButtonIfNeeded(viewPager.getCurrentItem());
break;
default:
mFloatingActionButton.hide();
}
}
});
private void displayFloatingActionButtonIfNeeded(int position) {
if (mFragmentStatePagerAdapter.getItem(position) instanceof FloatingActionButtonFragment) {
final FloatingActionButtonFragment floatingActionButtonFragment = (FloatingActionButtonFragment) mFragmentStatePagerAdapter.getItem(position);
mFloatingActionButton.show();
mFloatingActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
floatingActionButtonFragment.handleFABClick(v);
}
});
}
}
これにより、ユーザーがビューを変更しているときにFABが「非表示」になりますが、ビューステートがアイドル(解決済み)または解決中の場合にshowメソッドをトリガーしますアイドル)。
私の問題では、最初のタブにフローティングアクションボタンを表示したくありませんでした。これを達成するために、私は追加しました
Android:visibility="invisible"
フローティングアクションバーで。
<Android.support.design.widget.FloatingActionButton
Android:id="@+id/fab"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="end|bottom"
Android:layout_margin="@dimen/fab_margin"
Android:visibility="invisible"
app:srcCompat="@Android:drawable/ic_input_add" />
そして、@ chantellが示唆するように、アクティビティにViewpagerListnerを追加しました
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
switch (position) {
case 0:
addFloatingActionBt.hide();
break;
default:
addFloatingActionBt.show();
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
私は最近、私が満足しているはるかに優れたソリューションを見つけました。 FABのhideメソッドには、パラメーターを設定することもできます。リスナーは、ボタンが非表示になったときにトリガーされます(showメソッドにもこれがあります)。唯一の欠点は、viewpagerとtablayoutの変更を手動で実装する必要があることです。
@Override
public void onPageSelected(int position) {
onToolbarTitleChanged(adapter.getPageTitle(position).toString());
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(final TabLayout.Tab tab) {
fab.hide(new FloatingActionButton.OnVisibilityChangedListener() { // Hide FAB
@Override
public void onHidden(FloatingActionButton fab) {
fab.show(); // After FAB is hidden show it again
}
});
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
特定のタブでのみFABを表示する場合は、onTabSelectedメソッドを次のように変更できます。
@Override
public void onTabSelected(TabLayout.Tab tab) {
if (tab.getPosition() == 2) {
createButton.hide();
}
viewPager.setCurrentItem(tab.getPosition());
}