片段中的 ActionBar 和 Toolbar
ActionBar and Toolbar in a fragment
我正在努力让我的片段子视图在显示时考虑 ActionBar/Toolbar。
我遵循了 here 的示例,该示例将布局很好地划分为 activity 布局和包含 AppBar/Toolbar 标签的片段,在我的例子中,还有浮动操作按钮(很棒)。我重构了我已经工作的代码,使 AppBar/Toolbar 和 fab 在 activity 布局上,只有片段处于单独的布局中。但是在片段上包含 AppBar/Toolbar 和 fab 的方法使我能够拥有一个干净的 activity 可以容纳任何片段,有或没有 AppBar/Toolbar 或 fab(或任何其他 UI 个元素)。下面是我的基本布局设置。我遇到的问题是我的 RecyclerView 被 Appbar/Toolbar 遮住了。
activity_main.axml
<?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:id="@+id/main_coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- Actual content of the screen -->
<FrameLayout
android:id="@+id/main_content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
</android.support.design.widget.CoordinatorLayout>
fragment_list.axml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/list_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<include
layout="@layout/include_toolbar_actionbar" />
<MvvmCross.Droid.Support.V4.MvxSwipeRefreshLayout
android:id="@+id/listsRefresher"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:MvxBind="Refreshing IsLoading; RefreshCommand ReloadCommand">
<MvvmCross.Droid.Support.V7.RecyclerView.MvxRecyclerView
android:id="@+id/listsRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:MvxItemTemplate="@layout/item_list"
app:MvxBind="ItemsSource Lists; ItemClick ShowListItemsCommand" />
</MvvmCross.Droid.Support.V4.MvxSwipeRefreshLayout>
<include
layout="@layout/include_floatingactionbutton" />
</FrameLayout>
include_toolbar_actionbar.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/main_tool_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.ToolBar"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
include_floatingactionbutton.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.FloatingActionButton
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="@dimen/margin_medium"
android:src="@drawable/ic_add_white_24dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_anchor="@id/main_content_frame"
app:layout_anchorGravity="bottom|right|end" />
MainActivity.cs
namespace List.Mobile.Droid.Activities
{
[Activity(
Label = "@string/applicationName",
Icon = "@drawable/ic_icon",
Theme = "@style/AppTheme.Default",
LaunchMode = LaunchMode.SingleTop,
ScreenOrientation = ScreenOrientation.Portrait,
Name = "list.droid.mobile.activities.MainActivity")]
public class MainActivity : MvxAppCompatActivity<MainViewModel>
{
...
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
ViewModel.ShowLists();
}
}
}
ListsFragment.cs
namespace List.Mobile.Droid.Views
{
[MvxFragmentPresentation(typeof(MainViewModel), Resource.Id.main_content_frame, true)]
[Register("list.mobile.droid.views.ListsFragment")]
public class ListsFragment : BaseFragment<ListsViewModel>, ActionMode.ICallback
{
...
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
var swipeToRefresh = FragmentView.FindViewById<MvxSwipeRefreshLayout>(Resource.Id.refresher);
if (AppBar != null)
AppBar.OffsetChanged += (sender, args) => swipeToRefresh.Enabled = args.VerticalOffset == 0;
var listsRecyclerView = FragmentView.FindViewById<MvxRecyclerView>(Resource.Id.listsRecyclerView);
...
return FragmentView;
}
}
}
BaseFragment.cs
namespace List.Mobile.Droid.Views
{
public abstract class BaseFragment<T> : MvxFragment<T> where T : MvxViewModel
{
protected abstract int FragmentResourceId { get; }
protected View FragmentView { get; set; }
protected AppBarLayout AppBar { get; set; }
protected FloatingActionButton Fab { get; set; }
protected Toolbar Toolbar { get; set; }
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = base.OnCreateView(inflater, container, savedInstanceState);
FragmentView = this.BindingInflate(FragmentResourceId, null);
AppBar = FragmentView.FindViewById<AppBarLayout>(Resource.Id.main_app_bar);
Fab = FragmentView.FindViewById<FloatingActionButton>(Resource.Id.fab);
Toolbar = FragmentView.FindViewById<Toolbar>(Resource.Id.main_tool_bar);
AppCompatActivity parentActivity = ((AppCompatActivity)Activity);
parentActivity.SetSupportActionBar(Toolbar);
parentActivity.SupportActionBar.SetDisplayHomeAsUpEnabled(false);
parentActivity.SupportActionBar.SetHomeButtonEnabled(false);
return view;
}
}
}
如果你结合activity+fragment+include的布局结构你会看到这样的东西:
CoordinatorLayout
--FrameLayout -> id=main_content_frame
----FrameLayout -> id=list_frame
------AppBarLayout
--------Toolbar
------SwipeRefresh
--------Recycler
------Fab
这意味着,您在 FrameLayout 中有工具栏和 swipe/recycler,而这个位于另一个之上正是预期的行为。
要解决这个问题,您应该将 AppBar+Swipe+Fab 作为 CoordinatorLayout
的子项(这是正确处理 Toolbar/Fab/Scrolling 内容之间交互的布局。因此请更改您的 activity只是 FrameLayout
并将片段重新排序为:
CoordinatorLayout
--AppBarLayout
----Toolbar
--SwipeRefresh
----RecyclerView
--Fab
并且不要忘记将 app:layout_behavior="@string/appbar_scrolling_view_behavior"
添加到 SwipeRefreshLayout
,以便协调器正确定位它。
我正在努力让我的片段子视图在显示时考虑 ActionBar/Toolbar。
我遵循了 here 的示例,该示例将布局很好地划分为 activity 布局和包含 AppBar/Toolbar 标签的片段,在我的例子中,还有浮动操作按钮(很棒)。我重构了我已经工作的代码,使 AppBar/Toolbar 和 fab 在 activity 布局上,只有片段处于单独的布局中。但是在片段上包含 AppBar/Toolbar 和 fab 的方法使我能够拥有一个干净的 activity 可以容纳任何片段,有或没有 AppBar/Toolbar 或 fab(或任何其他 UI 个元素)。下面是我的基本布局设置。我遇到的问题是我的 RecyclerView 被 Appbar/Toolbar 遮住了。
activity_main.axml
<?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:id="@+id/main_coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- Actual content of the screen -->
<FrameLayout
android:id="@+id/main_content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
</android.support.design.widget.CoordinatorLayout>
fragment_list.axml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/list_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<include
layout="@layout/include_toolbar_actionbar" />
<MvvmCross.Droid.Support.V4.MvxSwipeRefreshLayout
android:id="@+id/listsRefresher"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:MvxBind="Refreshing IsLoading; RefreshCommand ReloadCommand">
<MvvmCross.Droid.Support.V7.RecyclerView.MvxRecyclerView
android:id="@+id/listsRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:MvxItemTemplate="@layout/item_list"
app:MvxBind="ItemsSource Lists; ItemClick ShowListItemsCommand" />
</MvvmCross.Droid.Support.V4.MvxSwipeRefreshLayout>
<include
layout="@layout/include_floatingactionbutton" />
</FrameLayout>
include_toolbar_actionbar.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/main_tool_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.ToolBar"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
include_floatingactionbutton.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.FloatingActionButton
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="@dimen/margin_medium"
android:src="@drawable/ic_add_white_24dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_anchor="@id/main_content_frame"
app:layout_anchorGravity="bottom|right|end" />
MainActivity.cs
namespace List.Mobile.Droid.Activities
{
[Activity(
Label = "@string/applicationName",
Icon = "@drawable/ic_icon",
Theme = "@style/AppTheme.Default",
LaunchMode = LaunchMode.SingleTop,
ScreenOrientation = ScreenOrientation.Portrait,
Name = "list.droid.mobile.activities.MainActivity")]
public class MainActivity : MvxAppCompatActivity<MainViewModel>
{
...
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
ViewModel.ShowLists();
}
}
}
ListsFragment.cs
namespace List.Mobile.Droid.Views
{
[MvxFragmentPresentation(typeof(MainViewModel), Resource.Id.main_content_frame, true)]
[Register("list.mobile.droid.views.ListsFragment")]
public class ListsFragment : BaseFragment<ListsViewModel>, ActionMode.ICallback
{
...
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
var swipeToRefresh = FragmentView.FindViewById<MvxSwipeRefreshLayout>(Resource.Id.refresher);
if (AppBar != null)
AppBar.OffsetChanged += (sender, args) => swipeToRefresh.Enabled = args.VerticalOffset == 0;
var listsRecyclerView = FragmentView.FindViewById<MvxRecyclerView>(Resource.Id.listsRecyclerView);
...
return FragmentView;
}
}
}
BaseFragment.cs
namespace List.Mobile.Droid.Views
{
public abstract class BaseFragment<T> : MvxFragment<T> where T : MvxViewModel
{
protected abstract int FragmentResourceId { get; }
protected View FragmentView { get; set; }
protected AppBarLayout AppBar { get; set; }
protected FloatingActionButton Fab { get; set; }
protected Toolbar Toolbar { get; set; }
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = base.OnCreateView(inflater, container, savedInstanceState);
FragmentView = this.BindingInflate(FragmentResourceId, null);
AppBar = FragmentView.FindViewById<AppBarLayout>(Resource.Id.main_app_bar);
Fab = FragmentView.FindViewById<FloatingActionButton>(Resource.Id.fab);
Toolbar = FragmentView.FindViewById<Toolbar>(Resource.Id.main_tool_bar);
AppCompatActivity parentActivity = ((AppCompatActivity)Activity);
parentActivity.SetSupportActionBar(Toolbar);
parentActivity.SupportActionBar.SetDisplayHomeAsUpEnabled(false);
parentActivity.SupportActionBar.SetHomeButtonEnabled(false);
return view;
}
}
}
如果你结合activity+fragment+include的布局结构你会看到这样的东西:
CoordinatorLayout
--FrameLayout -> id=main_content_frame
----FrameLayout -> id=list_frame
------AppBarLayout
--------Toolbar
------SwipeRefresh
--------Recycler
------Fab
这意味着,您在 FrameLayout 中有工具栏和 swipe/recycler,而这个位于另一个之上正是预期的行为。
要解决这个问题,您应该将 AppBar+Swipe+Fab 作为 CoordinatorLayout
的子项(这是正确处理 Toolbar/Fab/Scrolling 内容之间交互的布局。因此请更改您的 activity只是 FrameLayout
并将片段重新排序为:
CoordinatorLayout
--AppBarLayout
----Toolbar
--SwipeRefresh
----RecyclerView
--Fab
并且不要忘记将 app:layout_behavior="@string/appbar_scrolling_view_behavior"
添加到 SwipeRefreshLayout
,以便协调器正确定位它。