Xamarin中MainActivity的OnCreate获取Toolbar返回null问题求助
兄弟,我太懂刚接触Xamarin踩坑的感觉了!你遇到的这个FindViewById返回null的问题,核心原因是Xamarin.Forms的界面接管机制:
当你在OnCreate里调用LoadApplication(new App(...))之后,Xamarin.Forms会完全替换掉MainActivity的原生ContentView,把它改成Forms自己的容器视图。你之前通过ToolbarResource = Resource.Layout.Toolbar设置的工具栏,已经被整合到Forms的页面层级里了,不在Activity的原生视图树里,所以直接用FindViewById肯定找不到。
下面给你两种靠谱的解决方案,按需选择:
方法一:优先用Xamarin.Forms原生API操作工具栏
如果你的需求只是自定义工具栏样式、标题或者添加按钮,强烈推荐用Forms的跨平台API来实现,这样不用碰原生代码,还能保证多平台一致:
- 要替换标题栏内容:在ContentPage里用
NavigationPage.SetTitleView(this, 你的自定义视图) - 要修改全局样式:在App.xaml里定义
NavigationPage的样式,比如设置背景色、字体等 - 要添加工具栏按钮:在ContentPage的
ToolbarItems集合里添加即可
方法二:一定要在MainActivity里操作原生Toolbar?试试这两个方案
如果必须要操作原生的Toolbar控件,有两种可行的思路:
方案1:调整代码顺序,在LoadApplication前获取
因为LoadApplication才会替换ContentView,所以你可以把获取Toolbar的代码放到LoadApplication之前,这样此时Activity的视图还是原生的Toolbar布局:
protected override void OnCreate(Bundle bundle) { TabLayoutResource = Resource.Layout.Tabbar; ToolbarResource = Resource.Layout.Toolbar; base.OnCreate(bundle); // 重点:在初始化Forms和加载应用前获取Toolbar Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar); if (toolbar != null) { // 在这里做你的自定义操作,比如改标题、加按钮 toolbar.Title = "我的自定义标题"; toolbar.SetSubtitleTextColor(Android.Graphics.Color.Gray); } Xamarin.Forms.Forms.Init(this, bundle); LoadApplication(new App(new AndroidInitializer())); }
注意:这种方式下,后续Forms可能会覆盖你对Toolbar的部分设置,所以如果需要持久化的自定义,还是推荐用渲染器方案。
方案2:用自定义渲染器获取Forms中的原生Toolbar
如果你的Toolbar是Forms的NavigationBar对应的原生控件,通过自定义渲染器可以精准拿到它:
- 先在共享项目里创建一个自定义ContentPage:
public class CustomContentPage : ContentPage { // 定义事件,通知原生Toolbar已就绪 public event EventHandler<Android.Support.V7.Widget.Toolbar> NativeToolbarReady; internal void RaiseToolbarReady(Android.Support.V7.Widget.Toolbar toolbar) { NativeToolbarReady?.Invoke(this, toolbar); } }
- 在Android项目里写对应的渲染器:
[assembly: ExportRenderer(typeof(CustomContentPage), typeof(CustomContentPageRenderer))] namespace YourAppName.Droid.Renderers { public class CustomContentPageRenderer : PageRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Page> e) { base.OnElementChanged(e); if (e.NewElement is CustomContentPage customPage) { // 从MainActivity中获取原生Toolbar var toolbar = ((MainActivity)Context).FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar); if (toolbar != null) { customPage.RaiseToolbarReady(toolbar); } } } } }
- 最后在共享项目的页面里订阅事件,操作Toolbar:
public partial class MainPage : CustomContentPage { public MainPage() { InitializeComponent(); NativeToolbarReady += MainPage_NativeToolbarReady; } private void MainPage_NativeToolbarReady(object sender, Android.Support.V7.Widget.Toolbar e) { // 在这里对原生Toolbar做你需要的操作 e.Subtitle = "这是原生副标题"; e.MenuItemClick += (s, args) => { // 处理菜单点击事件 }; } }
最后再提醒一句:除非是平台特有的高级自定义,否则尽量用Forms的API来做界面操作,这样能减少跨平台适配的麻烦~
内容的提问来源于stack exchange,提问作者Mattias Greger

