歷史版本
版本號 | 時間 |
---|---|
V1.0 | 2017.07.12 |
前言
大家在做圖片上傳還有頭像等很多時候,經(jīng)常都會碰到圖片拉伸或者壓縮等幾種情況,下面我們就舉個例子說一下這幾種填充模式。
一、代碼展示
??下面我們就先寫一個簡單的控件,并渲染出來如下所示。
先看一下下面的代碼。
#import "JJContentModeVC.h"
@interface JJContentModeVC ()
@property (nonatomic, strong) UIImageView *coverImageView;
@end
@implementation JJContentModeVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self setupUI];
}
#pragma mark - Object Private Function
- (void)setupUI
{
UIImageView *coverImageView = [[UIImageView alloc] init];
coverImageView.image = [UIImage imageNamed:@"girl_or_women"];
coverImageView.frame = CGRectMake(50.0, 300.0, 200, 200.0);
[self.view addSubview:coverImageView];
self.coverImageView = coverImageView;
}
@end
下面我們先看一下原圖
下面看一下仿真器效果圖。
二、幾種內(nèi)容模式基礎(chǔ)
下面我們看一下蘋果的API,如下所示。
@interface UIView(UIViewRendering)
- (void)drawRect:(CGRect)rect;
- (void)setNeedsDisplay;
- (void)setNeedsDisplayInRect:(CGRect)rect;
@property(nonatomic) BOOL clipsToBounds; // When YES, content and subviews are clipped to the bounds of the view. Default is NO.
@property(nullable, nonatomic,copy) UIColor *backgroundColor UI_APPEARANCE_SELECTOR; // default is nil. Can be useful with the appearance proxy on custom UIView subclasses.
@property(nonatomic) CGFloat alpha; // animatable. default is 1.0
@property(nonatomic,getter=isOpaque) BOOL opaque; // default is YES. opaque views must fill their entire bounds or the results are undefined. the active CGContext in drawRect: will not have been cleared and may have non-zeroed pixels
@property(nonatomic) BOOL clearsContextBeforeDrawing; // default is YES. ignored for opaque views. for non-opaque views causes the active CGContext in drawRect: to be pre-filled with transparent pixels
@property(nonatomic,getter=isHidden) BOOL hidden; // default is NO. doesn't check superviews
@property(nonatomic) UIViewContentMode contentMode; // default is UIViewContentModeScaleToFill
@property(nonatomic) CGRect contentStretch NS_DEPRECATED_IOS(3_0,6_0) __TVOS_PROHIBITED; // animatable. default is unit rectangle {{0,0} {1,1}}. Now deprecated: please use -[UIImage resizableImageWithCapInsets:] to achieve the same effect.
@property(nullable, nonatomic,strong) UIView *maskView NS_AVAILABLE_IOS(8_0);
/*
-tintColor always returns a color. The color returned is the first non-default value in the receiver's superview chain (starting with itself).
If no non-default value is found, a system-defined color is returned.
If this view's -tintAdjustmentMode returns Dimmed, then the color that is returned for -tintColor will automatically be dimmed.
If your view subclass uses tintColor in its rendering, override -tintColorDidChange in order to refresh the rendering if the color changes.
*/
@property(null_resettable, nonatomic, strong) UIColor *tintColor NS_AVAILABLE_IOS(7_0);
/*
-tintAdjustmentMode always returns either UIViewTintAdjustmentModeNormal or UIViewTintAdjustmentModeDimmed. The value returned is the first non-default value in the receiver's superview chain (starting with itself).
If no non-default value is found, UIViewTintAdjustmentModeNormal is returned.
When tintAdjustmentMode has a value of UIViewTintAdjustmentModeDimmed for a view, the color it returns from tintColor will be modified to give a dimmed appearance.
When the tintAdjustmentMode of a view changes (either the view's value changing or by one of its superview's values changing), -tintColorDidChange will be called to allow the view to refresh its rendering.
*/
@property(nonatomic) UIViewTintAdjustmentMode tintAdjustmentMode NS_AVAILABLE_IOS(7_0);
/*
The -tintColorDidChange message is sent to appropriate subviews of a view when its tintColor is changed by client code or to subviews in the view hierarchy of a view whose tintColor is implicitly changed when its superview or tintAdjustmentMode changes.
*/
- (void)tintColorDidChange NS_AVAILABLE_IOS(7_0);
@end
?? contentMode是UIView的屬性,這個屬性的值決定了,當(dāng)視圖的幾何形狀變化時如何復(fù)用它的內(nèi)容。當(dāng)視圖第一次展示前,它會將自己的內(nèi)容渲染成一張底層的bitmap。 然后視圖的幾何變化都不會使bitmap重新生成。而視圖contentMode屬性的值決定了bitmap是否縮放、位置在哪兒(固定在左邊、右邊、上面、下面、居中)。它是UIView的子類UIViewRendering的一個屬性,它是以一個枚舉值,默認(rèn)是UIViewContentModeScaleToFill。
下面看一下這個枚舉值。
typedef NS_ENUM(NSInteger, UIViewContentMode) {
UIViewContentModeScaleToFill,
UIViewContentModeScaleAspectFit, // contents scaled to fit with fixed aspect. remainder is transparent
UIViewContentModeScaleAspectFill, // contents scaled to fill with fixed aspect. some portion of content may be clipped.
UIViewContentModeRedraw, // redraw on bounds change (calls -setNeedsDisplay)
UIViewContentModeCenter, // contents remain same size. positioned adjusted.
UIViewContentModeTop,
UIViewContentModeBottom,
UIViewContentModeLeft,
UIViewContentModeRight,
UIViewContentModeTopLeft,
UIViewContentModeTopRight,
UIViewContentModeBottomLeft,
UIViewContentModeBottomRight,
};
三、幾種填充模式講解和效果展示
下面我們就說一下下面幾種模式及其效果展示。
1. UIViewContentModeScaleToFill
這個是填充模式的默認(rèn)選項。
UIViewContentModeScaleToFill
Scales the content to fit the size of itself by changing the aspect ratio of the content if necessary.
改變內(nèi)容的高寬比例,縮放內(nèi)容,UIView中完整顯示內(nèi)容,填滿UIView,
??上面那個模擬器圖就是這個內(nèi)容模式下的效果,imageView的尺寸沒有改變,這里改變的是所給圖像的寬高比例,并且全部填充到UIImageView里面。下面看代碼和效果。
- (void)setupUI
{
UIImageView *coverImageView = [[UIImageView alloc] init];
coverImageView.contentMode = UIViewContentModeScaleToFill;
coverImageView.clipsToBounds = YES;
coverImageView.layer.borderColor = [UIColor blueColor].CGColor;
coverImageView.layer.borderWidth = 0.5;
coverImageView.image = [UIImage imageNamed:@"girl_or_women"];
coverImageView.frame = CGRectMake(50.0, 300.0, 200, 200.0);
[self.view addSubview:coverImageView];
self.coverImageView = coverImageView;
}
效果展示如下所示。
2. UIViewContentModeScaleAspectFit
UIViewContentModeScaleAspectFit
Scales the content to fit the size of the view by maintaining the aspect ratio. Any remaining area of the view’s bounds is transparent.
保持內(nèi)容的高寬比,縮放內(nèi)容,完整顯示內(nèi)容,最大化填充UIview,沒填充上的區(qū)域透明
下面我們看一下代碼和效果。
- (void)setupUI
{
UIImageView *coverImageView = [[UIImageView alloc] init];
coverImageView.contentMode = UIViewContentModeScaleAspectFit;
coverImageView.clipsToBounds = YES;
coverImageView.layer.borderColor = [UIColor blueColor].CGColor;
coverImageView.layer.borderWidth = 0.5;
coverImageView.image = [UIImage imageNamed:@"girl_or_women"];
coverImageView.frame = CGRectMake(50.0, 300.0, 200, 200.0);
[self.view addSubview:coverImageView];
self.coverImageView = coverImageView;
}
3. UIViewContentModeScaleAspectFill
UIViewContentModeScaleAspectFill
Scales the content to fill the size of the view. Some portion of the content may be clipped to fill the view’s bounds.
保持內(nèi)容高寬比,縮放內(nèi)容,超出視圖的部分內(nèi)容會被裁減,填充UIView
下面看一下效果圖和代碼。
- (void)setupUI
{
UIImageView *coverImageView = [[UIImageView alloc] init];
coverImageView.contentMode = UIViewContentModeScaleAspectFill;
coverImageView.clipsToBounds = YES;
coverImageView.layer.borderColor = [UIColor blueColor].CGColor;
coverImageView.layer.borderWidth = 0.5;
coverImageView.image = [UIImage imageNamed:@"girl_or_women"];
coverImageView.frame = CGRectMake(50.0, 300.0, 200, 200.0);
[self.view addSubview:coverImageView];
self.coverImageView = coverImageView;
}
??這個方法嚴(yán)格按照圖像的寬高比進行填充,超過的部分會被裁剪掉,好處就是這個方法保證不會失真,可以看見右邊的紙盒子已經(jīng)被裁剪掉了。
4. UIViewContentModeRedraw
UIViewContentModeRedraw
The option to redisplay the view when the bounds change by invoking the setNeedsDisplay method.
當(dāng)View的bounds改變,系統(tǒng)會調(diào)用setNeedsDisplay,重新繪制視圖
下面看代碼和效果。
- (void)setupUI
{
UIImageView *coverImageView = [[UIImageView alloc] init];
coverImageView.contentMode = UIViewContentModeRedraw;
coverImageView.clipsToBounds = YES;
coverImageView.layer.borderColor = [UIColor blueColor].CGColor;
coverImageView.layer.borderWidth = 0.5;
coverImageView.image = [UIImage imageNamed:@"girl_or_women"];
coverImageView.frame = CGRectMake(50.0, 300.0, 200, 200.0);
[self.view addSubview:coverImageView];
self.coverImageView = coverImageView;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
coverImageView.frame = CGRectMake(50.0, 300.0, 220, 130.0);
});
}
??我這里采用了延時處理,3s后更改imageview的bounds,系統(tǒng)會自動調(diào)用setNeedsDisplay方法,重新繪制,效果如下圖所示。
5. UIViewContentModeCenter
UIViewContentModeCenter
The option to center the content in the view’s bounds, keeping the proportions the same.
不縮放,內(nèi)容在視圖中間
下面我們就看一下代碼和效果。
- (void)setupUI
{
UIImageView *coverImageView = [[UIImageView alloc] init];
coverImageView.contentMode = UIViewContentModeCenter;
coverImageView.clipsToBounds = YES;
coverImageView.layer.borderColor = [UIColor blueColor].CGColor;
coverImageView.layer.borderWidth = 0.5;
coverImageView.image = [UIImage imageNamed:@"girl_or_women"];
coverImageView.frame = CGRectMake(50.0, 300.0, 200, 200.0);
[self.view addSubview:coverImageView];
self.coverImageView = coverImageView;
}
下面看效果圖。
6. UIViewContentModeTop
UIViewContentModeTop
不縮放,內(nèi)容在視圖上部。
下面看一下代碼和效果。
- (void)setupUI
{
UIImageView *coverImageView = [[UIImageView alloc] init];
coverImageView.contentMode = UIViewContentModeTop;
coverImageView.clipsToBounds = YES;
coverImageView.layer.borderColor = [UIColor blueColor].CGColor;
coverImageView.layer.borderWidth = 0.5;
coverImageView.image = [UIImage imageNamed:@"girl_or_women"];
coverImageView.frame = CGRectMake(50.0, 300.0, 200, 200.0);
[self.view addSubview:coverImageView];
self.coverImageView = coverImageView;
}
??剩下的其他幾種方法很不常用而且簡單易懂這里就不說了。借用網(wǎng)絡(luò)上的一張圖片讓大家看看,所有填充模式的填充效果如下。
??這里大家可能會有個需求,如果我需要進行一個圖像固定區(qū)域的裁剪,該如何進行呢,下面給大家一個方法,如下所示。
+ (UIImage *)clipWithClipImage:(UIImage *)clipImage;
{
float width = clipImage.size.width > clipImage.size.height ? clipImage.size.height : clipImage.size.width;
CGSize clipSize = CGSizeMake(width, width);
UIGraphicsBeginImageContext(clipSize);
[clipImage drawInRect:CGRectMake(0,0,width,width)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
??上面這個方法可以在任意點開始截取,并且截取任意size大小的圖片。
后記
??未完,待續(xù)~~~~