iOS 重构: 视图子元素动态化
2020-06-26 本文已影响0人
SoaringHeart
当我们布局时,总需要布局各种各样的子视图(UIView/UIImageView/UIButton/UIlabel 及其子类),随思考有没有一种方法通过字符串/类型为参数生成子视图的方法实现,然后子视图还可以二次属性设置,经过不断(半年时间)思考,然后在一个周末,灵光一闪,在 swift 中泛型首先突破实现预期效果,(以九宫格视图为例)代码如下:
//
// UIView+Add.swift
// SwiftTemplet
//
// Created by Bin Shang on 2018/8/27.
// Copyright © 2018年 BN. All rights reserved.
//
import UIKit
public extension UIView{
///更新各种子视图
///更新各种子视图
final func updateItems<T: UIView>(_ count: Int, type: T.Type, hanler: ((T) -> Void)) -> [T] {
if count == 0 {
return []
}
if let list = self.subviews.filter({ $0.isMember(of: type) }) as? [T] {
if list.count == count {
list.forEach { hanler($0) }
return list
}
}
subviews.filter { $0.isMember(of: type) }.forEach { $0.removeFromSuperview() }
var arr: [T] = [];
for i in 0..<count {
let subview = type.init()
subview.tag = i
self.addSubview(subview)
arr.append(subview)
hanler(subview)
}
return arr;
}
///更新各种子类按钮
final func updateButtonItems<T: UIButton>(_ count: Int, type: T.Type, hanler: ((T) -> Void)) -> [T] {
return updateItems(count, type: type) {
if $0.title(for: .normal) == nil {
$0.titleLabel?.font = UIFont.systemFont(ofSize: 15)
$0.setTitle("\(type)\($0.tag)", for: .normal)
$0.setTitleColor(.black, for: .normal)
$0.setBackgroundColor(.gray, for: .disabled)
}
hanler($0)
}
}
🌰🌰:
//
// UITableViewCellSudokuButton.swift
// SwiftTemplet
//
// Created by Bin Shang on 2020/6/19.
// Copyright © 2020 BN. All rights reserved.
//
import UIKit
///九宫格
@objcMembers class UITableViewCellSudokuButton: UITableViewCell {
var numOfRow: Int = 3
var row: Int = 3
var inset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
var itemType: UIButton.Type = UIButton.self
// MARK: -lazy
lazy var items: [UIButton] = {
return self.contentView.updateItems(self.row*self.numOfRow, type: self.itemType) {
$0.titleLabel?.font = UIFont.systemFont(ofSize: 15)
$0.setTitle("\(self.itemType)\($0.tag)", for: .normal)
$0.setTitleColor(.systemBlue, for: .normal)
}
}()
// MARK: -life cycle
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier);
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder);
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews();
setupConstraint()
}
func setupConstraint() {
if bounds.height <= 0.0 {
return;
}
items.snp.distributeSudokuViews(fixedLineSpacing: 5, fixedInteritemSpacing: 10, warpCount: numOfRow, edgeInset: inset)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
// MARK: -funtions
}
Objc 版本:
//
// UIView+Ext.m
// Xcode11Project
//
// Created by Bin Shang on 2020/6/25.
// Copyright © 2020 Bin Shang. All rights reserved.
//
#import "UIView+Ext.h"
#import "NSArray+Ext.h"
@implementation UIView (Ext)
- (NSArray<__kindof UIView *> *)updateItems:(NSInteger)count aClassName:(NSString *)aClassName handler:(void(^)(__kindof UIView *obj))handler {
if (count == 0) {
return @[];
}
Class cls = NSClassFromString(aClassName);
NSArray *list = [self.subviews filter:^BOOL(UIView * obj, NSUInteger idx) {
return [obj isKindOfClass:cls.class];
}];
if (list.count == count) {
[list enumerateObjectsUsingBlock:^(UIView * obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (handler) {
handler(obj);
}
}];
return list;
}
for (UIView *view in self.subviews) {
if ([view isMemberOfClass:cls]) {
[view removeFromSuperview];
}
}
NSMutableArray *marr = [NSMutableArray array];
for (NSInteger i = 0; i < count; i++) {
UIView *subview = [[cls alloc]init];
subview.tag = i;
[self addSubview:subview];
[marr addObject:subview];
if (handler) {
handler(subview);
}
}
return marr;
}
- (NSArray<__kindof UIButton *> *)updateButtonItems:(NSInteger)count aClassName:(NSString *)aClassName handler:(void(^)(__kindof UIButton *obj))handler {
return [self updateItems:count aClassName:aClassName handler:^(__kindof UIView * _Nonnull obj) {
if (![obj isKindOfClass:UIButton.class]) {
return;
}
// NSString *clsName = NSStringFromClass(obj.class);
UIButton *sender = (UIButton *)obj;
if (![sender titleForState:UIControlStateNormal]) {
sender.titleLabel.font = [UIFont systemFontOfSize:15];
NSString *title = [NSString stringWithFormat:@"%@%@", aClassName, @(obj.tag)];
[sender setTitle:title forState:UIControlStateNormal];
[sender setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
}
if (handler) {
handler(obj);
}
}];
}
@end
//
// NSArray+Ext.m
// Xcode11Project
//
// Created by Bin Shang on 2020/6/20.
// Copyright © 2020 Bin Shang. All rights reserved.
//
#import "NSArray+Ext.h"
@implementation NSArray (Ext)
- (NSArray *)map:(id (^)(id obj, NSUInteger idx))handler{
__block NSMutableArray *marr = [NSMutableArray array];
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (handler) {
id blockResult = handler(obj, idx) ? : obj;
[marr addObject:blockResult];
}
}];
// DDLog(@"%@->%@", self, marr.copy);
return marr.copy;
}
- (NSArray *)filter:(BOOL(^)(id obj, NSUInteger idx))handler{
__block NSMutableArray *marr = [NSMutableArray array];
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (handler && handler(obj, idx) == true) {
[marr addObject:obj];
}
}];
return marr.copy;
}
- (NSNumber *)reduce:(NSNumber *(^)(NSNumber *num1, NSNumber *num2))handler{
__block CGFloat result = 0.0;
[self enumerateObjectsUsingBlock:^(NSNumber *_Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (idx < self.count - 1) {
NSNumber *num1 = idx == 0 ? obj : @(result);
NSNumber *num2 = self[idx+1];
if (handler) {
result = handler(num1, num2).floatValue;
// DDLog(@"handler_%@_%@_%@_%@",num1, num2, handler(num1, num2), @(result));
}
}
}];
return @(result);
}
@end
🌰🌰:
//
// NNHomeViewController.m
// MasonryExtend_Example
//
// Created by Bin Shang on 2019/12/13.
// Copyright © 2019 shang1219178163. All rights reserved.
//
#import "NNHomeViewController.h"
//#import "Masonry.h"
#import "MasonryExtend.h"
#import "UIView+Ext.h"
#import "UIButton+Ext.h"
@interface NNHomeViewController ()
@end
@implementation NNHomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.edgesForExtendedLayout = UIRectEdgeNone;
self.title = @"Sudoku";
NSArray *list = [self.view updateItems:9 aClassName:@"NXButton" handler:^(UIView * _Nonnull obj) {
if (![obj isKindOfClass:UIButton.class]) {
return;
}
NSString *clsName = NSStringFromClass(obj.class);
UIButton *sender = (UIButton *)obj;
sender.titleLabel.font = [UIFont systemFontOfSize:15];
NSString *title = [NSString stringWithFormat:@"%@%@", clsName, @(obj.tag)];
[sender setTitle:title forState:UIControlStateNormal];
[sender setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
[sender setBackgroundColor:UIColor.whiteColor forState:UIControlStateNormal];
[sender setBackgroundColor:UIColor.systemBlueColor forState:UIControlStateHighlighted];
[sender setBackgroundColor:UIColor.grayColor forState:UIControlStateDisabled];
}];
[list mas_distributeSudokuViewsWithFixedLineSpacing:5
fixedInteritemSpacing:5
warpCount:3
inset:UIEdgeInsetsMake(10, 10, 10, 10)];
// [list mas_distributeSudokuViewsWithFixedItemWidth:120
// fixedItemHeight:120
// warpCount:3
// inset:UIEdgeInsetsMake(10, 10, 10, 10)];
self.view.backgroundColor = UIColor.systemGreenColor;
}
@end
Simulator Screen Shot - iPhone 6s Plus - 2020-06-25 at 16.22.20.png
Simulator Screen Shot - iPhone 6s Plus - 2020-06-25 at 16.22.47.png