最近項目中做了一個標題列中的按鈕選取器,原生的UISegmentedControl 無法達到項目效果,效果如下圖:
如果只針對項目寫一個不難,可是如果以後遇到了還需要針對項目再去寫一個,於是我打算把他寫的活一些,最終決定用Builder模式來完成它,以前做android原生的時候就用Builder模式構建了一些組合view,但是我嘗試著用java的方式去Builder的時候發現行不通,這次是Xamarin的項目,語言是C#,於是我又去學習了一下C#的Builder模式(淺顯的理解很簡單)。
哦,差點忘了介紹,項目的架構是MvvmCross,不理解的同學去他的官網看看,很良心的。
最終計划了一下這個工作分為三步走(典型的面向過程,哈哈)。
第一步:將這些可以看見的屬性,或者隨時可以變的屬性抽象出來。
using System;using UIKit;namespace RuilaiGrow.iOS{ /// <summary> /// 多按鈕圓角view構建抽象類別 /// by ge /// </summary> abstract class BuilderTopSelectedTitle { public abstract void setTitles(string[] titles); public abstract void setTextSize(nfloat size); public abstract void setCornerRadius(nfloat radius); public abstract void setHeight(nfloat height); public abstract void setWidth(nfloat width); public abstract void setNormalTextColor(UIColor color); public abstract void setSelectedTextColor(UIColor color); public abstract void setViewBackground(UIColor background); public abstract void setItemNormal(UIColor corlor); public abstract void setItemSelected(UIColor selected); public abstract UIView create(); }}
項目比較緊張,可能這些屬性還是不夠,或者說想的不到位,以後慢慢添加和最佳化。
第二步:建立實作類別,構建需要的控制項。
經過一番研究,最外層(也就是最終建立返回給介面的)是一個UIView,中間的按鈕用UIButton來代替,原因是:經過查閱資料,和嘗試,發現UIButton是將UILable於UIImageView封裝的結果,採用懶載入的方式,用誰初始化誰,感覺很棒不用我自己造輪子了(以前一直做android原生,對iOS不是很瞭解,大家見笑)。下面是實作類別的代碼,注視挺全的了,直接複製粘貼了(懶懶懶)。
using System;using System.Drawing;using RuilaiGrow.iOS.Common;using UIKit;namespace RuilaiGrow.iOS{ /// <summary> /// 知識庫首頁標題切換控制器 /// </summary> class KnowledgeTitleControl : BuilderTopSelectedTitle { public KnowledgeTitleControl() { } //最外層總view UIView _thisView = null; public UIView ThisView { get { if (_thisView == null) { //根據本view的寬與高來計算其實位置(目的最終添加到View的導覽列的時候可以置中顯示) nfloat startX = (UIScreen.MainScreen.Bounds.Width - _itemWid * _titles.Length) / 2; nfloat startY = (EasyLayout.BarHeight - _viewHei) / 2; _thisView = new UIView(new RectangleF((float)startX, (float)startY, (float(_itemWid * _titles.Length), (float)_viewHei)); _thisView.BackgroundColor = _viewBackground; } return _thisView; } } //標題數組 private string[] _titles; //item數組 private UIButton[] _itemBtns; //控制項的高 private nfloat _viewHei = 45; //item的寬 private nfloat _itemWid = 70; //item正常時的顏色 private UIColor _itemNormalBac = UIColor.Blue; //item選中時的顏色 private UIColor _itemSeletedBac = UIColor.White; //文字正常的顏色 private UIColor _textNormalColor = UIColor.Black; //文字選中時的顏色 private UIColor _textSeletedColor = UIColor.Red; //設定本view的顏色 private UIColor _viewBackground = UIColor.Blue; //文字的大小 private nfloat _textSize = 15; //邊框與按鈕的圓角 private nfloat _radius = 18; //按鈕上次點擊事件 預設0 private int lastIndex = 0; /// <summary> /// 最終建立view /// </summary> public override UIView create() { ThisView.Layer.BorderWidth = 1; ThisView.Layer.BorderColor = MvxTouchColor.ShallowGrayOne.CGColor; ThisView.Layer.CornerRadius = _radius; _itemBtns = new UIButton[_titles.Length]; //迴圈建立文字按鈕並加入到總view中 int lenght = _titles.Length; for (int i = 0; i < lenght; i++) { _itemBtns[i] = new UIButton(); _itemBtns[i].Tag = i; _itemBtns[i].SetTitle(_titles[i], UIControlState.Normal); _itemBtns[i].SetTitleColor(_textNormalColor, UIControlState.Normal); _itemBtns[i].Layer.CornerRadius = _radius; _itemBtns[i].TitleLabel.Font = UIFont.SystemFontOfSize(_textSize);//設定第一個按鈕選中狀態 if (i == 0) { _itemBtns[i].BackgroundColor = _itemSeletedBac; _itemBtns[i].SetTitleColor(_textSeletedColor, UIControlState.Normal); } } ThisView.AddSubviews(_itemBtns); //迴圈設定view內部item之間約束 for (int i = 0; i < lenght; i++) { if (i == 0) { ThisView.ConstrainLayout(() => _itemBtns[i].Frame.GetCenterY() == ThisView.Frame.GetCenterY() && _itemBtns[i].Frame.Width == _itemWid && _itemBtns[i].Frame.Height == ThisView.Frame.Height && _itemBtns[i].Frame.Left == ThisView.Frame.Left && ThisView.Frame.Bottom == _itemBtns[i].Frame.Bottom ); } else { ThisView.ConstrainLayout(() => _itemBtns[i].Frame.GetCenterY() == ThisView.Frame.GetCenterY() && _itemBtns[i].Frame.Left == _itemBtns[i - 1].Frame.Right && _itemBtns[i].Frame.Width == _itemWid && _itemBtns[i].Frame.Height == ThisView.Frame.Height ); } } //按鈕點擊事件 for (int i = 0; i < _titles.Length; i++) { _itemBtns[i].TouchUpInside += this.TouchBtn; } return ThisView; } //按鈕點擊處理 private void TouchBtn(object sender, EventArgs e) { UIButton v = (UIKit.UIButton)sender; //如果和上次點的一樣 return if (v.Tag == lastIndex) return; //清空上次點擊view的狀態 _itemBtns[lastIndex].BackgroundColor = _itemNormalBac; _itemBtns[lastIndex].SetTitleColor(_textNormalColor, UIControlState.Normal); //設定本次點擊的view的狀態 _itemBtns[v.Tag].BackgroundColor = _itemSeletedBac; _itemBtns[v.Tag].SetTitleColor(_textSeletedColor, UIControlState.Normal); //記錄本次點擊的位置 lastIndex = (int)v.Tag; //回調點擊位置 if (_click != null) { _click.TitleBackIndex((int)v.Tag); } } /// <summary> /// 設定按鈕正常時的狀態顏色 /// </summary> /// <param name="corlor">Corlor.</param> public override void setItemNormal(UIColor corlor) { this._itemNormalBac = corlor; } /// <summary> /// 設定item選中時的背景 /// </summary> /// <param name="selected">Selected.</param> public override void setItemSelected(UIColor selected) { this._itemSeletedBac = selected; } /// <summary> /// 設定正常時的文字的顏色 /// </summary> /// <param name="color">Color.</param> public override void setNormalTextColor(UIColor color) { this._textNormalColor = color; } /// <summary> /// 設定選中時文字的顏色 /// </summary> /// <param name="color">Color.</param> public override void setSelectedTextColor(UIColor color) { this._textSeletedColor = color; } /// <summary> /// 設定item的文字 /// </summary> /// <param name="titles">Titles.</param> public override void setTitles(string[] titles) { this._titles = titles; } /// <summary> /// 設定view的背景圖片 /// </summary> /// <param name="background">Background.</param> public override void setViewBackground(UIColor background) { this._viewBackground = background; } /// <summary> /// 設定item的寬 /// </summary> /// <param name="width">Width.</param> public override void setWidth(nfloat width) { this._itemWid = width; } /// <summary> /// 設定本view的高 /// </summary> /// <param name="height">Height.</param> public override void setHeight(nfloat height) { this._viewHei = height; } /// <summary> /// 設定邊框的圓角與按鈕的圓角 /// </summary> /// <param name="radius">Radius.</param> public override void setCornerRadius(nfloat radius) { this._radius = radius; } /// <summary> /// 設定文字的大小 /// </summary> /// <param name="size">Size.</param> public override void setTextSize(nfloat size) { this._textSize = size; } /// <summary> /// 點擊view回調介面 /// </summary> public interface ClickTitleControlItem { void TitleBackIndex(int index); } private ClickTitleControlItem _click; public void setClickTitleControlItem(ClickTitleControlItem click) { this._click = click; } }}
上面就是實作類別的全部內容,最後那個介面是這個view點擊某個按鈕時的回調,同事說我這是拿java的思想來寫c#,搞得我去查了一下,打算把這個換成事件委託機制。
下面看一下第三步:使用
在Controller中直接定義一個UIView接收建立的view就可以:
//頭部導覽列的view UIView _topViewControl = null; public UIView TopViewControl { get{ if (_topViewControl == null) { string[] s = new string[] { "0-1歲", "1-3歲", "3-6歲" }; KnowledgeTitleControl ctr = new KnowledgeTitleControl(); ctr.setWidth(85); ctr.setHeight(EasyLayout.BarHeight - 10f); ctr.setTitles(s); ctr.setTextSize(15); ctr.setCornerRadius(18); ctr.setItemNormal(MvxTouchColor.DeepRed); ctr.setViewBackground(MvxTouchColor.DeepRed); ctr.setItemSelected(MvxTouchColor.White); ctr.setNormalTextColor(MvxTouchColor.ShallowGrayOne); ctr.setSelectedTextColor(MvxTouchColor.DeepRed); ctr.setClickTitleControlItem(this); _topViewControl = ctr.create(); } return _topViewControl; } }
最後將view添加到導覽列就可以了:
在ViewDidLoad()方法中:
//將頭部控制器的uiview加入頂部導覽列NavigationController.NavigationBar.AddSubview(TopViewControl);
按鈕的個數是根據建構函式傳入的數組決定的。
搞定。。