给三方库增加属性

不改动三方库的情况下,利用关联属性扩展三方文件的属性

920 发布: 2025/12/30 06:10 本文总阅读量

使用方式

- (UICollectionViewCell<TYTabPagerBarCellProtocol> *)pagerTabBar:(TYTabPagerBar *)pagerTabBar cellForItemAtIndex:(NSInteger)index {
    // UICollectionViewCell<TYTabPagerBarCellProtocol> *cell = [pagerTabBar dequeueReusableCellWithReuseIdentifier:[TYTabPagerBarCell cellIdentifier] forIndex:index];
    TYTabPagerBarCell *cell = [pagerTabBar dequeueReusableCellWithReuseIdentifier:[TYTabPagerBarCell cellIdentifier] forIndex:index];

    NSDictionary *subDic = _dataArray[index];
    cell.titleLabel.text = [PublicObj hfTitle:subDic];
    if ([PublicObj hfHasImg:subDic]) {
        cell.ty_showImg = YES;
        cell.ty_imgWidth = [PublicObj hfShowWidth:subDic];
        [cell.ty_imageView sd_setImageWithURL:[NSURL URLWithString:[PublicObj hfImgUrl:subDic]]];
    }else {
        cell.ty_showImg = NO;
        cell.ty_imgWidth = 0;
    }
    return cell;
}

给TYTabPagerBarCell增加属性

.h


#import <TYPagerController/TYPagerController.h>
#import <TYPagerController/TYTabPagerBarCell.h>

NS_ASSUME_NONNULL_BEGIN

@interface TYTabPagerBarCell (Bar)

// 新增的图片视图
@property (nonatomic, strong) UIImageView *ty_imageView;
// 控制是否显示图片
@property (nonatomic, assign) BOOL ty_showImg;
// 图片宽度(新增)
@property (nonatomic, assign) CGFloat ty_imgWidth;

@end

NS_ASSUME_NONNULL_END

.m

#import "TYTabPagerBarCell+Bar.h"
#import <objc/runtime.h>
#import <objc/message.h>

// 关联对象key
static const void *TYImageViewKey = &TYImageViewKey;
static const void *TYShowImgKey = &TYShowImgKey;
static const void *TYImgWidthKey = &TYImgWidthKey;

@implementation TYTabPagerBarCell (Bar)

#pragma mark - 关联属性实现
- (UIImageView *)ty_imageView {
    UIImageView *imageView = objc_getAssociatedObject(self, TYImageViewKey);
    if (!imageView) {
        imageView = [[UIImageView alloc] init];
        imageView.contentMode = UIViewContentModeScaleAspectFit;
        [self.contentView addSubview:imageView];
        objc_setAssociatedObject(self, TYImageViewKey, imageView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return imageView;
}

- (void)setTy_imageView:(UIImageView *)ty_imageView {
    objc_setAssociatedObject(self, TYImageViewKey, ty_imageView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)ty_showImg {
    return [objc_getAssociatedObject(self, TYShowImgKey) boolValue];
}

- (void)setTy_showImg:(BOOL)ty_showImg {
    objc_setAssociatedObject(self, TYShowImgKey, @(ty_showImg), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self setNeedsLayout];
}

- (CGFloat)ty_imgWidth {
    NSNumber *widthNum = objc_getAssociatedObject(self, TYImgWidthKey);
    return widthNum ? [widthNum floatValue] : 20.0f;
}

- (void)setTy_imgWidth:(CGFloat)ty_imgWidth {
    objc_setAssociatedObject(self, TYImgWidthKey, @(ty_imgWidth), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self setNeedsLayout];
}

#pragma mark - 方法交换
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 只交换布局方法,移除初始化方法交换
        [self swizzleMethod:@selector(layoutSubviews) withMethod:@selector(ty_layoutSubviews)];
    });
}

+ (void)swizzleMethod:(SEL)originalSEL withMethod:(SEL)swizzledSEL {
    Class class = [self class];
    Method originalMethod = class_getInstanceMethod(class, originalSEL);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSEL);

    BOOL didAddMethod = class_addMethod(class, originalSEL, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod(class, swizzledSEL, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

#pragma mark - 布局方法(文字在前,图片在后)
- (void)ty_layoutSubviews {
    [self ty_layoutSubviews]; // 先执行原布局逻辑

    if (self.ty_showImg) {
        // 第一次访问ty_imageView时会自动创建并添加到contentView
        CGFloat imageW = self.ty_imgWidth;
        CGFloat imageH = [PublicObj hfShowHeight]; // 可按需新增imgHeight属性
        CGFloat spacing = [PublicObj hfImgTxtSpace]; // 图文间距

        // 兼容iOS 13+的文字宽度计算(避免废弃API警告)
        CGFloat titleW = [self.titleLabel.text boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, self.titleLabel.font.lineHeight)
                                                            options:NSStringDrawingUsesLineFragmentOrigin
                                                         attributes:@{NSFontAttributeName: self.titleLabel.font}
                                                            context:nil].size.width;
        CGFloat totalW = titleW + spacing + imageW; // 图文总宽度(文字+间距+图片)
        // CGFloat totalH = MAX(imageH, self.titleLabel.font.lineHeight); // 图文总高度

        // 整体居中的基准坐标
        CGFloat centerX = self.contentView.bounds.size.width / 2;
        CGFloat centerY = self.contentView.bounds.size.height / 2;

        // ===== 核心修改:文字在前(左),图片在后(右) =====
        // 文字布局:整体居中的左侧起点
        self.titleLabel.frame = CGRectMake(centerX - totalW / 2,
                                           centerY - self.titleLabel.font.lineHeight / 2,
                                           titleW,
                                           self.titleLabel.font.lineHeight);
        // 图片布局:文字右侧,间距spacing
        self.ty_imageView.frame = CGRectMake(CGRectGetMaxX(self.titleLabel.frame) + spacing,
                                             centerY - imageH / 2,
                                             imageW,
                                             imageH);

        self.ty_imageView.hidden = NO;
    } else {
        // 不显示图片:仅文字居中
        self.titleLabel.frame = self.contentView.bounds;
        self.ty_imageView.hidden = YES;
    }
}
@end