蘋果框架
UIKit -> UI
QuartzCore(繪圖)
Core Animation
MapKit(地圖)
CoreLocation(定位)
AVFoundation(音視頻)
...
UIKit常用的總結(jié):
UIButton內(nèi)部細(xì)節(jié)
#import "XLShopViewButton.h"
@implementation XLShopViewButton
# 內(nèi)部會(huì)調(diào)用的指定初始化器
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.titleLabel.textAlignment = NSTextAlignmentCenter;
// 禁止點(diǎn)擊
self.enabled = NO;
// 高亮狀態(tài)下不要調(diào)整按鈕顯示的圖片
self.adjustsImageWhenHighlighted = NO;
// disabled狀態(tài)下不要調(diào)整按鈕顯示的圖片
self.adjustsImageWhenDisabled = NO;
}
return self;
}
+ (instancetype)shopView {
return [[self alloc] init];
}
+ (instancetype)shopWithModel:(id)model {
XLShopViewButton *button = [self shopView];
return button;
}
# 布局子控件方式一
// 返回文字的位置和尺寸
//- (CGRect)titleRectForContentRect:(CGRect)contentRect {
// return CGRectMake(0, 0, contentRect.size.width, contentRect.size.width);
//}
// 返回圖片的位置和尺寸
//- (CGRect)imageRectForContentRect:(CGRect)contentRect {
// return CGRectMake(0, 70, contentRect.size.width, contentRect.size.height - 70);
//}
- (void)configationLabelAndImageValues {
[self setImage:[UIImage imageNamed:@"tab1"] forState:UIControlStateNormal];
[self setTitle:@"我是文字" forState:UIControlStateNormal];
[self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}
# 布局子控件方式二
- (void)layoutSubviews {
[super layoutSubviews];
// 蘋果內(nèi)部會(huì)在這個(gè)方法布局子控件,它布局好后,在改回需求的位置尺寸和位置
CGFloat imageWidth = self.frame.size.width;
CGFloat height = self.frame.size.height;
self.imageView.frame = CGRectMake(0, 0, imageWidth, imageWidth);
self.titleLabel.frame = CGRectMake(0, imageWidth, imageWidth, height - imageWidth);
}
@end
按鈕調(diào)整內(nèi)部控件的eg.
// 去調(diào)整按鈕內(nèi)部的titleLabel的大小
// 返回按鈕titleLabel內(nèi)部的尺寸
// contentRect:按鈕當(dāng)前的位置尺寸
- (CGRect)titleRectForContentRect:(CGRect)contentRect {
return CGRectMake(0, 0, contentRect.size.width, contentRect.size.width);
}
// 去調(diào)整按鈕內(nèi)部的imageView的大小
// 返回按鈕imageView內(nèi)部的尺寸
// contentRect:按鈕當(dāng)前的位置尺寸
- (CGRect)imageRectForContentRect:(CGRect)contentRect {
CGFloat w = 40;
CGFloat h = 45;
CGFloat x = (contentRect.size.width - w) * 0.5;
CGFloat y = 20;
return CGRectMake(x, y, w,h);
}
ScrollView常用屬性
#import "XLShopScrollView.h"
@interface XLShopScrollView ()
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicatorView;
@end
@implementation XLShopScrollView
#pragma mark - life cycle
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor redColor];
self.contentSize = CGSizeZero;
self.scrollEnabled = YES;
self.scrollsToTop = YES;
// 是否開啟分頁功能
// 以scrollView的尺寸為標(biāo)準(zhǔn)分頁
self.pagingEnabled = YES;
// 是否展示指示器
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;
// 是否有彈簧效果
self.bounces = YES;
// 即使沒有設(shè)置contentSize,也是有彈簧效果,用該屬性做下拉刷新。
self.alwaysBounceVertical = YES;
self.alwaysBounceHorizontal = NO;
// 設(shè)置內(nèi)容的偏移量,得知內(nèi)容的偏移量
// 手機(jī)中的坐標(biāo)系:水平方向右邊是正方向,豎直方向下邊是正方向
// scrollView的偏移量是scrollView的原點(diǎn)位置減去內(nèi)容的原點(diǎn)位置
// 向左滑動(dòng)偏移量是正的;向上滑動(dòng)偏移量是正的
self.contentOffset = CGPointMake(0, 100);
// 是否動(dòng)畫設(shè)置偏移量
[self setContentOffset:CGPointZero animated:YES];
// 設(shè)置內(nèi)邊距,偏移量還是之前的計(jì)算方式,只是可以多滾動(dòng)出內(nèi)邊距的距離
self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
// 設(shè)置代理監(jiān)聽控件的內(nèi)部事件
self.delegate = self;
// 設(shè)置最大和最小縮放比例并實(shí)現(xiàn)縮放的代理方法,返回縮放對(duì)象
// option + shift 可以移動(dòng)模擬器的縮放手勢(shì),松開shift間然后再縮放
self.minimumZoomScale = 0.5;
self.maximumZoomScale = 2;
[self addSubview:self.activityIndicatorView];
}
return self;
}
//MARK:
// 系統(tǒng)的短的指定初始化器會(huì)去調(diào)用長(zhǎng)的指定初始化器,
// 利用系統(tǒng)的指定初始化器來初始化自定義控件,把要自定義的控件放到長(zhǎng)的初始化方法內(nèi)部, 不管調(diào)用短的初始化還是長(zhǎng)的初始化方法都會(huì)得到自定義控件的創(chuàng)建和初始化
- (instancetype)init {
if (self = [super init]) {}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
self.activityIndicatorView.center = CGPointMake(self.center.x, -30);
}
#pragma mark - UIScrollViewDelegate
// scrollView正在滾動(dòng)的時(shí)候就會(huì)自動(dòng)調(diào)用這個(gè)方法
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {}
// 用戶即將拖拽scrollview的時(shí)候會(huì)自動(dòng)調(diào)用這個(gè)方法
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {}
// 用戶即將停止拖拽scrollview的時(shí)候會(huì)自動(dòng)調(diào)用這個(gè)方法
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset API_AVAILABLE(ios(5.0)) {
}
// 用戶已經(jīng)停止拖拽scrollview的時(shí)候會(huì)自動(dòng)調(diào)用這個(gè)方法
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (!decelerate) {
NSLog(@"用戶已經(jīng)停止拖拽scrollView,scrollView停止?jié)L動(dòng)");
} else {
NSLog(@"用戶已經(jīng)停止拖拽scrollView,但是scrollview由于慣性會(huì)繼續(xù)滾動(dòng),并減速");
}
}
// 停止?jié)L動(dòng)
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSLog(@"scrollView減速完畢,停止?jié)L動(dòng)");
}
// 將要開始減速
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {}
// scrollView已經(jīng)結(jié)束帶有動(dòng)畫的滑動(dòng)
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {}
// 返回帶縮放的控件
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {return nil;}
// scrollView將要開始縮放
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view {}
// scrollView已經(jīng)結(jié)束縮放
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale {}
// scrollview已經(jīng)結(jié)束縮放
- (void)scrollViewDidZoom:(UIScrollView *)scrollView API_AVAILABLE(ios(3.2)){}
// scrollView是否可以滑動(dòng)到頂部
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {return YES;}
// scrollView已經(jīng)滑動(dòng)到頂部
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {}
// iOS11 新增方法
- (void)scrollViewDidChangeAdjustedContentInset:(UIScrollView *)scrollView API_AVAILABLE(ios(11.0), tvos(11.0)) {
}
#pragma mark - getters and setters
- (UIActivityIndicatorView *)activityIndicatorView {
if (_activityIndicatorView == nil) {
_activityIndicatorView = [[UIActivityIndicatorView alloc] init];
[_activityIndicatorView startAnimating];
}
return _activityIndicatorView;
}
@end
scrollView分頁實(shí)現(xiàn)
# 方式一
// scrollView正在滾動(dòng)的時(shí)候就會(huì)自動(dòng)調(diào)用這個(gè)方法
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// 在滾動(dòng)的時(shí)候來判斷是幾頁,四舍五入
NSInteger pageNum = scrollView.contentOffset.x / scrollView.frame.size.width + 0.5;
}
# 方式二
// 用戶已經(jīng)停止拖拽scrollview的時(shí)候會(huì)自動(dòng)調(diào)用這個(gè)方法
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (!decelerate) {
NSLog(@"用戶已經(jīng)停止拖拽scrollView,scrollView停止?jié)L動(dòng)");
NSInteger pageNum = scrollView.contentOffset.x / scrollView.frame.size.width;
}
}
// 停止?jié)L動(dòng)
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSLog(@"scrollView減速完畢,停止?jié)L動(dòng)");
NSInteger pageNum = scrollView.contentOffset.x / scrollView.frame.size.width;
}
- (UIPageControl *)pageControl {
if (_pageControl == nil) {
_pageControl = [[UIPageControl alloc] init];
// 當(dāng)頁數(shù)隱藏控件
_pageControl.hidesForSinglePage = YES;
}
return _pageControl;
}
UITableView&collectionView
# tableview對(duì)多個(gè)插入,刪除,重新加載和移動(dòng)操作進(jìn)行動(dòng)畫處理
- (void)beginUpdates;
- (void)endUpdates;
// UITableView中該方法在是iOS11才有的方法
- (void)performBatchUpdates:(void (NS_NOESCAPE ^ _Nullable)(void))updates
completion:(void (^ _Nullable)(BOOL finished))completion API_AVAILABLE(ios(11.0),
# collectionView對(duì)多個(gè)插入,刪除,重新加載和移動(dòng)操作進(jìn)行動(dòng)畫處理
// 很早之前就有了,可以直接使用
- (void)performBatchUpdates:(void (NS_NOESCAPE ^ _Nullable)(void))updates
completion:(void (^ _Nullable)(BOOL finished))completion
對(duì)tableView的性能優(yōu)化?
1. 緩存池
2. Cell行高問題,如果不是等高的cell,必須的提前計(jì)算好行高,在heightForRowAtIndexPath:直接返回,此方法會(huì)調(diào)用很多次,在此方法當(dāng)中盡量少做大量計(jì)算操作。可以提前估一個(gè)行高,estimatedRowHeight(200-250)之間(目的是減少heightForRowAtIndexPath方法調(diào)用次數(shù))
3. Cell內(nèi)部空間最好一次給添加完,不要?jiǎng)討B(tài)去添加子控件
4. 如果說cell內(nèi)容子控件比較多,可以考慮把不需要于用戶交互的控件通過drawRect生成圖片的方式進(jìn)行繪制
5. 如果cell當(dāng)中使用圓角圖片時(shí),圖片最好通過quartz2D裁剪成圖形.,如果使用layer.cornerRadius+layer.masksToBounds 會(huì)造成離屏渲染,會(huì)耗性能
6. imageView寬高出現(xiàn)小數(shù)點(diǎn),會(huì)造成鋸齒,會(huì)造成離屏渲染耗性能。
7. 如果cell里面有圖片時(shí),imageView的尺寸要與圖片保持一樣大,服務(wù)器提供兩套圖片,開始加載的是小圖,點(diǎn)擊時(shí)在去加載大圖。如果圖片的尺寸不一樣,要對(duì)圖片進(jìn)行壓縮操作(形變操作transform,進(jìn)行大量的計(jì)算會(huì)耗性能)
UITextFiled
@interface XLShopTextField ()<UITextFieldDelegate>
@end
@implementation XLShopTextField
#pragma mark - life cycle
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.delegate = self;
// 指定鍵盤
self.inputView = [UIView new];
}
return self;
}
// 通過xib創(chuàng)建
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
// 指定鍵盤
self.inputView = [UIView new];
}
return self;
}
- (instancetype)init {
if (self = [super init]) {
}
return self;
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
}
- (void)textFieldDidEndEditing:(UITextField *)textField reason:(UITextFieldDidEndEditingReason)reason API_AVAILABLE(ios(10.0)); {
}
// 是否允許改變字符竄
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
return NO;
}
- (void)textFieldDidChangeSelection:(UITextField *)textField API_AVAILABLE(ios(13.0), tvos(13.0)) {
}
- (BOOL)textFieldShouldClear:(UITextField *)textField {
return NO;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
return NO;
}
@end
UITableViewCell
@interface XLShopTableViewCell ()
@property (nonatomic, strong) UIView *customBackgroundView;
@property (nonatomic, strong) UIView *customSelectedBackgroundView;
@end
@implementation XLShopTableViewCell
#pragma mark - life cycle
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
// accessoryView的優(yōu)先級(jí)大于accessoryType
// 設(shè)置cell的右邊的指示控件
self.accessoryView = [UIView new];
// 設(shè)置cell的右邊的指示樣式
self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// 設(shè)置cell的選中的樣式
self.selectionStyle = UITableViewCellSelectionStyleNone;
// 設(shè)置cell的背景顏色,backgroundView 優(yōu)先級(jí)大于backgroundColor
self.backgroundColor = [UIColor redColor];
// UITableViewCell的背景控件可以用圖片
self.backgroundView = self.customBackgroundView;
// 設(shè)置選中的背景控件
self.selectedBackgroundView = self.customSelectedBackgroundView;
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#pragma mark - getters and setters
- (UIView *)customBackgroundView {
if (_customBackgroundView == nil) {
_customBackgroundView = [UIView new];
_customBackgroundView.backgroundColor = [UIColor greenColor];
}
return _customBackgroundView;
}
- (UIView *)customSelectedBackgroundView {
if (_customSelectedBackgroundView == nil) {
_customSelectedBackgroundView = [UIView new];
_customSelectedBackgroundView.backgroundColor = [UIColor purpleColor];
}
return _customSelectedBackgroundView;
}
@end
UIViewContentMode
typedef NS_ENUM(NSInteger, UIViewContentMode) {
# 拉伸到填充整個(gè)imageView
UIViewContentModeScaleToFill,
# 等比拉伸到剛好看到整個(gè)圖片
UIViewContentModeScaleAspectFit,
# 等比拉伸到圖片的寬度或者高度剛好等于imageView,寬先達(dá)到ImageView的寬或者高先達(dá)到,之后居中顯示。搭配`clipsToBounds`超過圖片的內(nèi)容裁剪掉
UIViewContentModeScaleAspectFill,
// redraw on bounds change (calls -setNeedsDisplay)
UIViewContentModeRedraw,
# 按圖片原大小顯示 搭配`clipsToBounds`超過圖片的內(nèi)容裁剪掉
UIViewContentModeCenter,
UIViewContentModeTop,
UIViewContentModeBottom,
UIViewContentModeLeft,
UIViewContentModeRight,
UIViewContentModeTopLeft,
UIViewContentModeTopRight,
UIViewContentModeBottomLeft,
UIViewContentModeBottomRight,
};
獲取軟件安裝包資源路徑
# 導(dǎo)入播放器框架
#import <AVFoundation/AVFoundation.h>
// 獲取軟件的安裝包
NSBundle *bundle = [NSBundle mainBundle];
// 獲取安裝包某一個(gè)資源的路徑
NSURL *url = [bundle URLForResource:@"fileName" withExtension:@"mp3"];
// 創(chuàng)建 AVPlayer
AVPlayer *player = [AVPlayer playerWithURL:url];
// 播放
[player play];
圖片內(nèi)存問題
# 緩存圖片只能訪問`Assets.xcassets`
UIImage *cachedImage = [UIImage imageNamed:@"fileName"];
# 不緩存圖片,不放在`Assets.xcassets`下,放在項(xiàng)目的其他位置,會(huì)打包到`NSBundle`里
//MARK:OfFile:代表資源的全路徑
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"fileName" ofType:@"mp3"];
UIImage *noCachedImage = [UIImage imageWithContentsOfFile:imagePath];

Assets.png
xib
.c -> 編譯 -> .o
.xib -> 編譯 -> nib
# nib里可以有很多個(gè)view
# 加載xib方式一
NSArray * viewArray1 = [[NSBundle mainBundle] loadNibNamed:@"contentView" owner:nil options:nil];
UIView *view = array.firstObject;
# 加載xib方式二
UINib *nib = [UINib nibWithNibName:@"contentView" bundle:[NSBundle mainBundle]];
NSArray *viewArry2 = [nib instantiateWithOwner:nil options:nil];
UIView *view = viewArry2.firstObject;
# MARK: 如果一個(gè)控件是從xib或者storyboard創(chuàng)建出來的,初始化的時(shí)候一定調(diào)用initWithCoder:這個(gè)方法,但是拿到的控件可能會(huì)空的不能再這里做初始化操作。
# MARK: 通過該方式創(chuàng)建非xib的自定義控件,可以被其他的xib文件中引用該控件
- (instancetype)initWithCoder:(NSCoder *)coder {
if ([super initWithCoder:coder]) {
}
return self;
}
# MARK: 如果一個(gè)控件是從xib或者storyboard創(chuàng)建出來的,加載完畢的時(shí)候一定調(diào)用awakeFromNib這個(gè)方法
# MARK:在這里做一些屬性的初始化操作
- (void)awakeFromNib {
[super awakeFromNib];
}
performSegueWithIdentifier:內(nèi)部實(shí)現(xiàn)
1. 根據(jù)標(biāo)志去storyBoard中查找有沒有標(biāo)志,如果有
2. 會(huì)創(chuàng)建segue對(duì)象UIStoryboardSegue *segue
3. 給segue對(duì)象的屬性賦值 segue.sourceViewController = self
4. 給segue對(duì)象設(shè)置目的地vc segue.destinationViewController = vc;
5. 會(huì)調(diào)用當(dāng)前控制器的方法
// 告訴segue已經(jīng)準(zhǔn)備好開始跳轉(zhuǎn),在方法里面可以拿到要跳轉(zhuǎn)的控制器,可以在這里給目標(biāo)控制器傳遞數(shù)據(jù)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
6. 真正跳轉(zhuǎn)的方法是[segue perform];方法,我們不需要手動(dòng)實(shí)現(xiàn),上邊這個(gè)方法內(nèi)部已經(jīng)處理了
iOS 應(yīng)用數(shù)據(jù)存儲(chǔ)的常用方式
1. XML 屬性列表(plist)歸檔
2. Preference(偏好設(shè)置,存放一些用戶比較小的數(shù)據(jù))本質(zhì)也是plist文件,內(nèi)部做了一層封裝
3. NSKeyedArchiver 歸檔(NSCoding) 存放自定義對(duì)象
4. SQLite
5. CoreData
iOS 每個(gè)應(yīng)用都有一個(gè)獨(dú)立的沙盒,不允許訪問別的沙盒中的數(shù)據(jù)
Documents:`保存應(yīng)用運(yùn)行時(shí)生成的需要持久化的數(shù)據(jù), itunes同步設(shè)備時(shí)會(huì) 備份該目錄例
如,游戲應(yīng)用可將游戲存檔保存在該目錄`
Library
Caches:`保存應(yīng)用運(yùn)行時(shí)生成的需要持久化的數(shù)據(jù), iTunes同步設(shè)備時(shí)不會(huì)備份該目錄。一般存儲(chǔ)體
積大、不需要備份的非重要數(shù)據(jù)`
Preference:`保存應(yīng)用的所有偏好設(shè)置,iOS的 Settings(設(shè)置) 應(yīng)用會(huì)在該目錄中査找應(yīng)用的設(shè)置信息。 iTunesi同步設(shè)備時(shí)會(huì)備份該目錄`
tmp: `保存應(yīng)用運(yùn)行時(shí)所需的臨時(shí)數(shù)據(jù),使用完畢后再將相應(yīng)的文件從該目錄刪除。應(yīng)用沒有運(yùn)行時(shí),系
統(tǒng)也可能會(huì)清除該目錄下的文件。 itunes同步設(shè)備時(shí) 不會(huì)備份該目錄`
ViewController注意點(diǎn)
// 是否隱藏狀態(tài)欄
- (BOOL)prefersStatusBarHidden {
}
導(dǎo)航控制器注意點(diǎn)
#1. 凡是在導(dǎo)航控制器下的 scrollview,會(huì)自動(dòng)設(shè)置一個(gè)上面的內(nèi)邊距64
self, tableview, contentinset = (64, 0, 0, 0)
// 如果不讓它自動(dòng)設(shè)置內(nèi)邊距,可以通過以下方法取消
self. automaticallyadjustsscrollviewinsets = NO;
// iOS 11 新增的方法
UIScrollView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever
# 2. 隱導(dǎo)航控制器的導(dǎo)航條
self.navigationController.navigationbar.hidden = YES
#3. 設(shè)置導(dǎo)航條的透明度
// 導(dǎo)航條以及它里面的子控件設(shè)置透明度是沒有效果的
self.navigationcontroller.navigationbar.alpha = 0;
# 4. 設(shè)置導(dǎo)航條的背景圖片
// 設(shè)置設(shè)置導(dǎo)航條的背景圖片必須得要使用 UIBarMetricsDefault
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"barBg"] forBarMetrics:(UIBarMetricsDefault)];
//如果說導(dǎo)航條的背景圖片設(shè)置的是ni1的話,會(huì)自動(dòng)幫你創(chuàng)建一個(gè)白色的半透明圖片,設(shè)置導(dǎo)航條的背景圖片
[self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:(UIBarMetricsDefault)];
// 設(shè)置導(dǎo)航條的背景圖片為透明
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:(UIBarMetricsDefault)];
// 隱藏導(dǎo)航條下面的陰影圖片
[self.navigationController.navigationBar setShadowImage:[UIImage new]];
# 設(shè)置導(dǎo)航條的字體大小,顏色等:
setTitleTextAttributes:
# 配置全局的導(dǎo)航條樣式 (UIView遵守了這個(gè)協(xié)議UIAppearance)
UINavigationBar *navigationBar = [UINavigationBar appearance];
# 配置指定類的導(dǎo)航條樣式,防止把系統(tǒng)的導(dǎo)航條樣式給修改掉
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[UISplitViewController class]]] setBarTintColor:myColor];
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[UITabBarController class], [UISplitViewController class]]] setBarTintColor:myTabbedNavBarColor];
TableView添加拉伸控件注意點(diǎn)
坐標(biāo)系正方向,水平向右、豎直向下正方向。
contentSize:內(nèi)容,滾動(dòng)范圍,所有cell的集合+頭部,尾部視圖
contentInset:額外滾動(dòng)區(qū)域,超出內(nèi)容,還可以滾動(dòng)多少
contentOffset:移量, tableview頂點(diǎn)與內(nèi)容頂點(diǎn)差值
tableview 默認(rèn)會(huì)滾動(dòng)到最上面
額外滾動(dòng)區(qū)域,不屬于內(nèi)容
導(dǎo)航控制器和tabBarController會(huì)影響contentInset。
設(shè)置tableView指示器的內(nèi)間距
tableView.scrollIndicatorInsets = UIEdgeInsetsMake(64, 0, 49,0);
1. 通過上面的方法設(shè)置導(dǎo)航條透明
2. 不讓導(dǎo)航條自動(dòng)設(shè)置內(nèi)邊距,方法同上
3. 設(shè)置TableView的內(nèi)邊距,目的在當(dāng)前試圖控制器view上添加一個(gè)可拉伸的自定義控件
tableView.contentInset = UIEdgeInsetsMake(kCustomHeaderViewHeight, 0, 0, 0);
設(shè)置后會(huì)造成tableView內(nèi)容的偏移量發(fā)生變化 kTableViewOriginOffsetY =【tableView原點(diǎn)位置減去內(nèi)容原點(diǎn)位置】
4. 計(jì)算scrollView的偏移量
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
#define kCustomHeaderViewOriginHeight 200
#define kTableViewOriginOffsetY -244
//1. 計(jì)算偏移量
// scrollView.contentInset = UIEdgeInsetsMake(244, 0, 0, 0);
// 當(dāng)前scrollView偏移量減去原始的偏移量
CGFloat offsetY = scrollView.contentOffset.y - kTableViewOriginOffsetY;
//2.計(jì)算高度 h = 原始高度 - 偏移量
CGFloat height = kCustomHeaderViewOriginHeight - offsetY;
if (height <= 64) {
height = 64;
}
//3. 更新高度
self.customHeaderViewHeight = height;
//4. 動(dòng)態(tài)求出alpha
// 求變化的值
// 最大值的方法公式
// 1.最大值為多少(最大值為1)
// 2.什么情況下最大(當(dāng)offset 為136.0 最大)
// 當(dāng)offset等于136的時(shí)候 alpha = 1
// 當(dāng)變化的值等于固定的值的時(shí)候?yàn)樽畲?
// 導(dǎo)航條內(nèi)部會(huì)做一次判斷 當(dāng)設(shè)置的背景圖片的alpha == 1,這張圖片會(huì)被設(shè)置半透明
CGFloat alpha = offsetY * 1 / 136.0;
if (alpha >= 1) {
alpha = 0.99;
}
// 根據(jù)顏色,生成一張圖片
UIColor *color = [[UIColor redColor] colorWithAlphaComponent:alpha];
UIImage *image = [UIImage imageWithColor:color];
[self.navigationController.navigationBar setBackgroundImage:image forBarMetrics:(UIBarMetricsDefault)];
// 直接設(shè)置self.navigationItem.titleView.alpha變化是不起效果的
// 設(shè)置titleLabel的textColor跟隨alpha變化
UILabel *titlLabel = (UILabel *)self.navigationItem.titleView;
titlLabel.textColor = [UIColor colorWithWhite:0 alpha:alpha];
}
我的實(shí)現(xiàn)表頭拉伸 eg:
#define kZommedContentViewHeith 244
#define kzommedHeaderViewHeight 200
#define kTableViewOriginOffsetY -244
#define kSepViewHeight 44
@interface PersonDetailViewController ()<UITableViewDataSource,UITableViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UIView *zoomedHeaderView;
@property (nonatomic, strong) UIView *sepView;
@property (nonatomic, strong) UIView *zommedContentView;
@property (nonatomic, assign) CGFloat navigationHegiht;
@end
@implementation PersonDetailViewController
#pragma mark - life cycle
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.tableView];
[self.view addSubview:self.zommedContentView];
[self setupNavigationDefaultConfi];
[self setupLayoutConstraintOfTableView];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.navigationHegiht = self.navigationController.navigationBar.frame.size.height + [[UIApplication sharedApplication] statusBarFrame].size.height;
}
#pragma mark - UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIndentifer = @"cellIndentifer";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIndentifer forIndexPath:indexPath];
cell.textLabel.text = @"哈哈哈哈";
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 30;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// 計(jì)算偏移量
CGFloat offsetY = scrollView.contentOffset.y - kTableViewOriginOffsetY;
// 計(jì)算高度 原始高度 - 偏移量
CGFloat height = kzommedHeaderViewHeight - offsetY;
if (height <= self.navigationHegiht) {
height = self.navigationHegiht;
}
[self.zommedContentView setNeedsLayout];
[self.zommedContentView layoutIfNeeded];
[self.zoomedHeaderView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(height);
}];
// 計(jì)算alpha
CGFloat alpha = 1 * offsetY/(kzommedHeaderViewHeight - self.navigationHegiht);
if (alpha >= 1) {
alpha = 0.99;
}
// 生成帶alpha的顏色
UIColor *color = [[UIColor whiteColor] colorWithAlphaComponent:alpha];
// 根據(jù)顏色生成一張圖片
UIImage *image = [UIImage imageWithColor:color];
[self.navigationController.navigationBar setBackgroundImage:image forBarMetrics:(UIBarMetricsDefault)];
UILabel *label = (UILabel *)self.navigationItem.titleView;
label.textColor = [UIColor colorWithWhite:0 alpha:alpha];
}
#pragma mark - private methods
- (void)setupNavigationDefaultConfi {
if (@available(iOS 11.0, *)) {
self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
// Fallback on earlier versions
self.automaticallyAdjustsScrollViewInsets = NO;
}
UILabel *titleLabel = [UILabel new];
titleLabel.text = @"個(gè)人詳情";
self.navigationItem.titleView = titleLabel;
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:(UIBarMetricsDefault)];
[self.navigationController.navigationBar setShadowImage:[UIImage new]];
UIBarButtonItem *leftBarbutton = [[UIBarButtonItem alloc] initWithTitle:@"點(diǎn)我" style:(UIBarButtonItemStylePlain) target:self action:@selector(clickAction:)];
self.navigationItem.leftBarButtonItem = leftBarbutton;
}
- (void)clickAction:(UIBarButtonItem *)barBtton {
}
- (void)setupLayoutConstraintOfTableView {
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view.mas_safeAreaLayoutGuideLeft);
make.right.equalTo(self.view.mas_safeAreaLayoutGuideRight);
make.top.equalTo(self.view);
make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom);
}];
[self.zommedContentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view.mas_safeAreaLayoutGuideLeft);
make.right.equalTo(self.view.mas_safeAreaLayoutGuideRight);
make.top.equalTo(self.view);
}];
}
#pragma mark getters and setters
- (UITableView *)tableView {
if (_tableView == nil) {
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:(UITableViewStylePlain)];
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cellIndentifer"];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.rowHeight = 80;
_tableView.estimatedRowHeight = 200;
_tableView.estimatedSectionFooterHeight = 0;
_tableView.estimatedSectionHeaderHeight = 0;
_tableView.contentInset = UIEdgeInsetsMake(244, 0, 0, 0);
}
return _tableView;
}
- (UIView *)zoomedHeaderView {
if (_zoomedHeaderView == nil) {
_zoomedHeaderView = [UIView new];
_zoomedHeaderView.backgroundColor = [UIColor greenColor];
_zoomedHeaderView.frame = CGRectMake(0, 0, self.view.bounds.size.width, kzommedHeaderViewHeight);
}
return _zoomedHeaderView;
}
- (UIView *)sepView {
if (_sepView == nil) {
_sepView = [UIView new];
_sepView.frame = CGRectMake(0, kzommedHeaderViewHeight, self.view.bounds.size.width, kSepViewHeight);
_sepView.backgroundColor = [UIColor yellowColor];
}
return _sepView;
}
- (UIView *)zommedContentView {
if (_zommedContentView == nil) {
_zommedContentView = [UIView new];
_zommedContentView.frame = CGRectMake(0, 0, self.view.frame.size.width, kZommedContentViewHeith);
_zommedContentView.backgroundColor = [UIColor blackColor];
[_zommedContentView addSubview:self.zoomedHeaderView];
[_zommedContentView addSubview:self.sepView];
[self.zoomedHeaderView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.equalTo(_zommedContentView);
make.height.mas_equalTo(kzommedHeaderViewHeight);
}];
[self.sepView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.zoomedHeaderView.mas_bottom);
make.left.right.bottom.equalTo(_zommedContentView);
make.height.mas_equalTo(kSepViewHeight);
}];
}
return _zommedContentView;
}
@end
設(shè)置半透明指示器
# 1. 設(shè)置控件本身完全不透明
# 2. 設(shè)置控件背景色半透明
UILabel *hubLabel = [[UILabel alloc] init];
hubLabel.text = @"showHubTipStr";
hubLabel.alpha = 1.0;
hubLabel.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
AutoLayout本質(zhì)是轉(zhuǎn)換成Frame布局
萬能公式:
obj1.property1 = (obj2.property2 * multiplier) + constant value
事件是怎樣產(chǎn)生于傳遞的?
觸摸事件的傳遞是才父控件傳遞到子控件
如果父控件不能接收觸摸事件,那么子控件就不能接收到觸摸事件
一個(gè)控件什么情況下不能夠接受事件?
1. 不能接收用戶交互時(shí)不能夠處理事件 userInteractionEnabled = NO
2. 當(dāng)一個(gè)控件隱藏的時(shí)候不能接收事件 Hidden = YES的時(shí)候
3. 當(dāng)一個(gè)控件為透明時(shí)候也不能接收事件
4. UIImageView,UILabel 默認(rèn)用戶交互是NO
如何尋找最透合的View?
1. 先判斷自己是否能能夠接收觸摸事件,如果能再繼續(xù)往下判斷
2. 在判斷觸摸的當(dāng)前的點(diǎn)在不在自己身上
3. 如果在自己身上,他會(huì)從后往前遍歷子控件,遍歷出每個(gè)子控件后,重復(fù)前面的兩個(gè)步驟
4. 如果沒有符合條件的子控件,那么它自己即使最適合的view
hitTest方法
hitTest方法
作用:尋找最合適的view
參數(shù):當(dāng)前是手指所在的點(diǎn),產(chǎn)生的事件
返回值:返回誰,誰就是最合適的view
什么時(shí)候調(diào)用:只要一個(gè)事件,傳遞給一個(gè)控件時(shí),就會(huì)調(diào)用這個(gè)控件的hitTest方法
-(UIVIew*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
PointInside方法
PointInside方法
判斷觸摸點(diǎn)是否在控件上
以控件坐上角為坐標(biāo)原點(diǎn)
UIResponder
@implementation XLShopResponder
// 觸摸事件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {}
// 加速事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {}
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {}
// 遠(yuǎn)程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {}
- (instancetype)init {
if (self = [super init]) {
}
return self;
}
@end
UITouch
@implementation XLShopTouch
// 返回值表示觸摸在view上的位置
// 這里返回的位置是針對(duì)view的坐標(biāo)系的(以view的左上角為原點(diǎn)(0,O) 調(diào)用時(shí)傳入的view參數(shù)為nil的話,返回的是觸摸點(diǎn)在 UIWindoow的位置
- (CGPoint)locationInView:(UIView *)view {
return [super locationInView:view];
}
//該方法記錄了當(dāng)前試圖,前一次觸摸點(diǎn)的位置。
- (CGPoint)preciseLocationInView:(UIView *)view {
return [super preciseLocationInView:view];
}
@end
@implementation XLResponderView
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
CGPoint prePoint = [touch preciseLocationInView:self];
CGFloat offsetx = currentPoint.x - prePoint.x;
CGFloat offsety = currentPoint.y - prePoint.y;
self.transform = CGAffineTransformTranslate(self.transform, offsetx, offsety);
}
@end
UIEvent
@implementation XLShopEvent
- (instancetype)init {
if (self = [super init]) {
// UIEvent稱為事件對(duì)象,記錄事件產(chǎn)生的類型和時(shí)刻
// 事件的類型
// @property(nonatomic,readonly) UIEventType type API_AVAILABLE(ios(3.0));
// @property(nonatomic,readonly) UIEventSubtype subtype API_AVAILABLE(ios(3.0));
// 事件的時(shí)間戳
// @property(nonatomic,readonly) NSTimeInterval timestamp;
}
return self;
}
@end
@implementation XLResponderView
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
CGPoint prePoint = [touch preciseLocationInView:self];
CGFloat offsetx = currentPoint.x - prePoint.x;
CGFloat offsety = currentPoint.y - prePoint.y;
self.transform = CGAffineTransformTranslate(self.transform, offsetx, offsety);
}
@end
手勢(shì)
@interface XLShopGestureRecognizer ()<UIGestureRecognizerDelegate>
@end
@implementation XLShopGestureRecognizer
#pragma mark life cycle
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// 點(diǎn)擊手勢(shì)
UITapGestureRecognizer *tapGes = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGes:)];
[self addGestureRecognizer:tapGes];
// 平移手勢(shì)
UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGes:)];
panGes.delegate = self;
[self addGestureRecognizer:panGes];
// 相對(duì)于坐標(biāo)系,坐標(biāo)系有大小有方向
// - (CGPoint)translationInView:(nullable UIView *)view;
// 轉(zhuǎn)換后清零操作
// - (void)setTranslation:(CGPoint)translation inView:(nullable UIView *)view
// 旋轉(zhuǎn)手勢(shì)
UIRotationGestureRecognizer *rotationGes = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationGes:)];
rotationGes.delegate = self;
[self addGestureRecognizer:rotationGes];
// 捏合手勢(shì)
UIPinchGestureRecognizer *pinGes = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinGes:)];
pinGes.delegate = self;
[self addGestureRecognizer:pinGes];
// 手勢(shì)默認(rèn)是不能同時(shí)支持多個(gè)手勢(shì)的,可以通過代理設(shè)置shouldRecognizeSimultaneouslyWithGestureRecognizer 返回YES,返回多個(gè)手勢(shì)
}
return self;
}
#pragma mark - event response
- (void)tapGes:(UITapGestureRecognizer *)tap {
}
// 獲取的偏移量是相對(duì)于最原始的點(diǎn)
- (void)panGes:(UIPanGestureRecognizer *)pan {
// 相對(duì)于控件原點(diǎn)的位置的偏移量有大小
// CGPoint point = [pan locationInView:self];
// 相對(duì)于控件坐標(biāo)系的偏移量(有大小方向)
CGPoint point = [pan translationInView:self];
// 方式一:
// 使用帶make松開手第二次再次平移的時(shí)候會(huì),控件的位置又會(huì)回到原點(diǎn)的位置。
// self.transform = CGAffineTransformMakeTranslation(point.x, point.y);
// 方式二:
self.transform = CGAffineTransformTranslate(self.transform, point.x, point.y);
// 清零操作
[pan setTranslation:CGPointMake(0, 0) inView:self];
}
- (void)rotationGes:(UIRotationGestureRecognizer *)rorationGes {
// 獲取選裝角度(已經(jīng)是弧度)
// 相對(duì)于最原始的弧度
CGFloat roration = rorationGes.rotation;
self.transform = CGAffineTransformRotate(self.transform, roration);
// 清零操作
[rorationGes setRotation:0];
}
- (void)pinGes:(UIPinchGestureRecognizer *)pin {
// 放大縮小
// 獲取縮放比例相對(duì)于最原始的比例
CGFloat scale = pin.scale;
self.transform = CGAffineTransformScale(self.transform, scale, scale);
// 清零操作
[pin setScale:1];
}
#pragma mark - UIGestureRecognizerDelegate
// 是否允許接收手勢(shì)事件
// 詢問delegate是否允許手勢(shì)接收者接收一個(gè)touch對(duì)象
// 返回YES,則允許對(duì)這個(gè)touch對(duì)象審核,NO,則不允許。
// 這個(gè)方法在touchesBegan:withEvent:之前調(diào)用,為一個(gè)新的touch對(duì)象進(jìn)行調(diào)用
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// 相對(duì)于控件的原點(diǎn)的位置(有大小)
CGPoint point = [touch locationInView:self];
// 判斷點(diǎn)在控件的左邊還是右邊
if (point.x > self.frame.size.width * 0.5) {
// 在控件的右邊允許Target接收事件
return YES;
}
// 在控件的左邊不允許Target接收事件
return NO;
}
// 是否允許同時(shí)支持多個(gè)手勢(shì),系統(tǒng)默認(rèn)返回NO
// 這個(gè)函數(shù)一般在一個(gè)手勢(shì)接收者要阻止另外一個(gè)手勢(shì)接收自己的消息的時(shí)候調(diào)用
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
// 詢問一個(gè)手勢(shì)接收者是否應(yīng)該開始解析執(zhí)行一個(gè)觸摸的接收事件
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press {
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveEvent:(UIEvent *)event API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos) {
return YES;
}
//下面這個(gè)兩個(gè)方法也是用來控制手勢(shì)的互斥執(zhí)行的
//這個(gè)方法返回YES,第一個(gè)手勢(shì)和第二個(gè)互斥時(shí),第一個(gè)會(huì)失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
//這個(gè)方法返回YES,第一個(gè)和第二個(gè)互斥時(shí),第二個(gè)會(huì)失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
@end
抽屜效果
#define kXLScreenWidth [UIScreen mainScreen].bounds.size.width
#define TargetMaxX (kXLScreenWidth * 0.8)
@interface XLShopDrawViewController ()
@property (nonatomic, strong) UIView *leftView;
@property (nonatomic, strong) UIView *mainView;
@end
@implementation XLShopDrawViewController
#pragma mark - life cycle
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.leftView];
[self.view addSubview:self.mainView];
[self openDraw];
}
#pragma mark - event response
- (void)panGes:(UIPanGestureRecognizer *)pan {
// 結(jié)束偏移操作
if (pan.state == UIGestureRecognizerStateEnded) {
// 控件的相對(duì)于父控件中心點(diǎn)左邊,關(guān)閉抽屜
if (self.mainView.frame.origin.x < kXLScreenWidth * 0.5) {
[self closeDraw];
return;
} else {
// 控件的相對(duì)于父控件中心點(diǎn)右邊,打開抽屜
[self openDraw];
return;
}
}
// 相對(duì)于坐標(biāo)系的偏移量
CGPoint point = [pan translationInView:self.mainView];
[self positionWithOffsetX:point.x];
[pan setTranslation:CGPointZero inView:self.mainView];
}
#pragma mark - publickMethod
- (void)closeDraw {
[UIView animateWithDuration:0.25 animations:^{
// 清空形變
self.mainView.transform = CGAffineTransformIdentity;
// 位置復(fù)位
self.mainView.frame = self.view.bounds;
}];
}
- (void)openDraw {
[UIView animateWithDuration:0.25 animations:^{
CGFloat offset = TargetMaxX - self.mainView.frame.origin.x;
[self positionWithOffsetX:offset];
CGFloat maxX = TargetMaxX;
CGRect targetFrame = self.mainView.frame;
targetFrame.origin.x = maxX;
self.mainView.frame = targetFrame;
}];
}
#pragma mark - private methods
// 根據(jù)原始偏移量,計(jì)算當(dāng)前位置大小
- (void)positionWithOffsetX:(CGFloat)offsetX {
void(^animatonBlock)(void) = ^ {
// 1. 控件偏移量修改
// 方式一:修改frame
// 方式二:做transform形變
// self.mainView.transform = CGAffineTransformTranslate(self.mainView.transform, offsetX, 0);
// 修改mainView的frame
CGRect fram = self.mainView.frame;
fram.origin.x+= offsetX;
// 防止偏移量導(dǎo)致控件的位置偏移到屏幕的左邊
if (fram.origin.x <= 0) {
self.mainView.frame = self.view.bounds;
return;
}
self.mainView.frame = fram;
//2. 控件位置做縮放
// 原始比例:1
// 0.9 0.8 0.7
// 1- 0.1 = 0.9
// 1- 0.2 = 0.8
// 1- 0.3 = 0.7
// 縮放
// 找最大值 最大值是0.3
CGFloat scale = self.mainView.frame.origin.x * 0.3 / kXLScreenWidth;
scale = 1 - scale;
// 做縮放操作
self.mainView.transform = CGAffineTransformMakeScale(scale, scale);
};
[UIView animateWithDuration:0.25 animations:animatonBlock];
}
#pragma mark - getters and setters
- (UIView *)leftView {
if (_leftView == nil) {
_leftView = [UIView new];
_leftView.backgroundColor = [UIColor redColor];
_leftView.frame = self.view.bounds;
}
return _leftView;
}
- (UIView *)mainView {
if (_mainView == nil) {
_mainView = [UIView new];
_mainView.backgroundColor = [UIColor blueColor];
UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGes:)];
[_mainView addGestureRecognizer:panGes];
_mainView.frame = self.view.bounds;
}
return _mainView;
}
@end