UI界面相关方法
发表于 - 10 分钟 | --该文档用于记录iOS端常用的界面方法。
1.状态栏UIStatusBar相关设置
1.1 设置状态栏字体颜色
-
状态栏的样式有两种:
.lightContent
(白色),.default
(黑色) -
要使用该方法设置状态栏,需要先设置
.plist
里面的参数:View controller-based status bar appearance
值设为YES
设置更改时需要调用:
setNeedsStatusBarAppearanceUpdate()
调用该方法后,在以下方法里更改状态栏的样式:
override var preferredStatusBarStyle: UIStatusBarStyle {
if <##> {
return .lightContent
} else {
return .default
}
}
1.2设置状态栏颜色
- 当隐藏导航栏时从其子页面pop到该页面可能导致顶部出现变黑的动画,虽然不影响操作,但是也不美观,可通过该方法消除一闪而过的导航栏或者状态栏黑色样式
- 该设置会影响所有页面的状态栏颜色,如使用该方法,则页面主色调有更改的地方都需要更改statusBar
- 其他需要主动设置状态栏的情况也可调用该方法
//设置状态栏颜色
- (void)setStatusBarBackgroundColor:(UIColor *)color {
UIView *statusBar = [[[UIApplication sharedApplication] valueForKey:@"statusBarWindow"] valueForKey:@"statusBar"];
if ([statusBar respondsToSelector:@selector(setBackgroundColor:)]) {
statusBar.backgroundColor = color;
}
}
2.UINavigation及UITabbar相关方法
2.1 设置push进子界面的同时隐藏底部UITabbar
-
设置子界面的
hidesBottomBarWhenPushed
来隐藏子界面及其下级界面的UITabbar
-
可以在
NavigationController
的基类里覆盖push
方法
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
if (viewControllers.count > 0) {// 当非根控制器隐藏底部tabbar
viewController.hidesBottomBarWhenPushed = true;
viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named:"back"), style: .plain, target: self, action: #selector(back))
}
super.pushViewController(viewController, animated: animated)
}
2.2 设置UINavigationBar上按钮的文字颜色
全局设置:
UINavigationBar.appearance().tintColor = UIColor.orange
单独某页面设置:
navigationItem.rightBarButtonItem?.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor.primary], for:.normal)
navigationItem.rightBarButtonItem?.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor.primary], for:.highlighted)
2.3 设置UITabBarItem上的文字颜色
UITabBarItem.appearance().setTitleTextAttributes(
[NSAttributedString.Key.foregroundColor:UIColor.primary], for:.selected)
3.滚动视图相关设置
3.1 设置UITableView分隔线(下划线)
- 移除多余分隔线
tableView.tableFooterView = UIView(frame: CGRect.zero)
- 将分隔线左右拉伸
tableview.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
- 设置分隔线颜色
tableview.separatorColor = UIColor.line_grey
3.2 UITableView及UICollectionView的点击事件穿透设置方法
- 该方法可以将滚动视图内部的滚动视图的响应穿透,使所有的响应皆为该滚动视图的
- 被吃掉的响应无法再有点击触碰、滑动等效果
- 故使用该方法时需考虑被穿透的响应是否需要
- 设置
UITableView
的穿透,则UITableView
中除UITableViewCell
的响应全部失效;设置UITableViewCell
的穿透,则cell内部的所有响应全部失效 - 如果子滚动视图存在需要滚动的情况,则应该只判断
UITableView
(其他滚动视图同理)
//点击事件穿透,不响应tableView的点击事件
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
if let bool1 = (view?.superview?.isKind(of: UITableViewCell.self)), let bool2 = view?.isKind(of: UITableView.self), bool1 || bool2 {
return self
}
return view
}
4.UITextView
4.1 UITextView设置超链接,点击可响应及其相关方法
ViewDidLoad:
//The description for the phone call.
let tipStr = "一串内容。"
let popStr = "内容后面可点击的文字"
let contentStr = tipStr + popStr
let range = NSRange(location: tipStr.count, length: popStr.count)
let contentAttrStr = NSMutableAttributedString(string: contentStr)
contentAttrStr.addAttributes([NSAttributedString.Key.link : "pop://"], range: range)
phoneCallContentTv.isEditable = false
phoneCallContentTv.delegate = self
phoneCallContentTv.attributedText = contentAttrStr
phoneCallContentTv.font = UIFont.systemFont(ofSize: 12)
phoneCallContentTv.textContainerInset = UIEdgeInsets.zero
phoneCallContentTv.tintColor = UIColor.primary
headBoard.addSubview(phoneCallContentTv)
extension:
extension PhoneCallReminderController:UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
if URL.description == "pop://" {
showDetails()
return false
}
return true
}
}
4.2 禁止UITextView被选中(复制粘贴全选)
//禁止textView选中
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
phoneCallContentTv.resignFirstResponder()
return super.canPerformAction(action, withSender: sender)
}
5.UIView界面相关方法
5.1 UIView的部分圆角设置
/**
按钮的圆角设置
@param view view类控件
@param rectCorner UIRectCorner要切除的圆角
@param borderColor 边框颜色
@param borderWidth 边框宽度
@param viewColor view类控件颜色
*/
- (void)setupRoundedCornersWithView:(UIView *)view cutCorners:(UIRectCorner)rectCorner borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth viewColor:(UIColor *)viewColor {
CAShapeLayer *mask=[CAShapeLayer layer];
UIBezierPath * path= [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:rectCorner cornerRadii:CGSizeMake(9,9)];
mask.path=path.CGPath;
mask.frame=view.bounds;
CAShapeLayer *borderLayer=[CAShapeLayer layer];
borderLayer.path=path.CGPath;
borderLayer.fillColor = [UIColor clearColor].CGColor;
borderLayer.strokeColor = borderColor.CGColor;
borderLayer.lineWidth = borderWidth;
borderLayer.frame = view.bounds;
view.layer.mask = mask;
[view.layer addSublayer:borderLayer];
}
6.UIImage方法
6.1 图片染色
将图片染成想要的颜色,适合带有透明度的png图片。
以下为UIImage的类扩展:
.h文件:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIImage (ChangeColor)
-(UIImage*)imageWithColor:(UIColor*)color;
- (UIImage *)originalImageWithColor:(UIColor *)color;
@end
NS_ASSUME_NONNULL_END
.m文件:
#import "UIImage+ChangeColor.h"
@implementation UIImage (ChangeColor)
//绘图
-(UIImage*)imageWithColor:(UIColor*)color
{
//获取画布
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
//画笔沾取颜色
[color setFill];
CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
UIRectFill(bounds);
//绘制一次
[self drawInRect:bounds blendMode:kCGBlendModeOverlay alpha:1.0f];
//再绘制一次
[self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0f];
//获取图片
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
- (UIImage *)originalImageWithColor:(UIColor *)color {
UIImage *img = [self imageWithColor:color];
img = [img imageWithRenderingMode:(UIImageRenderingModeAlwaysOriginal)];
return img;
}
@end
当对作为tabbar的图标做染色时发现图片被显示成系统默认的蓝色了,此时可以调用以下方法对图片做进一层封装,调用时使用以下方法即可:
- (UIImage *)originalImageWithColor:(UIColor *)color {
UIImage *img = [self imageWithColor:color];
img = [img imageWithRenderingMode:(UIImageRenderingModeAlwaysOriginal)];
return img;
}
使用方式:
UIImage *image= [UIImage imageNamed:@"tab_home_selected"];
image = [image imageWithColor:[UIColor redColor]];
参考文章:iOS改变图片的颜色
6.2 更改图片中的特定颜色
有时候如果要根据主题或者主色调对图片进行更改时,可调用以下方法,将一定范围内的颜色更改成指定的颜色。
以下为UIImage的类扩展:
.h文件:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIImage (Rander)
- (UIImage *)translatePixelColorByTargetNearBlackColor:(UIColor *)nearBlackColor nearWhiteColor:(UIColor *)nearWhiteColor transColor:(UIColor *)transColor;
- (UIImage *)translatePixelColorByTargetNearBlackColorHex:(UInt32)nearBlackRGB nearWhiteColorHex:(UInt32)nearWhiteRGB transColorHex:(UInt32)transRGB;
- (UIImage *)translatePixelColorByTargetNearBlackColorRGBA:(UInt32)nearBlackRGBA nearWhiteColorRGBA:(UInt32)nearWhiteRGBA transColorRGBA:(UInt32)transRGBA inRect:(CGRect)rect;
@end
NS_ASSUME_NONNULL_END
.m文件
#import "UIImage+Rander.h"
#import "UIColor+RGB.h"
@implementation UIImage (Rander)
- (UIImage *)translatePixelColorByTargetNearBlackColor:(UIColor *)nearBlackColor
nearWhiteColor:(UIColor *)nearWhiteColor
transColor:(UIColor *)transColor {
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
return [self translatePixelColorByTargetNearBlackColor:nearBlackColor nearWhiteColor:nearWhiteColor transColor:transColor inRect:rect];
}
- (UIImage *)translatePixelColorByTargetNearBlackColor:(UIColor *)nearBlackColor
nearWhiteColor:(UIColor *)nearWhiteColor
transColor:(UIColor *)transColor
inRect:(CGRect)rect {
// UIColor 转 RGBA
UInt32 nearBlackRGBA = nearBlackColor.RGBA;
UInt32 nearWhiteRGBA = nearWhiteColor.RGBA;
UInt32 transRGBA = transColor.RGBA;
return [self translatePixelColorByTargetNearBlackColorRGBA:nearBlackRGBA nearWhiteColorRGBA:nearWhiteRGBA transColorRGBA:transRGBA inRect:rect];
}
- (UIImage *)translatePixelColorByTargetNearBlackColorHex:(UInt32)nearBlackRGB
nearWhiteColorHex:(UInt32)nearWhiteRGB
transColorHex:(UInt32)transRGB {
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
return [self translatePixelColorByTargetNearBlackColorHex:nearBlackRGB nearWhiteColorHex:nearWhiteRGB transColorHex:transRGB inRect:rect];
}
- (UIImage *)translatePixelColorByTargetNearBlackColorHex:(UInt32)nearBlackRGB
nearWhiteColorHex:(UInt32)nearWhiteRGB
transColorHex:(UInt32)transRGB
inRect:(CGRect)rect {
// RGB 转 RGBA
UInt32 nearBlackRGBA = (nearBlackRGB << 8) + 0xFF;
UInt32 nearWhiteRGBA = (nearWhiteRGB << 8) + 0xFF;
UInt32 transRGBA = (transRGB << 8) + 0xFF;
return [self translatePixelColorByTargetNearBlackColorRGBA:nearBlackRGBA nearWhiteColorRGBA:nearWhiteRGBA transColorRGBA:transRGBA inRect:rect];
}
/**
解释一下前两个参数的含义:
想象一个数轴,最左边是黑色(RGBX:0x000000FF),最右边是白色(0xFFFFFFFF),
nearBlackColor是靠近左边边界的色值,nearWhiteColor是靠近右边边界的色值,
它们中间则是需要被修改的色值范围
*/
- (UIImage *)translatePixelColorByTargetNearBlackColorRGBA:(UInt32)nearBlackRGBA
nearWhiteColorRGBA:(UInt32)nearWhiteRGBA
transColorRGBA:(UInt32)transRGBA
inRect:(CGRect)rect {
// 第一步:判断传入的rect是否在图片的bounds内
CGRect canvas = CGRectMake(0, 0, self.size.width, self.size.height);
if (!CGRectContainsRect(canvas, rect)) {
if (CGRectIntersectsRect(canvas, rect)) {
rect = CGRectIntersection(canvas, rect); // 取交集
} else {
return self;
}
}
UIImage *transImage = nil;
int imageWidth = self.size.width;
int imageHeight = self.size.height;
// 第二步:创建色彩空间、画布上下文,并将图片以bitmap(不含alpha通道)的方式画在画布上。
size_t bytesPerRow = imageWidth * 4;
uint32_t *rgbImageBuf = (uint32_t *)malloc(bytesPerRow * imageHeight);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), self.CGImage);
// 第三步:遍历并修改像素
uint32_t *pCurPtr = rgbImageBuf;
pCurPtr += (long)(rect.origin.y*imageWidth); // 将指针移动到初始行的起始位置
// 空间复杂度:O(rect.size.width * rect.size.height)
for (int i = rect.origin.y; i < CGRectGetMaxY(rect); i++) { // row
pCurPtr += (long)rect.origin.x; // 将指针移动到当前行的起始列
for (int j = rect.origin.x; j < CGRectGetMaxX(rect); j++, pCurPtr++) { // column
if (*pCurPtr < nearBlackRGBA || *pCurPtr > nearWhiteRGBA) { continue; }
// 将图片转成想要的颜色
uint8_t *ptr = (uint8_t *)pCurPtr;
ptr[3] = (transRGBA >> 24) & 0xFF; // R
ptr[2] = (transRGBA >> 16) & 0xFF; // G
ptr[1] = (transRGBA >> 8) & 0xFF; // B
}
pCurPtr += (long)(imageWidth - CGRectGetMaxX(rect)); // 将指针移动到下一行的起始列
}
// 第四步:输出图片
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight, providerReleaseDataCallback);
CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight, 8, 32, bytesPerRow, colorSpace,
kCGImageAlphaLast | kCGBitmapByteOrder32Little, dataProvider,
NULL, true, kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
transImage = [UIImage imageWithCGImage:imageRef];
// end:清理空间
CGImageRelease(imageRef);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return transImage ? : self;
}
void providerReleaseDataCallback (void *info, const void *data, size_t size) {
free((void*)data);
}
@end
该方法调用了UIColor的类扩展,以下是扩展内容
.h文件
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIColor (RGB)
- (UInt32)RGBA;
@end
NS_ASSUME_NONNULL_END
.m文件
#import "UIColor+RGB.h"
@implementation UIColor (RGB)
- (UInt32)RGBA {
CGFloat red = 0;
CGFloat green = 0;
CGFloat blue = 0;
CGFloat alpha = 0;
BOOL succ = [self getRed:&red green:&green blue:&blue alpha:&alpha];
UInt32 r = round(red*255);
UInt32 g = round(green*255);
UInt32 b = round(blue*255);
UInt32 a = round(alpha*255);
r = (r << 24);
g = (g << 16);
b = (b << 8);
UInt32 rgba = r + g + b + a;
return succ ? rgba : 0x00000000;
}
@end
参考文章:iOS修改图片颜色(修改像素色值)
6.3 生成二维码图片
生成二维码是iOS内置功能,直接调用iOS系统库即可:#import <CoreImage/CoreImage.h>
6.3.1 根据CIImage生成指定大小的UIImage
创建二维码滤镜后生成的二维码图片为CIImage类型,需根据该方法将其转换为指定大小的UIImage。
代码如下:
- (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat) size {
CGRect extent = CGRectIntegral(image.extent);
CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
//1.创建bitmap;
size_t width = CGRectGetWidth(extent) * scale;
size_t height = CGRectGetHeight(extent) * scale;
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
CGContextScaleCTM(bitmapRef, scale, scale);
CGContextDrawImage(bitmapRef, extent, bitmapImage);
//2.保存bitmap到图片
CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
CGContextRelease(bitmapRef);
CGImageRelease(bitmapImage);
return [UIImage imageWithCGImage:scaledImage];
}
6.3.2 生成二维码
方法如下:
- (void)setupQRCodeWithContent:(NSString *)content {
//创建二维码滤镜示例
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
[filter setDefaults];
//赋值
NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding];
[filter setValue:data forKeyPath:@"inputMessage"];
// 生成二维码
CIImage *outputImage = [filter outputImage];
UIImage *qrImage = [self createNonInterpolatedUIImageFormCIImage:outputImage withSize:self.width_qr];
self.qrImgv.image = qrImage;
}
6.3.3 生成中间带有图片的二维码图片
二维码也可以生成为中间带图片的二维码样式,该效果需要在生成二维码图片之后再对图片进行处理。
方法如下:
//开启图形上下文
UIGraphicsBeginImageContext(qrImage.size);
//将二维码的图片画入
[qrImage drawInRect:CGRectMake(0, 0, qrImage.size.width, qrImage.size.height)];
//添加中间图片
UIImage *centerImage = [UIImage imageNamed:@"imageName"];
CGFloat width_center = qrImage.size.width * 0.3;
CGFloat width_height = width_center;
CGFloat x_center = (qrImage.size.width - width_center) * 0.5;
CGFloat y_center = (qrImage.size.height - width_height) * 0.5;
[centerImage drawInRect:CGRectMake(x_center, y_center, width_center, width_height)];
//获取绘制好的图片
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
//关闭图像上下文
UIGraphicsEndImageContext();
- 该方法在二维码生成之后使用
- finalImage即需要的中间带图片的二维码
7.视图边界方法
7.1 扩散动画效果
7.1.1 雷达扩散效果
- (void)addRadarAnimator
{
if (spreadLayer != nil && spreadLayer.superlayer != nil) {
[spreadLayer removeFromSuperlayer];
spreadLayer = nil;
}
spreadLayer = [CALayer layer];
CGFloat diameter = 180;//扩散的大小
spreadLayer.bounds = CGRectMake(0,0, diameter, diameter);
spreadLayer.cornerRadius = diameter/2; //设置圆角变为圆形
spreadLayer.position = self.scanIcon.center;
spreadLayer.backgroundColor = UIColorHex(0x8AC859).CGColor;
[self.scanBgView.layer insertSublayer:spreadLayer below:_scanIcon.layer];//把扩散层放到头像按钮下面
CAMediaTimingFunction * defaultCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
CAAnimationGroup * animationGroup = [CAAnimationGroup animation];
animationGroup.duration = 3;
animationGroup.repeatCount = INFINITY;//重复无限次
animationGroup.removedOnCompletion = NO;
animationGroup.timingFunction = defaultCurve;
//尺寸比例动画
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.xy"];
scaleAnimation.fromValue = @0.7;//开始的大小
scaleAnimation.toValue = @1.0;//最后的大小
scaleAnimation.duration = 3;//动画持续时间
//透明度动画
CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
opacityAnimation.duration = 3;
opacityAnimation.values = @[@0.4, @0.45,@0];//透明度值的设置
opacityAnimation.keyTimes = @[@0, @0.2,@1];//关键帧
opacityAnimation.removedOnCompletion = NO;
animationGroup.animations = @[scaleAnimation, opacityAnimation];//添加到动画组
[spreadLayer addAnimation:animationGroup forKey:@"pulse"];
}