有个需求是这样的,有一个lable在一个button点击后,内容发生改变,相关尺寸也要发生改变,想要那个点击的buton位置跟随lable的位置发生同步变化。
开始的思路是在button点击执行的方法中更新相关约束,位置更新的没有达到想要的效果。就是lable的text属性改变后,button的位置约束就更新了,而现在的lable的bounds还没有变化,或者变化没有完成。这样button相对的更新的位置就是没有完全更新完的lable的位置为基准。所以没有达到效果。
这个时候想着换用添加观察者模式,当lable的bounds发生改变后,button的相对约束再更新。由于lable是系统空间,不方便直接增加功能。我这边选择一个比较好实现的方式,从新创建一个类继承自UILable,在自定义lable初始化的方式中添加观察者,观察bounds属性的变化,这时候效果达到了要求。下面是相关代码实现:
在实现上面的想法使用了block作为属性,因为功能单一,使用delegate有点大材小用,也不方便。
***** MyLable.h文件 *****
#import <UIKit/UIKit.h>
@interface MyLable : UILabel
//下面定义了block属性,确定当lable的bounds属性发生改变后将要做什么操作
@property (nonatomic,copy) void (^change)();
@end
***** MyLable.m文件 *****
#import "MyLable.h"
@implementation MyLable
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
//稍微对标签做了下美化,有圆角
self.layer.cornerRadius = 5;
self.layer.masksToBounds = YES;
//添加对bounds属性的观察
[self addObserver:self forKeyPath:@"bounds" options:NSKeyValueObservingOptionNew||NSKeyValueChangeOldKey context:nil];
}
//实现观察者模式需要实现的方法,调用改变后定义的block属性,做到改变后,
//完成需要的相关动作
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
self.change();
NSLog(@"%@",change);
}
//注意在这个方法中移除观察者,不然会发生错误。
-(void)dealloc{
[self removeObserver:self forKeyPath:@"bounds"];
}
@end
下面是viewController.m
方法
//中间约束使用了Masonry第三方库,比较方便。可以使用cocopods导入到项目中使用。
#import "ViewController.h"
#import <Masonry/Masonry.h>
#import "MyLable.h"
@interface ViewController ()
//因为需要在更新位置,使用到控件,便放到属性,方便使用
@property (nonatomic,strong)MyLable* lb;
@property (nonatomic,strong)UIButton* bt;
//这个是为了点击后,有不同的效果,设置的一个变量
@property (nonatomic) BOOL ag;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.ag = YES;
MyLable* lable = [[MyLable alloc]init];
lable.lineBreakMode = NSLineBreakByWordWrapping;
lable.numberOfLines = 0;
lable.text = @"这世界很复杂,混淆我想说的话我不懂,太复杂的玩法,什么样的礼物,能够永远记得住让幸福别走的太仓促,云和天,蝶和花,从来不需要说话,断不了依然日夜牵挂唱情歌,说情话,只想让你听清楚,我爱你是唯一的倾诉";
lable.font = [UIFont systemFontOfSize:18];
lable.textColor = [UIColor redColor];
lable.backgroundColor = [UIColor grayColor];
self.lb = lable;
float scw = [[UIScreen mainScreen]bounds].size.width;
[self.view addSubview:lable];
[self.lb mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(40);
make.width.mas_equalTo(scw-scw/4);
make.centerX.mas_equalTo(0);
}];
//用这个方法实现button的添加,可以达到在lable完成之后,button的相对位置才能正确。
[self performSelectorOnMainThread:@selector(addButton) withObject:nil waitUntilDone:NO];
}
-(void)addButton{
UIButton* button =[UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:@"点击" forState:UIControlStateNormal];
//为button添加点击响应方法,在响应方法中确定约束更新。
[button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor = [UIColor grayColor];
self.bt = button;
self.bt.titleLabel.textColor = [UIColor blackColor];
//避免循环引用的问题,为我自定义的MyLable对象的block属性实现方法。
__block typeof(self) weakself = self;
self.lb.change = ^(){
[weakself.bt mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.lb.bounds.size.height+50);
make.centerX.mas_equalTo(0);
}];
};
self.bt.layer.cornerRadius = 10;
self.bt.layer.masksToBounds = YES;
[self.view addSubview:button];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.lb.bounds.size.height+50);
make.width.mas_equalTo(100);
make.centerX.mas_equalTo(0);
}];
}
-(void)click{
self.ag = !self.ag;
if (self.ag) {
self.lb.text = @"我是第二个内容,我已经变化了";
}else{
self.lb.text = @"啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢uuuuuuuuuuuuuuuuuuuuuuuuuuuu";
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
好了,到这里,这个需求已经能满足了。其他更好的办法还没有想到,想到了再更新,如果有哪个高手有更好的方式,可以给我留言。