zoukankan      html  css  js  c++  java
  • C#使用Xamarin开发可移植移动应用进阶篇(7.使用布局渲染器,修改默认布局),附源码

    前言

    系列目录

    C#使用Xamarin开发可移植移动应用目录

    源码地址:https://github.com/l2999019/DemoApp

    可以Star一下,随意 - -

    说点什么..

    本篇..基本可以算是Xamarin在应用开发过程中的核心了..真的很很很重要..

    想学习的..想用的..建议仔细阅读..嗯..打酱油的 ..快速滑倒下面点个推荐 - - 哈哈哈...

    今天的学习内容?

    也只讲一个,关于Xamarin.Forms针对各个平台如何进行可定制化的布局操作.

    也就是针对某个平台的细颗粒化操作.

    废话不多说,我们直接开始.

    正文

    嗯..今天我会拿一个项目中的例子出来讲.

    说说原因吧,因为在谷歌的安卓开发建议中,是建议类似tab切换操作,是放在顶部的.

    然而苹果则不然,他建议放在底部..这样就造成了APP上各个平台对于TabbedPage视图的渲染差别

    如图:

    虽然在墙外..大多数的APP都遵循了这个规则,然而在我们特色的社会主义新中国..几乎所有的APP都是仿苹果的建议 将Tab标签放到了下面..

    嗯,入乡随俗,我们今天就来把这个tab,在安卓中给移到下面.

    效果如图吧:

    既然要移动到下面,那么我们肯定需要重写相关的内容,我们可以找到开源的Xamarin控件BottomNavigationBar

    做过安卓的应该都知道,这个是一个安卓中比较流行的控件,嗯..直接被移植到了Xamarin中

    我们在安卓的项目下,通过nuget添加这个包如下:

    然后我们在可移植的项目中,照常编写我们的TabbedPage页面如下:

    <TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                xmlns:local="clr-namespace:Xamarin.FormsDemo_CHN.Views;assembly=Xamarin.FormsDemo_CHN"
                x:Class="Xamarin.FormsDemo_CHN.Views.MainPage" BarBackgroundColor="#7EC0EE" BarTextColor="White">
        <local:ItemsPage Icon="ic_Messaget"/>
        <local:AboutPage Icon="ic_Info"/>
        <local:BaiDuMapPage  Icon="ic_Star" />
    </TabbedPage>

    我们给这个页面取名叫MainPage,后台代码如下:

    [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class MainPage : TabbedPage
        {
            public MainPage()
            {
                InitializeComponent();
            }
            protected override void OnCurrentPageChanged()
            {
                base.OnCurrentPageChanged();
    
                Title = CurrentPage?.Title;
                
            }
        }

    啥也不用干,就重写一下页面变更事件,改写一下title而已,很常见的代码.

    然后我们回到安卓的项目下.

    添加一个类,取名为MainPageRenderer,表示是重新渲染MainPage的

    编写渲染特性如下:

    [assembly: ExportRenderer(typeof(MainPage), typeof(MainPageRenderer))]
    
    namespace Xamarin.FormsDemo_CHN.Droid
    {
        class MainPageRenderer : VisualElementRenderer<MainPage>, IOnTabClickListener

    注意,我们这里继承了IOnTabClickListener,这个就是第三方的BottomNavigationBar的事件了,待会我们会用到.

    在注意:我们这里因为是重写布局,所以要继承VisualElementRenderer

    接下来我们直接上MainPageRenderer 的完整代码,因为内容较多..涉及的方面也比较多.嗯..包含一些安卓方面的重绘之类的.

    所以就不一一讲解了.大部分都已经写在了注释当中.请仔细看

    class MainPageRenderer : VisualElementRenderer<MainPage>, IOnTabClickListener
        {
    
            private BottomBar _bottomBar;
    
            private Page _currentPage;
    
            private int _lastSelectedTabIndex = -1;
    
            public MainPageRenderer()
            {
                // Required to say packager to not to add child pages automatically
                AutoPackage = false;
            }
    
            /// <summary>
            /// 选中后,加载新的页面内容
            /// </summary>
            /// <param name="position"></param>
            public void OnTabSelected(int position)
            {
                LoadPageContent(position);
            }
    
            public void OnTabReSelected(int position)
            {
            }
    
            protected override void OnElementChanged(ElementChangedEventArgs<MainPage> e)
            {
                base.OnElementChanged(e);
    
                if (e.OldElement != null)
                {
                    ClearElement(e.OldElement);
                }
    
                if (e.NewElement != null)
                {
                    InitializeElement(e.NewElement);
                }
            }
    
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    ClearElement(Element);
                }
    
                base.Dispose(disposing);
            }
    
            /// <summary>
            /// 重写布局的方法
            /// </summary>
            /// <param name="changed"></param>
            /// <param name="l"></param>
            /// <param name="t"></param>
            /// <param name="r"></param>
            /// <param name="b"></param>
            protected override void OnLayout(bool changed, int l, int t, int r, int b)
            {
                if (Element == null)
                {
                    return;
                }
    
                int width = r - l;
                int height = b - t;
    
                _bottomBar.Measure(
                    MeasureSpec.MakeMeasureSpec(width, MeasureSpecMode.Exactly),
                    MeasureSpec.MakeMeasureSpec(height, MeasureSpecMode.AtMost));
    
                //这里需要重新测量位置和尺寸,为了重新布置tab菜单的位置 
                _bottomBar.Measure(
                    MeasureSpec.MakeMeasureSpec(width, MeasureSpecMode.Exactly),
                    MeasureSpec.MakeMeasureSpec(_bottomBar.ItemContainer.MeasuredHeight, MeasureSpecMode.Exactly));
    
                int barHeight = _bottomBar.ItemContainer.MeasuredHeight;
    
                _bottomBar.Layout(0, b - barHeight, width, b);
    
                float density = Resources.DisplayMetrics.Density;
    
                double contentWidthConstraint = width / density;
                double contentHeightConstraint = (height - barHeight) / density;
    
                if (_currentPage != null)
                {
                    var renderer = Platform.GetRenderer(_currentPage);
    
                    renderer.Element.Measure(contentWidthConstraint, contentHeightConstraint);
                    renderer.Element.Layout(new Rectangle(0, 0, contentWidthConstraint, contentHeightConstraint));
    
                    renderer.UpdateLayout();
                }
            }
    
            /// <summary>
            /// 初始化方法
            /// </summary>
            /// <param name="element"></param>
            private void InitializeElement(MainPage element)
            {
                PopulateChildren(element);
            }
            /// <summary>
            /// 生成新的底部控件
            /// </summary>
            /// <param name="element"></param>
            private void PopulateChildren(MainPage element)
            {
                //我们需要删除原有的底部控件,然后添加新的
                _bottomBar?.RemoveFromParent();
                
                _bottomBar = CreateBottomBar(element);
                AddView(_bottomBar);
    
                LoadPageContent(0);
            }
    
    
            /// <summary>
            /// 清除旧的底部控件
            /// </summary>
            /// <param name="element"></param>
            private void ClearElement(MainPage element)
            {
                if (_currentPage != null)
                {
                    IVisualElementRenderer renderer = Platform.GetRenderer(_currentPage);
    
                    if (renderer != null)
                    {
                        renderer.ViewGroup.RemoveFromParent();
                        renderer.ViewGroup.Dispose();
                        renderer.Dispose();
    
                        _currentPage = null;
                    }
    
                    if (_bottomBar != null)
                    {
                        _bottomBar.RemoveFromParent();
                        _bottomBar.Dispose();
                        _bottomBar = null;
                    }
                }
            }
    
            /// <summary>
            /// 创建新的底部控件
            /// </summary>
            /// <param name="element"></param>
            /// <returns></returns>
            private BottomBar CreateBottomBar(MainPage element)
            {
                var bar = new BottomBar(Context);
    
                // TODO: Configure the bottom bar here according to your needs
    
                bar.SetOnTabClickListener(this);
                bar.UseFixedMode();
    
                PopulateBottomBarItems(bar, element.Children);
                var barcolor = element.BarBackgroundColor;
               // Color a = new Color(Convert.ToByte(barcolor.), Convert.ToByte(barcolor.G), Convert.ToByte(barcolor.B), Convert.ToByte(barcolor.A));
    
    
                bar.ItemContainer.SetBackgroundColor(barcolor.ToAndroid());
                bar.SetActiveTabColor(Color.White);
                //bar.ItemContainer.
                //bar.ItemContainer.SetBackgroundColor(Color.Red);
    
                return bar;
            }
    
            /// <summary>
            /// 查询原来底部的菜单,并添加到新的控件
            /// </summary>
            /// <param name="bar"></param>
            /// <param name="pages"></param>
            private void PopulateBottomBarItems(BottomBar bar, IEnumerable<Page> pages)
            {
                
                var barItems = pages.Select(x => new BottomBarTab(Context.Resources.GetDrawable(x.Icon), x.Title));
    
                bar.SetItems(barItems.ToArray());
            }
    
            /// <summary>
            /// 通过选择的下标加载Page
            /// </summary>
            /// <param name="position"></param>
            private void LoadPageContent(int position)
            {
                ShowPage(position);
            }
    
            /// <summary>
            /// 显示Page的方法
            /// </summary>
            /// <param name="position"></param>
            private void ShowPage(int position)
            {
                if (position != _lastSelectedTabIndex)
                {
                    Element.CurrentPage = Element.Children[position];
    
                    if (Element.CurrentPage != null)
                    {
                        LoadPageContent(Element.CurrentPage);
                    }
                }
    
                _lastSelectedTabIndex = position;
            }
    
            /// <summary>
            /// 加载方法
            /// </summary>
            /// <param name="page"></param>
            private void LoadPageContent(Page page)
            {
                UnloadCurrentPage();
    
                _currentPage = page;
    
                LoadCurrentPage();
    
                Element.CurrentPage = _currentPage;
            }
    
            /// <summary>
            /// 加载当前Page
            /// </summary>
            private void LoadCurrentPage()
            {
                var renderer = Platform.GetRenderer(_currentPage);
    
                if (renderer == null)
                {
                    renderer = Platform.CreateRenderer(_currentPage);
                    Platform.SetRenderer(_currentPage, renderer);
    
                   
                }
                else
                {
                    var basePage = _currentPage as BaseContentPage;
                    basePage?.SendAppearing();
                }
                
                AddView(renderer.ViewGroup);
                renderer.ViewGroup.Visibility = ViewStates.Visible;
              
            }
    
            /// <summary>
            /// 释放上一个Page
            /// </summary>
            private void UnloadCurrentPage()
            {
                if (_currentPage != null)
                {
                    var basePage = _currentPage as BaseContentPage;
                    basePage?.SendDisappearing();
                    var renderer = Platform.GetRenderer(_currentPage);
    
                    if (renderer != null)
                    {
                        renderer.ViewGroup.Visibility = ViewStates.Invisible;
                        RemoveView(renderer.ViewGroup);
                    }
                    
                }
            }
        }

    这样,我们就完成了整个tab菜单的替换工作.当然各位还可以根据需要来直接调用BottomNavigationBar的一些动画效果.其实也是很不错的.

    本篇就到此结束了.

  • 相关阅读:
    大二第二学期周学习进度总结(七)
    java课程之团队开发冲刺阶段1.1
    Java课程之团队开发(NABCD需求分析)
    大二第二学期周学习进度总结(六)
    Java课程之团队开发(团队介绍)
    大二第二学期周学习进度总结(五)
    模拟退火 费马点求解
    三分 传送带
    2357数
    B监狱 noip 模拟 7.29(区间DP)
  • 原文地址:https://www.cnblogs.com/GuZhenYin/p/7447336.html
Copyright © 2011-2022 走看看