Skip to content

Commit

Permalink
FWRadioButton
Browse files Browse the repository at this point in the history
  • Loading branch information
choiceyou committed Nov 1, 2018
1 parent bb75459 commit 721d40e
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 5 deletions.
4 changes: 4 additions & 0 deletions FWPopupView/FWPopupView.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
49089B94216DA23B00683B2F /* FWRadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49089B93216DA23B00683B2F /* FWRadioButton.swift */; };
491A970D20AFCD17006E3D70 /* FWMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491A970C20AFCD17006E3D70 /* FWMenuView.swift */; };
493BE226206A322B00E5EF80 /* FWDateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493BE225206A322B00E5EF80 /* FWDateView.swift */; };
49552D3D20B56C24000A1FA6 /* FWCustomPopupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49552D3C20B56C24000A1FA6 /* FWCustomPopupView.swift */; };
Expand Down Expand Up @@ -45,6 +46,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
49089B93216DA23B00683B2F /* FWRadioButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FWRadioButton.swift; sourceTree = "<group>"; };
491A970C20AFCD17006E3D70 /* FWMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FWMenuView.swift; sourceTree = "<group>"; };
493BE225206A322B00E5EF80 /* FWDateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FWDateView.swift; sourceTree = "<group>"; };
49552D3C20B56C24000A1FA6 /* FWCustomPopupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FWCustomPopupView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -162,6 +164,7 @@
495AC1042068C900002773F9 /* FWSheetView.swift */,
491A970C20AFCD17006E3D70 /* FWMenuView.swift */,
493BE225206A322B00E5EF80 /* FWDateView.swift */,
49089B93216DA23B00683B2F /* FWRadioButton.swift */,
);
path = FWPopupView;
sourceTree = "<group>";
Expand Down Expand Up @@ -307,6 +310,7 @@
49BB210F2060B86A00E0DE6E /* FWPopupCategory.swift in Sources */,
49BB212720623E8100E0DE6E /* FWPopupItem.swift in Sources */,
491A970D20AFCD17006E3D70 /* FWMenuView.swift in Sources */,
49089B94216DA23B00683B2F /* FWRadioButton.swift in Sources */,
49552D3D20B56C24000A1FA6 /* FWCustomPopupView.swift in Sources */,
49812DA7205F91F100639DDC /* FWPopupView.swift in Sources */,
493BE226206A322B00E5EF80 /* FWDateView.swift in Sources */,
Expand Down
10 changes: 9 additions & 1 deletion FWPopupView/FWPopupView/FWDemoViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class FWDemoViewController: UITableViewController {
var alertImage: FWAlertView!

/// 注意:这边不同的示例可能还附加演示了一些特性(比如:遮罩层是否能够点击、遮罩层的背景颜色等等),有用到时可以参考
var titleArray = ["Alert - 单个按钮", "Alert - 两个按钮", "Alert - 两个按钮(修改参数)", "Alert - 多个按钮", "Alert - 带输入框", "Alert - 带自定义视图", "Sheet - 少量Item", "Sheet - 大量Item", "Date - 自定义日期选择", "Menu - 自定义菜单", "Custom - 自定义弹窗"]
var titleArray = ["Alert - 单个按钮", "Alert - 两个按钮", "Alert - 两个按钮(修改参数)", "Alert - 多个按钮", "Alert - 带输入框", "Alert - 带自定义视图", "Sheet - 少量Item", "Sheet - 大量Item", "Date - 自定义日期选择", "Menu - 自定义菜单", "Custom - 自定义弹窗", "RadioButton"]

let block: FWPopupItemClickedBlock = { (popupView, index, title) in
print("AlertView:点击了第\(index)个按钮")
Expand Down Expand Up @@ -48,6 +48,11 @@ extension FWDemoViewController {
cell.textLabel?.numberOfLines = 0
if indexPath.row == 9 || indexPath.row == 10 {
cell.accessoryType = .disclosureIndicator
} else if indexPath.row == 11 {
let property = FWRadioButtonProperty()
property.selectedStateColor = UIColor.red
property.buttonType = .rectangle
cell.accessoryView = FWRadioButton.radio(frame: CGRect(x: 0, y: 0, width: 25, height: 25), property: property)
} else {
cell.accessoryType = .none
}
Expand Down Expand Up @@ -179,6 +184,9 @@ extension FWDemoViewController {
break
case 10:
self.navigationController?.pushViewController(FWCustomPopupDemoVC(), animated: true)
break
case 11:

break
default:
break
Expand Down
2 changes: 1 addition & 1 deletion FWPopupView/FWPopupView/FWPopupView/FWMenuView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Created by xfg on 2018/5/19.
// Copyright © 2018年 xfg. All rights reserved.
//
// 仿QQ、微信菜单

/** ************************************************
Expand Down
4 changes: 2 additions & 2 deletions FWPopupView/FWPopupView/FWPopupView/FWPopupView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Created by xfg on 2018/3/19.
// Copyright © 2018年 xfg. All rights reserved.
//
// 弹窗基类

/** ************************************************
Expand Down Expand Up @@ -714,7 +714,7 @@ extension FWPopupView {
}


// MARK: - 弹窗的的相关配置属性
// MARK: - 弹窗的相关配置属性
open class FWPopupViewProperty: NSObject {

/// 标题字体大小
Expand Down
2 changes: 1 addition & 1 deletion FWPopupView/FWPopupView/FWPopupView/FWPopupWindow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Created by xfg on 2018/3/19.
// Copyright © 2018年 xfg. All rights reserved.
//
// 弹窗window

/** ************************************************
Expand Down
220 changes: 220 additions & 0 deletions FWPopupView/FWPopupView/FWPopupView/FWRadioButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
//
// FWRadioButton.swift
// FWPopupView
//
// Created by xfg on 2018/10/10.
// Copyright © 2018年 xfg. All rights reserved.
// 单选按钮

import Foundation
import UIKit

/// 类型
///
/// - circular: 圆形,默认
/// - rectangle: 正方形,可设置圆角值
/// - image: 图片类型
@objc public enum FWRadioButtonType: Int {
case circular
case rectangle
case image
}

open class FWRadioButton : UIView {

@objc public var vProperty : FWRadioButtonProperty!

private var borderLayer: CAShapeLayer?
private var insideLayer: CAShapeLayer?

@objc public var isSelected : Bool = false {
willSet {
if self.vProperty.buttonType == .image {
self.drawWithSelection(selected: newValue)
} else {
self.setNeedsDisplay()
}
}
}

@objc open class func radio(frame: CGRect, property : FWRadioButtonProperty) -> FWRadioButton {

let radio = FWRadioButton()
radio.setupUI(frame: frame, property: property)
return radio
}
}

extension FWRadioButton {

private func setupUI(frame: CGRect, property: FWRadioButtonProperty?) {

self.frame = frame
self.backgroundColor = UIColor.clear

if property != nil {
self.vProperty = property
} else {
self.vProperty = FWRadioButtonProperty()
}

self.isUserInteractionEnabled = true
let tapGest = UITapGestureRecognizer(target: self, action: #selector(tapGesClick(tap:)))
self.addGestureRecognizer(tapGest)
}

/// 点击手势
///
/// - Parameter tap: 手势
@objc private func tapGesClick(tap: UITapGestureRecognizer) {

self.isSelected = !self.isSelected
}

/// 图片类型的切换
///
/// - Parameter selected: true:选中
private func drawWithSelection(selected: Bool) {

if selected {

} else {

}
}

/// 除图片类型外的绘制过程
///
/// - Parameter rect: rect
open override func draw(_ rect: CGRect) {

if self.borderLayer != nil {
self.borderLayer?.removeFromSuperlayer()
}
if self.insideLayer != nil {
self.insideLayer?.removeFromSuperlayer()
}

self.drawBorder(rect)
if self.isSelected {
self.drawInside(rect)
}

if self.vProperty.isAnimated && self.vProperty.animationDuration > 0 {
self.isUserInteractionEnabled = false
DispatchQueue.main.asyncAfter(deadline: .now()+self.vProperty.animationDuration) {
self.isUserInteractionEnabled = true
}
}
}

/// 绘制边框
///
/// - Parameter rect: frame
private func drawBorder(_ rect: CGRect) {

// 边框
let center = CGPoint(x: rect.width/2, y: rect.height/2)
var borderPath : UIBezierPath!

switch self.vProperty.buttonType {
case .circular:
borderPath = UIBezierPath(arcCenter: center, radius: rect.width*0.5-self.vProperty.lineWidth, startAngle: 0, endAngle: CGFloat(Double.pi*2), clockwise: true)
break
case .rectangle:
borderPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: rect.width-self.vProperty.lineWidth, height: rect.height-self.vProperty.lineWidth))
break

default: break

}

self.borderLayer = CAShapeLayer()
self.layer.addSublayer(self.borderLayer!)
self.borderLayer!.frame = CGRect(x: 0, y: 0, width: rect.width, height: rect.height)
self.borderLayer!.path = borderPath.cgPath
self.borderLayer!.lineWidth = self.vProperty.lineWidth
self.borderLayer!.strokeColor = self.isSelected ? self.vProperty.selectedStateColor.cgColor : self.vProperty.normalStateColor.cgColor
self.borderLayer!.fillColor = UIColor.clear.cgColor
}

/// 绘制内部选中状态
///
/// - Parameter rect: frame
private func drawInside(_ rect: CGRect) {

// 选中
let width = floor((rect.width - self.vProperty.lineWidth*2) * self.vProperty.insideMarginRate)

var insidePath : UIBezierPath!

switch self.vProperty.buttonType {
case .circular:
insidePath = UIBezierPath(ovalIn: CGRect(x: (self.frame.width-width)/2, y: (self.frame.width-width)/2, width: width, height: width))
break
case .rectangle:
let ipWidth = (rect.width-self.vProperty.lineWidth)*self.vProperty.insideMarginRate
let ipHeight = (rect.height-self.vProperty.lineWidth)*self.vProperty.insideMarginRate

insidePath = UIBezierPath(rect: CGRect(x: (rect.width-ipWidth-self.vProperty.lineWidth)/2, y: (rect.height-ipHeight-self.vProperty.lineWidth)/2, width: ipWidth, height: ipHeight))
break

default: break

}

self.insideLayer = CAShapeLayer()
self.layer.addSublayer(self.insideLayer!)
self.insideLayer!.frame = CGRect(x: 0, y: 0, width: width, height: width)
self.insideLayer!.path = insidePath.cgPath
self.insideLayer!.lineWidth = 0
self.insideLayer!.fillColor = self.vProperty.selectedStateColor.cgColor

let scaleValue = NSNumber(value: ((self.isSelected) ? 1 : 0))
if self.isSelected && self.vProperty.isAnimated {
let animation = CABasicAnimation(keyPath: "transform.scale")
animation.toValue = scaleValue
animation.duration = self.vProperty.animationDuration
self.insideLayer?.add(animation, forKey: "scale")
}
self.insideLayer?.transform = CATransform3DMakeScale(CGFloat(scaleValue.floatValue), CGFloat(scaleValue.floatValue), 0)
}
}



// MARK: - 单选按钮的相关配置属性
open class FWRadioButtonProperty: NSObject {

/// 未选中时的颜色
@objc open var normalStateColor: UIColor = kPV_RGBA(r: 51, g: 51, b: 51, a: 1)
/// 选中时的颜色
@objc open var selectedStateColor: UIColor = kPV_RGBA(r: 51, g: 51, b: 51, a: 1)

/// 按钮类型
@objc open var buttonType : FWRadioButtonType = .circular
/// 是否需要动画
@objc public var isAnimated : Bool = true
/// 动画所需的时间
@objc open var animationDuration: TimeInterval = 0.2

/// 圆角值,注意:当 buttonType == .circular 时无效
@objc public var radius: CGFloat = 0
/// 边的宽度
@objc public var lineWidth: CGFloat = 2

/// 内部选中状态的宽度与内边框的比例
@objc public var insideMarginRate: CGFloat = 0.6


public override init() {
super.init()

self.reSetParams()
}

/// 如果发现部分属性设置后没有生效,可执行该方法
@objc public func reSetParams() {

}
}

0 comments on commit 721d40e

Please sign in to comment.