写在前面
说明一下为什么使用UIControl来封装控件。
a.从需求方面来看,这个控件不仅仅是展示内容,有可能需要实现点击事件。
b.这个控件有可能存在选中状态和未选中状态等各种状态。
c.当这个控件的尺寸过大时,我们有可能需要控件的内容实现居上、居中、居下、居左、居右 and so on.UIControl相对于UIView的优点。
众所周知,UIButton继承自UIControl.
A、查看UIControl的API,可以发现如下内容:
contentVerticalAlignment、contentHorizontalAlignment就是1中说的居上、居中、居下、居左、居右 。
@property(nonatomic,getter=isSelected) BOOL selected;
@property(nonatomic,getter=isHighlighted) BOOL highlighted;
@property(nonatomic) UIControlContentVerticalAlignment contentVerticalAlignment;
@property(nonatomic) UIControlContentHorizontalAlignment contentHorizontalAlignment;
- (void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
- UIButton类,我们想要做到实现点击事件以及选中等各种状态下的样式,可以参考UIButton的API进行封装。说白了,就是提供给外界使用的方法
- (void)setTitle:(nullable NSString *)title forState:(UIControlState)state; // default is nil. title is assumed to be single line
- (void)setTitleColor:(nullable UIColor *)color forState:(UIControlState)state;
- (void)setImage:(nullable UIImage *)image forState:(UIControlState)state;
通过上述内容,应该总结UIControl以及UIButton的API方法,进行封装。
代码以及相关说明:
.h文件
.h文件提供了控件的Label以及ImageView属性。
同事实现了UIButton相似的方法以及快捷设置
(void)setImage:(UIImage*)image andTitleLableText:(NSString*)title
#import <UIKit/UIKit.h>
/** 上图下文组件 */
@interface RjxImageTitleView : UIControl
///上面图片
@property (nonatomic,strong) UIImageView *topImageView;
///下面文本
@property (nonatomic,strong) UILabel *titleLable;
///中间间隔
@property (nonatomic,assign) CGFloat spaceBetweenTitleAndImage;
/**
* @description 根据不同状态设置下面文本的值
* @param title 文本内容 可以为空
* @Param state UIControlState 枚举类型 状态值
*/
- (void)setTitle:(NSString *)title forState:(UIControlState)state;
/**
* @description 根据不同状态设置下面文本的颜色
* @param title 颜色
* @Param state UIControlState 枚举类型 状态值
*/
- (void)setTitleColor:(UIColor *)color forState:(UIControlState)state;
/**
* @description 根据不同状态设置图片
* @param image 图片
* @Param state UIControlState 枚举类型 状态值
*/
- (void)setImage:(UIImage *)image forState:(UIControlState)state;
/**
* @description 快捷设置上面图片和下面文本的值 这个时候状态默认为 UIControlStateNormal
* @param image 图片
* @Param title 文本的值
*/
- (void)setImage:(UIImage*)image andTitleLableText:(NSString*)title;
@end
///用于记录一些属性 当控件在不同状态的时候
@interface RjxImageTitleModel : NSObject
@property (nonatomic,strong) NSString *strTitle;
@property (nonatomic,strong) UIColor *color;
@property (nonatomic,strong) UIImage *image;
@end
.m文件
.m文件内容较多。望仔细阅读,
[NSLayoutConstraint activateConstraints:activeConstraints];激活某些约束
[NSLayoutConstraint deactivateConstraints:activeConstraints];关闭某些约束
#import "RjxImageTitleView.h"
@interface RjxImageTitleView()
//字典记录相应属性和对应的值 值应该是 key @(UIControlState) value : RjxImageTitleModel
@property (nonatomic,strong) NSMutableDictionary *dicProperty;
//底部标题距离上面图片的高度
@property (nonatomic,strong) NSLayoutConstraint *titleLableTopConstraint;
@property (nonatomic,strong) NSDictionary *contentViewHorizontalConstraints;
@property (nonatomic,strong) NSDictionary *contentViewVerticalConstraints;
@end
@implementation RjxImageTitleView
- (instancetype)init
{
self = [super init];
if (self) {
[self initView];
}
return self;
}
- (void)setSpaceBetweenTitleAndImage:(CGFloat)spaceBetweenTitleAndImage
{
if (spaceBetweenTitleAndImage == _spaceBetweenTitleAndImage) {
return;
}
_spaceBetweenTitleAndImage = spaceBetweenTitleAndImage;
self.titleLableTopConstraint.constant = _spaceBetweenTitleAndImage;
}
//初始化控件
- (void)initView
{
//
_spaceBetweenTitleAndImage = 2.;
UIView *contentView = [[UIView alloc] init];
[self addSubview:contentView];
contentView.backgroundColor = [UIColor yellowColor];
//使用NSLayoutConstraint添加约束
NSLayoutConstraint *constraint_top_greater = [NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1 constant:0];
NSLayoutConstraint *constraint_left_greater = [NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:0];
NSLayoutConstraint *constraint_bottom_less = [NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
NSLayoutConstraint *constraint_right_less = [NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1 constant:0];
// 一些位置约束 这里的约束就是用于contentVerticalAlignment和contentHorizontalAlignment来控制位置
NSLayoutConstraint *contentView_constraint_centerX = [contentView addCenterX:0 toView:self];
NSLayoutConstraint *contentView_constraint_centerY = [contentView addCenterY:0 toView:self];
NSLayoutConstraint *contentView_constraint_left = [contentView leftToView:self withSpace:0];
NSLayoutConstraint *contentView_constraint_right = [contentView rightToView:self withSpace:0];
NSLayoutConstraint *contentView_constraint_top = [contentView topToView:self withSpace:0];
NSLayoutConstraint *contentView_constraint_bottom = [contentView bottomToView:self withSpace:0];
// 这里分为横向纵向,分别将对用的值保存起来,
self.contentViewHorizontalConstraints = @{
@(UIControlContentHorizontalAlignmentCenter):contentView_constraint_centerX,
@(UIControlContentHorizontalAlignmentLeft):contentView_constraint_left,
@(UIControlContentHorizontalAlignmentRight):contentView_constraint_right,
};
self.contentViewVerticalConstraints = @{
@(UIControlContentVerticalAlignmentCenter):contentView_constraint_centerY,
@(UIControlContentVerticalAlignmentTop):contentView_constraint_top,
@(UIControlContentVerticalAlignmentBottom):contentView_constraint_bottom,
};
[self addConstraints:@[
constraint_top_greater,
constraint_left_greater,
constraint_bottom_less,
constraint_right_less,
]];
//
[contentView addSubview:self.topImageView];
[self.topImageView topToView:contentView withSpace:0];
[self.topImageView addCenterX:0 toView:contentView];
[contentView addConstraints:@[
[NSLayoutConstraint constraintWithItem:self.topImageView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:contentView attribute:NSLayoutAttributeLeft multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:self.topImageView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationLessThanOrEqual toItem:contentView attribute:NSLayoutAttributeRight multiplier:1 constant:0]
]];
//正常的约束
[contentView addSubview:self.titleLable];
[self.titleLable bottomToView:contentView withSpace:0];
[self.titleLable addCenterX:0 toView:contentView];
[contentView addConstraints:@[
[NSLayoutConstraint constraintWithItem:self.titleLable attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:contentView attribute:NSLayoutAttributeLeft multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:self.titleLable attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationLessThanOrEqual toItem:contentView attribute:NSLayoutAttributeRight multiplier:1 constant:0]
]];
//这里是绑定上下控件间隙
self.titleLableTopConstraint = [self.topImageView bottomToView:self.titleLable withSpace:self.spaceBetweenTitleAndImage];
/// 设置默认
self.contentVerticalAlignment = self.contentVerticalAlignment;
self.contentHorizontalAlignment = self.contentHorizontalAlignment;
}
- (void)setContentHorizontalAlignment:(UIControlContentHorizontalAlignment)contentHorizontalAlignment
{
//需要调用super 不然不会执行
[super setContentHorizontalAlignment:contentHorizontalAlignment];
[self setContentViewHorizontalPosition];
}
- (void)setContentVerticalAlignment:(UIControlContentVerticalAlignment)contentVerticalAlignment
{
[super setContentVerticalAlignment:contentVerticalAlignment];
[self setContentViewVerticalPosition];
}
/***
*设置contentview 的位置 九宫格 九种位置 6大属性决定
*/
- (void)setContentViewHorizontalPosition
{
//全部设置为不激活状态
[NSLayoutConstraint deactivateConstraints:self.contentViewHorizontalConstraints.allValues];
NSMutableArray *activeConstraints = [[NSMutableArray alloc] init];
//横向
if (self.contentHorizontalAlignment == UIControlContentHorizontalAlignmentFill) {
[activeConstraints addObject:[self.contentViewHorizontalConstraints objectForKey:@(UIControlContentHorizontalAlignmentLeft)]];
[activeConstraints addObject:[self.contentViewHorizontalConstraints objectForKey:@(UIControlContentHorizontalAlignmentRight)]];
}else{
[activeConstraints addObject:[self.contentViewHorizontalConstraints objectForKey:@(self.contentHorizontalAlignment)]];
}
[NSLayoutConstraint activateConstraints:activeConstraints];
}
/***
*设置contentview 的位置 九宫格 九种位置 6大属性决定
*/
- (void)setContentViewVerticalPosition
{
//全部设置为不激活状态
[NSLayoutConstraint deactivateConstraints:self.contentViewVerticalConstraints.allValues];
NSMutableArray *activeConstraints = [[NSMutableArray alloc] init];
//纵向
if (self.contentVerticalAlignment == UIControlContentVerticalAlignmentFill) {
[activeConstraints addObject:[self.contentViewVerticalConstraints objectForKey:@(UIControlContentVerticalAlignmentTop)]];
[activeConstraints addObject:[self.contentViewVerticalConstraints objectForKey:@(UIControlContentVerticalAlignmentBottom)]];
}else{
[activeConstraints addObject:[self.contentViewVerticalConstraints objectForKey:@(self.contentVerticalAlignment)]];
}
[NSLayoutConstraint activateConstraints:activeConstraints];
}
- (void)setSelected:(BOOL)selected
{
[super setSelected:selected];
UIControlState state = UIControlStateNormal;
if (selected) {
state = UIControlStateSelected;
}else{
state = UIControlStateNormal;
}
RjxImageTitleModel *model = [self getValueFromDicPropertyforKey:state];
[self setImage:model.image andTitleLableText:model.strTitle];
[self setTitleColor:model.color forState:UIControlStateSelected];
}
- (void)setHighlighted:(BOOL)highlighted
{
}
/**
* @description 根据key获取值
* @return RjxImageTitleModel 返回对应key的实体值
*/
- (RjxImageTitleModel*)getValueFromDicPropertyforKey:(UIControlState)state
{
RjxImageTitleModel *model = nil;
if (![self.dicProperty objectForKey:@(state)]) {
model = [[RjxImageTitleModel alloc] init];
[self.dicProperty setObject:model forKey:@(state)];
}
return model;
}
- (void)setTitle:(NSString *)title forState:(UIControlState)state
{
if (title) {
self.titleLable.text = title;
RjxImageTitleModel *model = [self getValueFromDicPropertyforKey:state];
model.strTitle = title;
}
}
- (void)setTitleColor:(UIColor *)color forState:(UIControlState)state
{
if (color) {
self.titleLable.textColor = color;
RjxImageTitleModel *model = [self getValueFromDicPropertyforKey:state];
model.color = color;
}
}
- (void)setImage:(UIImage *)image forState:(UIControlState)state
{
if (image) {
self.topImageView.image = image;
RjxImageTitleModel *model = [self getValueFromDicPropertyforKey:state];
model.image = image;
}
}
- (void)setImage:(UIImage*)image andTitleLableText:(NSString*)title
{
[self setImage:image forState:UIControlStateNormal];
[self setTitle:title forState:UIControlStateNormal];
}
/**属性懒加载**/
- (UIImageView *)topImageView
{
if (!_topImageView) {
_topImageView = [[UIImageView alloc] init];
}
return _topImageView;
}
- (UILabel *)titleLable
{
if (!_titleLable) {
_titleLable = [[UILabel alloc] init];
}
return _titleLable;
}
- (NSMutableDictionary *)dicProperty
{
if (!_dicProperty) {
_dicProperty = [[NSMutableDictionary alloc] init];
}
return _dicProperty;
}
@end
@implementation RjxImageTitleModel
@end
效果如下图:
调用方式如下图:
注意红色框内
如果不设置红色框内的两个值:默认是居中的。