源碼地址:https://github.com/l2999019/DemoAppgit
能夠Star一下,隨意 - -github
本篇..基本能夠算是Xamarin在應用開發過程當中的核心了..真的很很很重要..app
想學習的..想用的..建議仔細閱讀..嗯..打醬油的 ..快速滑倒下面點個推薦 - - 哈哈哈...ide
也只講一個,關於Xamarin.Forms針對各個平臺如何進行可定製化的佈局操做.佈局
也就是針對某個平臺的細顆粒化操做.post
廢話很少說,咱們直接開始.學習
嗯..今天我會拿一個項目中的例子出來說.動畫
說說緣由吧,由於在谷歌的安卓開發建議中,是建議相似tab切換操做,是放在頂部的.ui
然而蘋果則否則,他建議放在底部..這樣就形成了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的一些動畫效果.其實也是很不錯的.
本篇就到此結束了.