最近项目中做了一个标题栏中的按钮选择器,原生的UISegmentedControl 无法达到项目效果,效果如下图:
如果只针对项目写一个不难,可是如果以后遇到了还需要针对项目再去写一个,于是我打算把他写的活一些,最终决定用Builder模式来完成它,以前做android原生的时候就用Builder模式构建了一些组合view,但是我尝试着用java的方式去Builder的时候发现行不通,这次是Xamarin的项目,语言是C#,于是我又去学习了一下C#的Builder模式(浅显的理解很简单)。
哦,差点忘了介绍,项目的框架是MvvmCross,不理解的同学去他的官网看看,很良心的!
最终计划了一下这个工作分为三步走(典型的面向过程,哈哈)。
第一步:将这些可以看见的属性,或者随时可以变的属性抽象出来。
using System;
using UIKit;
namespace RuilaiGrow.iOS
{
///
/// 多按钮圆角view构建抽象类
/// by ge
///
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
{
///
/// 知识库主页标题切换控制器
///
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;
///
/// 最终创建view
///
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);
}
}
///
/// 设置按钮正常时的状态颜色
///
/// Corlor.
public override void setItemNormal(UIColor corlor)
{
this._itemNormalBac = corlor;
}
///
/// 设置item选中时的背景
///
/// Selected.
public override void setItemSelected(UIColor selected)
{
this._itemSeletedBac = selected;
}
///
/// 设置正常时的文字的颜色
///
/// Color.
public override void setNormalTextColor(UIColor color)
{
this._textNormalColor = color;
}
///
/// 设置选中时文字的颜色
///
/// Color.
public override void setSelectedTextColor(UIColor color)
{
this._textSeletedColor = color;
}
///
/// 设置item的文字
///
/// Titles.
public override void setTitles(string[] titles)
{
this._titles = titles;
}
///
/// 设置view的背景图片
///
/// Background.
public override void setViewBackground(UIColor background)
{
this._viewBackground = background;
}
///
/// 设置item的宽
///
/// Width.
public override void setWidth(nfloat width)
{
this._itemWid = width;
}
///
/// 设置本view的高
///
/// Height.
public override void setHeight(nfloat height)
{
this._viewHei = height;
}
///
/// 设置边框的圆角与按钮的圆角
///
/// Radius.
public override void setCornerRadius(nfloat radius)
{
this._radius = radius;
}
///
/// 设置文字的大小
///
/// Size.
public override void setTextSize(nfloat size)
{
this._textSize = size;
}
///
/// 点击view回调接口
///
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);
按钮的个数是根据构造函数传入的数组决定的。
搞定!!