自定义控件
2016-08-27 本文已影响30人
T92
自定义多段选择器

类代码
//需求分析:制作一个竖直排列的segement
//tag 0~10分配为segment按钮,11~15分配给滑条 其他未分配
class MySegment: UIView {
// MARK: - 属性
private var items:[String]
private var slider = UIView()
private var target: AnyObject? = nil
private var action: Selector? = nil
var selectedBtnBackGround:UIColor
//当外部改变MySegment的相关属性后需要作出相应地改变
//文字颜色
var titleColor = UIColor.blackColor(){
didSet{
for item in subviews{
if item.tag < 10{
(item as!UIButton).setTitleColor(titleColor, forState: .Normal)
}
}
}
}
//选中文字颜色
var selectedColor = UIColor.redColor(){
didSet {
//改变滑条颜色
slider.backgroundColor = selectedColor
//改变按钮文字颜色
for item in subviews{
if item.tag < 10{
(item as!UIButton).setTitleColor(selectedColor, forState: .Selected)
}
}
}
}
//选中按钮的是哪一个(默认选中0也就是第一个)
var selectedBtn = 0{
//将要给selectedBtn重新赋值时会自动执行里面的代码
willSet{
for item in self.subviews {
if item.tag == selectedBtn {
//1.先将原来选中的按钮变成非选中状态
(item as! UIButton).selected = false
//原来按钮背景颜色去掉
(item as! UIButton).backgroundColor = nil
}
if item.tag == newValue{
//2.将指定的按钮变成选中状态
(item as! UIButton).selected = true
//选中按钮背景颜色
(item as! UIButton).backgroundColor = selectedBtnBackGround
}
}
}
//已经改变值之后自动调用
didSet{
//改变滑条的y值,生硬
// slider.frame.origin.y = CGFloat(selectedBtn) * slider.frame.height
//尝试使用平移,生硬
//slider.transform = CGAffineTransformTranslate(self.transform, 0, CGFloat(selectedBtn) * slider.frame.height)
//加一个动画不会显得生硬
UIView.animateWithDuration(0.2) { self.slider.frame.origin.y = CGFloat(self.selectedBtn) * self.slider.frame.height }
}
}
// MARK: - 构造器
/**
构造器
- parameter items:要显示的分段文字
- parameter selectedBtnBackGround: 选中按钮的颜色
*/
init(items:[String],selectedBtnBackGround:UIColor){
self.items = items
self.selectedBtnBackGround = selectedBtnBackGround
assert(items.count < 10, "选择个数不能大于10")
super.init(frame: CGRectZero)
self.creatBtn()
self.creatSilder()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
/// MARK: - 创建子视图方法
extension MySegment{
func creatBtn(){
for (i,item) in items.enumerate(){
let btn = UIButton()
btn.setTitle(item, forState: .Normal)
btn.tag = i
btn.setTitleColor(titleColor, forState: .Normal)
btn.setTitleColor(selectedColor, forState: .Selected)
self.addSubview(btn)
if i == 0{
btn.selected = true
btn.backgroundColor = selectedBtnBackGround
// print(btn.tag) //测试
}
btn.addTarget(self, action: "btnAction:", forControlEvents: .TouchUpInside)
}
}
func creatSilder(){
slider.backgroundColor = selectedColor
self.addSubview(slider)
slider.tag = 11
}
//设置子视图的frame
override func layoutSubviews() {
super.layoutSubviews()
//获取当前分段选择器的宽高
let selfW = self.frame.size.width
let selfH = self.frame.size.height
//按钮的frame计算
//根据需求分析,btn的宽度为当前分段选择器的宽度
//高度是当前分段器高度除以item个数
//x是当前分段器的最左边,我们添加btn是添加到当前分段器上的,所以相对坐标 x = 0
let btnW = selfW
let btnH = selfH / CGFloat(items.count)
let btnX:CGFloat = 0
//y坐标是有规律变化的,所以最后考虑y
var i:CGFloat = 0
for item in self.subviews{
//判断分段选择器上的视图是不是按钮(分配的时候tag 0~10 是按钮)
if item.tag <= 10{
let btnY = i * btnH
item.frame = CGRectMake(btnX, btnY, btnW, btnH)
item.layer.cornerRadius = btnW * 0.2//切圆角
i += 1
}
}
//slider的frame计算
//根据需求分析,slider宽度自定,高度是按钮的高度
//x坐标不变,自定,y在变
let sliderW:CGFloat = 2
let sliderH = btnH
let sliderX = btnX - sliderW - sliderW //按钮与slider之间间距一个slider的宽度
let sliderY = sliderH * CGFloat(selectedBtn)
slider.frame = CGRectMake(sliderX, sliderY, sliderW, sliderH)
}
}
/// MARK: - 按钮事件添加
extension MySegment{
func btnAction(btn:UIButton){
if self.selectedBtn != btn.tag{
self.selectedBtn = btn.tag
}
if target != nil{
//让target去调用action中的方法
//参数1:需要调用的方法对应的Selecter
//参数2:如果Selecter中方法带参,那个这个参数的值就是Selecter中方法的实参
self.target?.performSelector(self.action!, withObject:self)
}
}
}
//MARK: - 提供给外部使用的方法
extension MySegment{
//保存target和action值
func addTarget(target:AnyObject?, action:Selector) {
self.target = target
self.action = action
}
}
测试
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let mySegment = MySegment(items: ["消息","分组","附近","地图"], selectedBtnBackGround: UIColor.blackColor())
mySegment.frame = CGRectMake(100, 100, 50, 200)
//mySegement.backgroundColor = UIColor.blueColor()
mySegment.selectedColor = UIColor.greenColor()
mySegment.titleColor = UIColor.redColor()
//mySegment.selectedBtn = 2 //测试改变默认选中为第三个按钮
self.view.addSubview(mySegment)
mySegment.addTarget(self, action: "action:")
}
func action(action:MySegment) {
print("选择器在做切换")
}
}
自定义按键Button

类代码
class ButtonStyle1: UIButton {
//重写按键上图片frame
override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
let w:CGFloat = contentRect.size.width
let h:CGFloat = contentRect.size.height * 4 / 5
return CGRectMake(0, 0, w, h)
}
//重写按键上文字的frame
override func titleRectForContentRect(contentRect: CGRect) -> CGRect {
let y:CGFloat = contentRect.size.height * 4 / 5 + 5 //设置文字与图片间距为5
let w:CGFloat = contentRect.size.width
let h:CGFloat = contentRect.size.height / 5 - 5 //高度加了5就要减5
return CGRectMake(0, y, w, h)
}
}
测试
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
creatUI()
}
}
extension ViewController{
//创建框架
func creatUI(){
//背景
let backGround = UIImageView(frame: self.view.bounds)
backGround.backgroundColor = UIColor.grayColor()
self.view.addSubview(backGround)
//按钮
let myBtn = ButtonStyle1(frame:CGRectMake(100,100,60,70))
myBtn.setImage(UIImage(named: "p1"), forState: .Normal)
//myBtn.backgroundColor = UIColor.yellowColor()
myBtn.setTitle("主题", forState: .Normal)
myBtn.titleLabel?.textAlignment = .Center
self.view.addSubview(myBtn)
}
}
自定义按钮2

首先创建自己按钮的类
class myButton: UIButton {
//设计要求:
//图片高度是整个按钮的高度的4/5
//文字高度是整个按钮的高度的1/5
//设置button上的imageView的坐标和大小
//参数1:当前按钮的范围(只需要大小)
//返回值:重新设置的图片的坐标和大小
override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
let x:CGFloat = 0
let y:CGFloat = 0
let w:CGFloat = contentRect.size.width
let h:CGFloat = contentRect.size.height * 4 / 5
return CGRectMake(x, y, w, h)
}
//设置button上的titleLabel的坐标和大小
//参数1:当前按钮的范围(只需要大小)
//返回值:重新设置的图片的坐标和大小
override func titleRectForContentRect(contentRect: CGRect) -> CGRect {
let x:CGFloat = 0
let y:CGFloat = contentRect.size.height * 4 / 5
let w:CGFloat = contentRect.size.width
let h:CGFloat = contentRect.size.height * 1 / 5
return CGRectMake(x, y, w, h)
}
}
应用自己定义的按钮
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//1.创建按钮对象
let button = myButton(frame:CGRectMake(100,100,100,120))
//2.设置文字
button.setTitle("按钮", forState: .Normal)
button.setTitleColor(UIColor.redColor(), forState: .Normal)
button.titleLabel?.textAlignment = .Center
//3.设置图片
button.setImage(UIImage(named:"luffy4.png"), forState: .Normal)
self.view.addSubview(button)
//4.添加按钮点击事件
//button.addTarget(<#T##target: AnyObject?##AnyObject?#>, action: <#T##Selector#>, forControlEvents: <#T##UIControlEvents#>)
}
}
自定义键盘

首先创建自定义的键盘类
protocol KeyboardDelegate{
//让代理方显示指定按键上的内容
func showContent(button:UIButton)
}
//1.在创建当前类的时候,去创建这个视图上所有的子视图,并且添加到当前视图(不需要设置子视图的frame)
class Keyboard: UIView {
var delegate:KeyboardDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
self.creatSubViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension Keyboard{
//计算子视图的frame
//当前视图将要显示在界面的时候会自动调用本方法。
//这个方法得到的frame是当前视图最终的frame,当前视图frame改变(包括坐标和大小)时,会再次调用这个方法
override func layoutSubviews() {
//按键间距
let margin:CGFloat = 10
//键盘宽度
let keyW = self.frame.size.width
//键盘高度
let keyH = self.frame.size.height
//按键列数
let col:CGFloat = 3
//按键行数
let row:CGFloat = 4
//按键宽度
let btnW = (keyW - (col + 1) * margin) / col
//按键高度
let btnH = (keyH - (row + 1) * margin) / row
var i = 0
//拿到当前视图上的子视图
for item in self.subviews{
if item.tag == 100{
let btnX = margin + (btnW + margin) * CGFloat (i % Int(col))
let btnY = margin + (btnH + margin) * CGFloat (i / Int(col))
item.frame = CGRectMake(btnX, btnY, btnW, btnH)
//找到一个按钮i加1
i += 1
}
}
}
//创建子视图(按键)
func creatSubViews(){
let titles = ["1","2","3","4","5","6","7","8","9","c","0","return"]
for (_,item) in titles.enumerate(){
//创建对应按钮,坐标00,大小00(原因是键盘大小有可能改变,按键大小不能定死)
let btn = UIButton()
btn.setTitle(item, forState: .Normal)
btn.setTitleColor(UIColor.blackColor(), forState: .Normal)
btn.backgroundColor = UIColor.yellowColor()
btn.tag = 100
btn.addTarget(self, action: "btnAction:", forControlEvents: .TouchDown)
self.addSubview(btn)
}
}
//按钮点击
func btnAction(btn:UIButton){
//print(btn.currentTitle)//currentTitle属性,按钮上的文字
//Keyboard想要将按键上的内容显示到ViewController中的TextField上,但是Keyboard做不到,但是ViewController可以。因此要用委托
//确定三要素
//委托方:Keyboard
//协议:将指定按键上的内容显示到textfield上
//代理方:ViewController
//让代理方显示内容
delegate?.showContent(btn)
}
}
应用自定义键盘
class ViewController: UIViewController,KeyboardDelegate {
var textField = UITextField()
override func viewDidLoad() {
super.viewDidLoad()
//1.创建文本框对象
textField = UITextField(frame: CGRectMake(100,100,100,50))
//2.设置背景颜色
textField.backgroundColor = UIColor.yellowColor()
self.view.addSubview(textField)
let keyboard = Keyboard(frame:CGRectMake(0,0,0,256))
keyboard.delegate = self
textField.inputView = keyboard
}
func showContent(button: UIButton) {
if button.currentTitle == "c"{
self.textField.deleteBackward()
return
}
if button.currentTitle == "return"{
self.textField.resignFirstResponder()
return
}
textField.text! += button.currentTitle!
}
}
自定义段选择器segment2
(老师版),下一篇文章会有自己仿写的分段选择器
创建自定义多段选择器的类
let BtnTag = 100
class YTSegmentControl: UIView {
//MARK: - 属性
///1.当前被选中的按钮的下标
var selectedSegmentIndex = 0{
//将要将新值赋给selectedSegmentIndex。这个selectedSegmentIndex还是原来
willSet{
//1.先将原来选中的按钮变成非选中状态
let btn1 = self.viewWithTag(BtnTag
+ selectedSegmentIndex) as! UIButton
btn1.selected = false
//2.将指定的按钮变成选中状态
//newValue -> 将要赋给当前属性的那个新的值
let btn2 = self.viewWithTag(BtnTag + newValue) as! UIButton
btn2.selected = true
}
//已经给selectedSegmentIndex赋值
didSet{
UIView.animateWithDuration(0.2) {
self.slider.frame.origin.x = CGFloat(self.selectedSegmentIndex) * self.slider.frame.size.width
}
}
}
///2.文字选中的颜色
var titleSelectedColor = UIColor.blueColor(){
didSet{
//更新滑块的背景颜色
self.slider.backgroundColor = self.titleSelectedColor
for item in self.subviews {
if item.tag >= BtnTag {
let btn = item as! UIButton
//改变按钮的文字颜色
btn.setTitleColor(self.titleSelectedColor, forState: .Selected)
}
}
}
}
///3.文字颜色
var titleColor = UIColor.blackColor(){
//每次从外部给titleColor属性赋值的时候,都需要用最新的titleColor的值去更新按钮的文字颜色
didSet{
for item in self.subviews {
if item.tag >= BtnTag {
let btn = item as! UIButton
//改变按钮的文字颜色
btn.setTitleColor(self.titleColor, forState: .Normal)
}
}
}
}
///4.items
private var items:[String]
///5.滑块
private var slider = UIView()
///6.保存target
private var target: AnyObject? = nil
///7.保存action
private var action: Selector? = nil
//MARK: - 构造方法
init(items:[String]){
self.items = items
//CGRectZero ->坐标是(0,0),大小是(0,0)
super.init(frame: CGRectZero)
//创建items中的每个数组元素对应的按钮
self.creatSubView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//MARK: - 提供给外部使用的方法
extension YTSegmentControl{
//保存target和action值
func addTarget(target:AnyObject?, action:Selector) {
self.target = target
self.action = action
}
}
//MARK: - 创建子视图
extension YTSegmentControl{
func creatSubView() {
//1.创建按钮
for (i,item) in self.items.enumerate() {
//创建按钮不设置frame属性
let btn = UIButton.init()
//设置文字
btn.setTitle(item, forState: .Normal)
//设置tag值
btn.tag = BtnTag + i
//设置文字颜色
btn.setTitleColor(self.titleColor, forState: .Normal)
btn.setTitleColor(self.titleSelectedColor, forState: .Selected)
//让默认第0个按钮处于选中状态
if i == 0 {
btn.selected = true
}
//添加点击事件
btn.addTarget(self, action: "btnAction:", forControlEvents: .TouchDown)
//添加到界面上
self.addSubview(btn)
}
//2.创建滑块
self.slider.backgroundColor = self.titleSelectedColor
self.addSubview(self.slider)
}
}
//MARK: - 按钮点击事件
extension YTSegmentControl{
func btnAction(btn:UIButton) {
if self.selectedSegmentIndex != btn.tag - BtnTag {
//更新选中的下标
self.selectedSegmentIndex = btn.tag - BtnTag
//通知外部值改变了
if self.target != nil {
//让target去调用action中的方法
//参数1:需要调用的方法对应的Selecter
//参数2:如果Selecter中方法带参,那个这个参数的值就是Selecter中方法的实参
self.target?.performSelector(self.action!, withObject:self)
}
}
}
}
//MARK: - 计算子视图的frame
extension YTSegmentControl{
override func layoutSubviews() {
super.layoutSubviews()
//当前分段选择器的宽和高
let segementW = self.frame.size.width
let segementH = self.frame.size.height
//1.计算按钮的frame
let btnW = segementW/CGFloat(self.items.count)
let btnH = segementH
let btnY: CGFloat = 0
//遍历所有的子视图
var i: CGFloat = 0
for item in self.subviews {
//找到其中的按钮
if item.tag >= BtnTag {
let btnX = i * btnW
item.frame = CGRectMake(btnX, btnY, btnW, btnH)
//找到一个按钮i加1
i += 1
}
}
//2.计算滑块的frame
let sliderX = CGFloat(self.selectedSegmentIndex) * btnW
let sliderH: CGFloat = 2
let sliderY = segementH - sliderH
let sliderW = btnW
self.slider.frame = CGRectMake(sliderX, sliderY, sliderW, sliderH)
}
}
应用自定义的分段选择器
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//系统的分段选择器
let segement = UISegmentedControl.init(items: ["1","2","3"])
segement.frame = CGRectMake(100, 100, 200, 50)
self.view.addSubview(segement)
segement.selectedSegmentIndex = 1
segement.addTarget(self, action: "action", forControlEvents: .ValueChanged)
//自己的分段选择器
let selfSegement = YTSegmentControl.init(items: ["海贼","路飞"])
selfSegement.frame = CGRectMake(100, 200, 200, 50)
selfSegement.titleColor = UIColor.redColor()
selfSegement.titleSelectedColor = UIColor.greenColor()
selfSegement.selectedSegmentIndex = 1
selfSegement.addTarget(self, action: "selfAction:")
self.view.addSubview(selfSegement)
}
func selfAction(segement:YTSegmentControl) {
print("自己的选择器在做切换")
print(segement.selectedSegmentIndex)
}
func action() {
print("系统的选择器在做切换")
}
}