UIEdgeInsetsMake学习

这篇博客介绍了UIEdgeInsetsMake在iOS开发中的应用,主要用于调整UIButton中Image和Label的位置。通过设置edge insets,可以实现按钮内容的上下左右间距,以满足不同布局需求。实战部分演示了如何创建一个具有特定间距的button,通过设置负值的UIEdgeInsetsMake属性实现内容上移。

参考链接
参考链接

在平常我们使用button的时候,需求可能是需要我们满足button的Image和Label的各种体位,这个使用我们就需要使用UIEdgeInsetsMake来满足下需求,通过设置button的image和label的insetEdge来满足。

UIEdgeInsetsMake 介绍

typedef struct UIEdgeInsets { 
  CGFloat top, left, bottom, right; // specify amount to inset (positive) for each of the edges. values can be negative to 'outset'
} UIEdgeInsets;

是一个结构体,里面有四个属性,上左下右,看注释大概意思是说
为每条边指定插入量。正值的话是距离边多多少,负值的话是距离边少多少

image.png

引用:
图中,蓝色标识为可变区域, 绿色标识为不变区域。UIEdgeInsets结构体的属性top与bottom为一对,用来指定纵向可变区域(黑色虚线矩形),left与right为一对,用来指定横向可变区域(白色虚线矩形)。当UIButton/UIImageView的size大于UIImage的size时,会调整图片中可变区域大小以铺满整个控件,具体调整规则如下:
(1)控件宽度大于图片宽度,拉伸白色虚线矩形
(2)控件高度大于图片高度,拉伸黑色虚线矩形
(3)控件宽度小于图片宽度时,横向整体缩小(可变区与不变区比例不变)
(4)控件高度小于图片高度时,纵向整体缩小(可变区与不变区比例不变)

实战

其实很简单,目标实现这样的一个button

image.png

我们现在的样子是这样的

image.png

  • 第一步我们先将image和label都居中放置

    我们让label向左便宜-imageWidth (意思就是让他往左走了imageView的宽度)
     [button setTitleEdgeInsets:UIEdgeInsetsMake(0, -imageWidth, 0, 0)];
     让image向右走-titleLabeWidth (意思是让他向右左了titleLabel的宽度)
     [button setImageEdgeInsets:UIEdgeInsetsMake(0, 0, 0, -titleLabelWidth)]; 
    

    设置完这些后我们看下当前的效果 我们发现现在image和label都是处在居中的状态下

image.png

  • 第二步我们在设置下上下的间距
    让titleLabel向下偏移- imageHeight - space (意思是向下走了图片的高度+偏移)
     [button setTitleEdgeInsets:UIEdgeInsetsMake(0, -imageWidth, -imageHeight - space, 0)];
     同理设置imageView的偏移
    [button setImageEdgeInsets:UIEdgeInsetsMake(-titleLabelHeigt - space, 0, 0, -titleLabelWidth)];
    

最后就实现了我们需要的效果

image.png

其实设置很简单,想清楚我们要怎么移动我们的内部空间,比如向上移动就是设置top属性同时设置一个负值这样的话对应的控件就会上移,按照这种思路设置的EdgeInset的属性都是负值

我给你代码,告诉我应该怎么改? // // TPBPageControl.h // TPBDesignKit // // Created by ming on 2025/2/13. // #import "TPBBaseView.h" #import "TPBMacro.h" NS_ASSUME_NONNULL_BEGIN @interface TPBPageControl : TPBBaseView @property (nonatomic) UIEdgeInsets contentInsets; @property (nonatomic, assign) NSInteger numberOfPages; @property (nonatomic, assign) NSInteger currentPage; @property (nonatomic, strong, nullable) UIColor *pageIndicatorTintColor; @property (nonatomic, strong, nullable) UIColor *currentPageIndicatorTintColor; @property (nonatomic, assign) BOOL sameWidthPageIndicator; // 默认为NO, 当前pageIndicator会更宽 @property (nonatomic, assign) BOOL hightlightPassedPageIndicator; @property (nonatomic, nullable, copy) TPBAppIntegerCallback indexDidChangeCallback; @end NS_ASSUME_NONNULL_END // // TPBPageControl.m // TPBDesignKit // // Created by ming on 2025/2/13. // #import "TPBPageControl.h" #import "TPBDesignKit.h" #import "NSString+TPBLocalization.h" @interface TPBPageControl() @property (nonatomic, strong) NSMutableArray<UIView *> *pageViewArray; @end @implementation TPBPageControl { CGFloat padding; // 圆点间的距离 CGFloat normalPageWidth; // 未选中Page宽度 CGFloat selectedPageWidth; // 选中Page宽度 } #pragma mark - ### ADA ### - (BOOL)isAccessibilityElement { return YES; } - (CGRect)accessibilityFrame { return [TPBA11yHelper getEnlargedAccessibilityFrame:self]; } - (NSString *)accessibilityLabel { return @"tpbPageControl".tpbDesignKitLocalized; } - (NSString *)accessibilityValue { NSString *indexValue = [NSString stringWithFormat:@"%ld", self.currentPage + 1]; NSString *totalValue = [NSString stringWithFormat:@"%ld", self.numberOfPages]; NSString *value = [@"tpbPageControlAccessibilityValue".tpbDesignKitLocalized tpbReplaceFormatPlaceholders:@[indexValue, totalValue]]; return value; } - (UIAccessibilityTraits)accessibilityTraits { return UIAccessibilityTraitAdjustable; } - (void)accessibilityIncrement { NSInteger targetPage = MAX(0, MIN(self.numberOfPages - 1, self.currentPage + 1)); if (targetPage == self.currentPage) { return; } self.currentPage = targetPage; if (self.indexDidChangeCallback) { self.indexDidChangeCallback(self.currentPage); } } - (void)accessibilityDecrement { NSInteger targetPage = MAX(0, MIN(self.numberOfPages - 1, self.currentPage - 1)); if (targetPage == self.currentPage) { return; } self.currentPage = targetPage; if (self.indexDidChangeCallback) { self.indexDidChangeCallback(self.currentPage); } } #pragma mark - 组件逻辑 - (void)setupInitialData { [super setupInitialData]; _contentInsets = UIEdgeInsetsMake(8, 12, 8, 12); _numberOfPages = 0; _currentPage = 0; _pageViewArray = [NSMutableArray array]; _sameWidthPageIndicator = NO; padding = 8; normalPageWidth = 8; selectedPageWidth = 32; self.accessibilityIdentifier = @"tpbPageControl_pageControl"; } - (void)layoutSubviews { [super layoutSubviews]; if (self.pageViewArray.count == 0) { return; } CGFloat contentWidth; CGFloat contentHeight = normalPageWidth; if (self.pageViewArray.count == 1) { contentWidth = normalPageWidth; } else { contentWidth = selectedPageWidth + (self.numberOfPages - 1) * (normalPageWidth + padding); } CGFloat x; if (self.tpbIsRTL) { x = self.bounds.size.width - (self.bounds.size.width - contentWidth) / 2; } else { x = (self.bounds.size.width - contentWidth) / 2; } CGFloat y = (self.bounds.size.height - contentHeight) / 2; for (NSInteger i = 0; i < self.pageViewArray.count; i++) { BOOL isCurrent = i == self.currentPage; BOOL isPassed = i < self.currentPage; CGFloat width = isCurrent && self.pageViewArray.count > 1 ? selectedPageWidth : normalPageWidth; if (self.tpbIsRTL) { x = x - width; } UIColor *color; if (isCurrent) { color = self.currentPageIndicatorTintColor != nil ? self.currentPageIndicatorTintColor : UIColor.tpbPrimary; } else if (isPassed && self.hightlightPassedPageIndicator) { color = self.currentPageIndicatorTintColor != nil ? self.currentPageIndicatorTintColor : UIColor.tpbPrimary; } else { color = self.pageIndicatorTintColor != nil ? self.pageIndicatorTintColor : UIColor.tpbSwitchBackground; } UIView *pageView = self.pageViewArray[i]; pageView.backgroundColor = color; pageView.frame = CGRectMake(x, y, width, normalPageWidth); if (self.tpbIsRTL) { x = x - padding; } else { x = x + width + padding; } } } - (CGSize)intrinsicContentSize { if (self.numberOfPages <= 0) { return CGSizeMake(0, 0); } CGFloat extraWidth = self.contentInsets.left + self.contentInsets.right; CGFloat extraHeight = self.contentInsets.top + self.contentInsets.bottom; CGFloat height = normalPageWidth + extraHeight; if (self.numberOfPages == 1) { return CGSizeMake(normalPageWidth + extraWidth, height); } CGFloat contentWidth = selectedPageWidth + (self.numberOfPages - 1) * (normalPageWidth + padding); return CGSizeMake(contentWidth + extraWidth, height); } - (void)setContentInsets:(UIEdgeInsets)contentInsets { _contentInsets = contentInsets; [self invalidateIntrinsicContentSize]; } - (void)setNumberOfPages:(NSInteger)numberOfPages { NSInteger fixedNumberOfPages = MAX(0, numberOfPages);; if (_numberOfPages == fixedNumberOfPages) { return; } _numberOfPages = fixedNumberOfPages; [self updatePageViewArray]; [self setNeedsLayout]; [self invalidateIntrinsicContentSize]; } - (void)setCurrentPage:(NSInteger)currentPage { NSInteger fixedCurrentPage = MAX(0, MIN(self.numberOfPages - 1, currentPage)); if (_currentPage == fixedCurrentPage) { return; } _currentPage = fixedCurrentPage; [self setNeedsLayout]; } - (void)setPageIndicatorTintColor:(UIColor *)pageIndicatorTintColor { _pageIndicatorTintColor = pageIndicatorTintColor; [self setNeedsLayout]; } - (void)setCurrentPageIndicatorTintColor:(UIColor *)currentPageIndicatorTintColor { _currentPageIndicatorTintColor = currentPageIndicatorTintColor; [self setNeedsLayout]; } - (void)setHightlightPassedPageIndicator:(BOOL)hightlightPassedPageIndicator { _hightlightPassedPageIndicator = hightlightPassedPageIndicator; [self setNeedsLayout]; } - (void)setSameWidthPageIndicator:(BOOL)sameWidthPageIndicator { _sameWidthPageIndicator = sameWidthPageIndicator; selectedPageWidth = sameWidthPageIndicator? 8 : 32; [self setNeedsLayout]; [self invalidateIntrinsicContentSize]; } - (void)updatePageViewArray { NSInteger currentCount = self.pageViewArray.count; if (currentCount < self.numberOfPages) { for (NSInteger i = currentCount; i < self.numberOfPages; i++) { UIView *pageView = [UIView new]; pageView.layer.cornerRadius = normalPageWidth / 2; pageView.layer.masksToBounds = YES; [self addSubview:pageView]; [self.pageViewArray addObject:pageView]; } } else if (currentCount > self.numberOfPages) { for (NSInteger i = currentCount - 1; i > self.numberOfPages - 1; i--) { UIView *pageView = self.pageViewArray[i]; [pageView removeFromSuperview]; [self.pageViewArray removeLastObject]; } } } @end
最新发布
12-17
根据你提供的 `TPBPageControl` 代码,我们来**定位问题并给出修改建议**,以解决 **RTL 布局下 pageControl 按钮切换行为与 LTR 不一致** 的问题。 --- ## 🧨 问题分析 你提到的问题是: > `pageControl` 控制切换按钮会随着 RTL 产生不同的结果,这样会与手动切换方式不符合,希望其在 RTL 时表现与 LTR 一致。 ### 🔍 问题定位 在 `TPBPageControl` 的 `layoutSubviews` 方法中,你使用了 `self.tpbIsRTL` 来判断是否是 RTL 布局,并据此调整按钮的排列方向: ```objc if (self.tpbIsRTL) { x = self.bounds.size.width - (self.bounds.size.width - contentWidth) / 2; } else { x = (self.bounds.size.width - contentWidth) / 2; } ``` 然后在循环中: ```objc if (self.tpbIsRTL) { x = x - width; } ``` 这段逻辑**手动处理了 RTL 布局**,但可能导致了按钮排列顺序和点击行为与 LTR 不一致。 --- ## ✅ 解决方案 ### ✅ 方法一:强制 `TPBPageControl` 使用 LTR 布局(推荐) 你可以在 `TPBPageControl` 初始化时,设置 `semanticContentAttribute` 为 `UISemanticContentAttributeForceLeftToRight`,以**禁止系统自动 RTL 翻转**。 #### ✅ 修改 `setupInitialData` 方法: ```objc - (void)setupInitialData { [super setupInitialData]; _contentInsets = UIEdgeInsetsMake(8, 12, 8, 12); _numberOfPages = 0; _currentPage = 0; _pageViewArray = [NSMutableArray array]; _sameWidthPageIndicator = NO; padding = 8; normalPageWidth = 8; selectedPageWidth = 32; self.accessibilityIdentifier = @"tpbPageControl_pageControl"; // 强制使用 LTR 布局 if (@available(iOS 10.0, *)) { self.semanticContentAttribute = UISemanticContentAttributeForceLeftToRight; } } ``` #### ✅ 同时,修改 `layoutSubviews` 方法中对 `tpbIsRTL` 的处理: ```objc - (void)layoutSubviews { [super layoutSubviews]; if (self.pageViewArray.count == 0) { return; } CGFloat contentWidth; CGFloat contentHeight = normalPageWidth; if (self.pageViewArray.count == 1) { contentWidth = normalPageWidth; } else { contentWidth = selectedPageWidth + (self.numberOfPages - 1) * (normalPageWidth + padding); } CGFloat x = (self.bounds.size.width - contentWidth) / 2; CGFloat y = (self.bounds.size.height - contentHeight) / 2; for (NSInteger i = 0; i < self.pageViewArray.count; i++) { BOOL isCurrent = i == self.currentPage; BOOL isPassed = i < self.currentPage; CGFloat width = isCurrent && self.pageViewArray.count > 1 ? selectedPageWidth : normalPageWidth; UIView *pageView = self.pageViewArray[i]; UIColor *color; if (isCurrent) { color = self.currentPageIndicatorTintColor ?: UIColor.tpbPrimary; } else if (isPassed && self.hightlightPassedPageIndicator) { color = self.currentPageIndicatorTintColor ?: UIColor.tpbPrimary; } else { color = self.pageIndicatorTintColor ?: UIColor.tpbSwitchBackground; } pageView.backgroundColor = color; pageView.frame = CGRectMake(x, y, width, normalPageWidth); x += width + padding; } } ``` #### ✅ 删除或注释掉所有与 `tpbIsRTL` 相关的判断逻辑,因为我们已经强制使用 LTR。 --- ## ✅ 方法二:适配 RTL 布局(可选) 如果你**希望支持 RTL 但保持逻辑一致**,则应修改 `scrollView` 的偏移计算逻辑(在 `TPBPageView.m` 中): ```objc - (void)innerSwitchToPage:(NSInteger)page animated:(BOOL)animated { CGFloat x = self.scrollView.frame.size.width * page; if ([UIView tpbIsRightToLeft]) { x = self.scrollView.contentSize.width - self.scrollView.frame.size.width * (page + 1); } [self.scrollView setContentOffset:CGPointMake(x, 0) animated:animated]; [self updateContentHeight]; [self reportPageChanged]; } ``` --- ## ✅ 总结修改点 | 文件 | 修改点 | 说明 | |------|--------|------| | `TPBPageControl.m` | 在 `setupInitialData` 设置 `semanticContentAttribute = ForceLeftToRight` | 禁止 RTL 自动翻转 | | `TPBPageControl.m` | 修改 `layoutSubviews`,移除 RTL 判断逻辑 | 统一使用 LTR 排列 | | `TPBPageView.m`(可选) | 修改 `innerSwitchToPage:animated:` 支持 RTL 偏移 | 保持页面切换逻辑一致 | --- ##
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值