在下小白一个,准备写写和自己开发息息相关的控件,希望大家批评指正。这是第一个常用的底部弹窗,使用了最简单的分装方式。适合新人使用,分装的不是很完全,使用者可以自己进行修改参数。
废话不多说先上代码
1、头文件里面声明了一个代理和初始化方法。
#import <UIKit/UIKit.h>
@class WDActionSheet;
@protocol WDActionSheetDelegate
- (void)selectedIndex:(NSInteger)index;
@end
@interface WDActionSheet : UIView
@property (nonatomic, weak) id <WDActionSheetDelegate> delegate;
// 单例
+ (instancetype)shareInstances;
/**
初始化ActionSheet
@param titleArray 标题文字数组---不能为空
@param cancelButtonTitle 取消按钮文字---可以为空
@param selectDelegate 代理
*/
- (void)setUIWithTitleArray:(NSArray<NSString *> *)titleArray
cancelButtonTitle:(NSString *)cancelButtonTitle
selectDelegate:(id <WDActionSheetDelegate>)selectDelegate;
@end
2、实现文件里面进行页面的绘制、数据处理和事件处理。
#import "WDActionSheet.h"
#define Sheet_IS_iPhoneX ([UIScreen mainScreen].bounds.size.width == 375 && [UIScreen mainScreen].bounds.size.height == 812)
#define Sheet_IPHONEX_MARGIN_BOTTOM (34)
#define Sheet_ScreenWidth UIScreen.mainScreen.bounds.size.width
#define Sheet_ScreenHeight UIScreen.mainScreen.bounds.size.height
typedef void (^ClickHandler)(NSInteger index);
@interface WDActionSheet ()<UIGestureRecognizerDelegate>
// 背景页面
@property (nonatomic, strong) UIView *containerView;
@end
@implementation WDActionSheet
#pragma mark -- 单例初始化
+ (instancetype)shareInstances{
static WDActionSheet* single;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
single = [[WDActionSheet alloc] init];
});
return single;
}
#pragma mark -- 捕捉错误
- (void)setUIWithTitleArray:(NSArray<NSString *> *)titleArray cancelButtonTitle:(NSString *)cancelButtonTitle selectDelegate:(id<WDActionSheetDelegate>)selectDelegate{
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(dismissView)];
tap.delegate = self;
[self addGestureRecognizer:tap];
@try {
if(titleArray.count == 0) {
@throw [NSException exceptionWithName:NSStringFromClass([self class])
reason:@"标题数组不能为空"
userInfo:nil];
} else if (selectDelegate == nil) {
@throw [NSException exceptionWithName:NSStringFromClass([self class])
reason:@"未设置代理对象"
userInfo:nil];
} else {
[self createUIWithTitleArray:titleArray cancelButtonTitle:cancelButtonTitle selectDelegate:selectDelegate];
}
} @catch (NSException *exception) {
@throw exception;
} @finally {
}
}
#pragma mark -- 进行页面绘制
- (void)createUIWithTitleArray:(NSArray<NSString *> *)titleArray cancelButtonTitle:(NSString *)cancelButtonTitle selectDelegate:(id<WDActionSheetDelegate>)selectDelegate{
self.containerView = [[UIView alloc] init];
CGFloat W = Sheet_ScreenWidth;
CGFloat X = 0;
CGFloat H = 55;
CGFloat Speace = 15;
// 设置了 取消按钮的文字
if(cancelButtonTitle.length > 0) { // 设置取消了按钮
for (int i = 0; i < titleArray.count; i++) {
UIButton *button = [self createButtonWithTitle:titleArray[i] buttonTag:10 + I];
button.frame = CGRectMake(X, H * i, W, H);
if( i > 0 ) {
UIView *line = [self createLine];
line.frame = CGRectMake(X, H * i + 0.5, W, 0.5);
}
}
UIButton *cancalButton = [self createButtonWithTitle:cancelButtonTitle buttonTag:9];
if(Sheet_IS_iPhoneX) {
cancalButton.frame = CGRectMake(X, (H + 0.5) * titleArray.count + Speace , W, H + Sheet_IPHONEX_MARGIN_BOTTOM);
} else {
cancalButton.frame = CGRectMake(X, (H + 0.5) * titleArray.count + Speace , W, H);
}
}else{ // 没有取消按钮
for (int i = 0; i < titleArray.count; i++) {
UIButton *button = [self createButtonWithTitle:titleArray[i] buttonTag:10 + I];
if(i == titleArray.count-1) {
if(Sheet_IS_iPhoneX){
button.frame = CGRectMake(X, H * i , W, H + Sheet_IPHONEX_MARGIN_BOTTOM);
} else {
button.frame = CGRectMake(X, H * i , W, H);
}
} else {
button.frame = CGRectMake(X, H * i, W, H);
}
if( i > 0 ) {
UIView *line = [self createLine];
line.frame = CGRectMake(X, H * i + 0.5, W, 0.5);
}
}
}
self.delegate = selectDelegate;
CGFloat AllHeight = cancelButtonTitle.length > 0 ? (H * (titleArray.count + 1) + 15) : (H * titleArray.count);
if(Sheet_IS_iPhoneX) {
AllHeight += Sheet_IPHONEX_MARGIN_BOTTOM;
}
[self showViewWithHeight:AllHeight];
}
#pragma mark -- 按钮点击事件进行传值
- (void)buttonAction:(UIButton *)sender {
if(sender.tag != 9) {
[self.delegate selectedIndex:sender.tag - 10];
}
[self dismissView];
}
#pragma mark -- 公共创建按钮
- (UIButton *)createButtonWithTitle:(NSString *)title buttonTag:(NSInteger)buttonTag {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:title forState:UIControlStateNormal];
[button sizeToFit];
[button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
button.backgroundColor = UIColor.whiteColor;
button.tag = buttonTag;
[button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
[self.containerView addSubview:button];
return button;
}
#pragma mark -- 公共创建View
- (UIView *)createLine {
UIView *line = [[UIView alloc] init];
line.backgroundColor = UIColor.lightGrayColor;
[self.containerView addSubview:line];
return line;
}
#pragma mark -- 页面显示
- (void)showViewWithHeight:(CGFloat)height {
[UIApplication.sharedApplication.keyWindow addSubview:self];
[self addSubview:self.containerView];
self.frame = UIScreen.mainScreen.bounds;
self.containerView.frame = CGRectMake(0, Sheet_ScreenHeight, Sheet_ScreenWidth, 0);
[UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
self.containerView.frame = CGRectMake(0, Sheet_ScreenHeight-height, Sheet_ScreenWidth, height);
} completion:^(BOOL finished) {
}];
}
#pragma mark -- 页面消失
- (void)dismissView {
[UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.backgroundColor = [UIColor colorWithWhite:0 alpha:0];
self.containerView.frame = CGRectMake(0, Sheet_ScreenHeight, Sheet_ScreenWidth, 0);
} completion:^(BOOL finished) {
[self removeFromSuperview];
[self.containerView removeFromSuperview];
}];
}
@end
3、使用方法,遵循WDActionSheetDelegate
无取消按钮
// cancelButtonTitle可以直接输入空字符串或者nil
[[WDActionSheet shareInstances] setUIWithTitleArray:@[@"拍照",@"打开相册"] cancelButtonTitle:@"" selectDelegate:self];
带取消按钮
[[WDActionSheet shareInstances] setUIWithTitleArray:@[@"拍照",@"打开相册"] cancelButtonTitle:@"取消" selectDelegate:self];
4、Swift版创建
import UIKit
class WDActionSheet: UIView , UIGestureRecognizerDelegate{
private var containerView : UIView?
private let Sheet_ScreenHeight = UIScreen.main.bounds.size.height
private let Sheet_ScreenWidth = UIScreen.main.bounds.size.width
private var delegate : WDActionSheetDelegate?
// MARK: - 初始化
convenience init(titleArray : Array<String> ,cancelButtonTitle : String , delegate : WDActionSheetDelegate) {
self.init()
let tap:UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(dismissView))
tap.delegate = self
self.addGestureRecognizer(tap)
if titleArray.count == 0 {
fatalError("标题数组不能为空")
} else {
setupUI(titleArray: titleArray, cancelButtonTitle: cancelButtonTitle, delegate: delegate)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - 绘制页面
private func setupUI(titleArray : Array<String> ,cancelButtonTitle : String , delegate : WDActionSheetDelegate) {
containerView = UIView.init()
containerView?.backgroundColor = UIColor.lightGray
let W:CGFloat = Sheet_ScreenWidth
let X:CGFloat = 0
let H:CGFloat = 55
let Speace:CGFloat = 15
if cancelButtonTitle.count == 0 {
for (index, _) in titleArray.enumerated() {
let button = setupButtons(title: titleArray[index], buttonTag: 10+index)
containerView?.addSubview(button)
button.frame = CGRect(x: X, y: H * CGFloat(index), width: W, height: H)
if index == titleArray.count - 1 {
let line = setupLineView()
containerView?.addSubview(line)
line.frame = CGRect(x: X, y: H * CGFloat(index) + 0.5, width: W, height: 0.5)
}
}
} else {
for (index, _) in titleArray.enumerated() {
let button = setupButtons(title: titleArray[index], buttonTag: 10+index)
containerView?.addSubview(button)
button.frame = CGRect(x: X, y: H * CGFloat(index), width: W, height: H)
if index > 0 {
let line = setupLineView()
containerView?.addSubview(line)
line.frame = CGRect(x: X, y: H * CGFloat(index) + 0.5, width: W, height: 0.5)
}
}
let cancalButton = setupButtons(title: cancelButtonTitle, buttonTag: 9)
containerView?.addSubview(cancalButton)
cancalButton.frame = CGRect(x: X, y: (H + 0.5) * CGFloat(titleArray.count) + Speace, width: W, height: H)
}
self.delegate = delegate
var AllHeight:CGFloat = 0.0
if cancelButtonTitle.count > 0 {
AllHeight = H * CGFloat(titleArray.count + 1) + 15.0
} else {
AllHeight = H * CGFloat(titleArray.count)
}
showView(height: AllHeight)
}
// MARK: - 公共创建按钮
private func setupButtons(title : String, buttonTag : Int) -> UIButton {
let button = UIButton.init(type: .custom)
button.sizeToFit()
button.backgroundColor = UIColor.white
button.setTitle(title, for: .normal)
button.setTitleColor(UIColor.black, for: .normal)
button.tag = buttonTag
button.addTarget(self, action: #selector(buttonAction(sender:)), for: .touchUpInside)
return button
}
// MARK: - 公共创建线条
private func setupLineView() -> UIView {
let line = UIView.init()
line.backgroundColor = UIColor.lightGray
return line
}
// MARK: - 点击事件并传值
@objc private func buttonAction(sender : UIButton) {
if sender.tag != 9 {
delegate?.selectedIndex(index: sender.tag)
}
dismissView()
}
// MARK: - 页面显示
private func showView(height:CGFloat) {
UIApplication.shared.keyWindow?.addSubview(self)
addSubview(containerView!)
frame = UIScreen.main.bounds;
containerView?.frame = CGRect(x: 0, y: Sheet_ScreenHeight, width: Sheet_ScreenWidth, height: 0)
UIView.animateKeyframes(withDuration: 0.35, delay: 0, options: .calculationModeLinear, animations: {
self.backgroundColor = UIColor.init(white: 0, alpha: 0.2)
self.containerView?.frame = CGRect(x: 0, y: self.Sheet_ScreenHeight-height, width: self.Sheet_ScreenWidth, height: height)
}, completion: nil)
}
// MARK: - 页面消失
@objc private func dismissView() {
UIView.animateKeyframes(withDuration: 0.35, delay: 0, options: .calculationModeLinear, animations: {
self.backgroundColor = UIColor.init(white: 0, alpha: 0.0)
self.containerView?.frame = CGRect(x: 0, y: self.Sheet_ScreenHeight, width: self.Sheet_ScreenWidth, height: 0)
}) { (finished) in
self.removeFromSuperview()
self.containerView?.removeFromSuperview()
}
}
}
// MARK: - 代理
@objc protocol WDActionSheetDelegate{
func selectedIndex(index:Int) -> Void
}
5、Swift版使用方式,也要遵循WDActionSheetDelegate
WDActionSheet.init(titleArray: ["拍照", "打开相册"], cancelButtonTitle: "取消", delegate: self)
WDActionSheet.init(titleArray: ["拍照", "打开相册"], cancelButtonTitle: "", delegate: self)
6、效果图两个版本现实都是一样的就放一个图了
效果图.gif
7、Demo地址:https://github.com/xlz520/WDActionSheet.git
结尾:有问题希望大家指正!😄😄😄
网友评论