ScrollView自動佈局技巧
阿新 • • 發佈:2018-12-31
scrollView自動佈局技巧
- 步驟:
1. sb中拖scrollView
2. 設定scrollView上下左右為0
4. 拖一個UIView"yellowView"到scrollView中(不是imageView)
5. 設定yellowView的自動佈局上下左右為0(此時報錯,實際缺少尺寸"無法算出contentSize")
6. 設定yellowView和scrollView等寬等高
7. 更新frame,並執行
- 此時無法滾動,因為contentSize和scrollView的size一樣大
8.設定yellowView寬約束的是scrollView寬的2倍,並執行
- 此時 可以滾動了,因為yellowView的寬大於scrollView自身的寬
9. 設定yellowView頂部約束為64,並執行,會影響它的contentSize
10. 給yellowView上的新增按鈕,並設定約束,演示分頁屬性,並執行
- 實驗小結:
1. 設定scrollView中內容的距離scrollView四邊邊距值,會影響contentSize即滾動範圍,上下間距
會影響contentSize的Hieght"垂直滾動範圍",左右間距會影響水平滾動範圍(不常用,瞭解裝逼使用)
2. 如果用AutoLayout約束scrollView中的內容時只設置四邊間距約束是不夠的,還要設定view寬高
3. 除了UIImageView可以不用直接設定寬高,因為它裡面如果設定了圖片,imageView的size會根據圖片
自適應,對應設定 scrollView的contentSize
4. 切記scrollView在實用自動佈局時比較特殊
5. 建議:如果一個scrollView中有很多小控制元件可以把小控制元件新增一個容器檢視 view,設定容器view的尺
寸為contentSize
scrollView-代理方法
- scrollViewDidScroll: 滾動檢視滾動時使用
- scrollViewDidEndDecelerating: 滾動檢視停止滾動時使用
- viewForZoomingInScrollView: 縮放檢視時使用
- 滾動相關方法
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSLog(@"%@", @"scrollview檢視開始滾動");
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
NSLog(@"%@", @"將要減速 - 在釋放開手之後呼叫");
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSLog(@"%@", @"完成減速 - 完全靜止後呼叫");
}
- 縮放相關方法
實現縮放的兩個步驟
- 需要設定最小縮放比例(minimumZoomScale)和最大縮放比例(maximumZoomScale)都為1時無法縮放
- 需要實現 “viewForZoomingInScrollView” 方法 告訴 scrollView 縮放的檢視
( 只要縮放就會呼叫 )
// 告訴滾動檢視縮放的檢視
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return _imageView;
}
// @param scrollView 滾動檢視
// @param view 縮放的檢視
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view {
NSLog(@"%@", @"縮放開始時呼叫");
}
/// @param scrollView 滾動檢視
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
NSLog(@"%@",@"正在縮放時呼叫");
}
/// @param scrollView 滾動檢視
/// @param view 縮放的檢視
/// @param scale 縮放的比例
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale {
NSLog(@"%@",@" 縮放結束後呼叫");
}
- 拖拽相關方法
/// @param scrollView 滾動檢視
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
NSLog(@"%@", @"將要開始拖拽");
}
/// @param scrollView 滾動檢視
/// @param velocity 速度
/// @param targetContentOffset 目標偏移位置
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
NSLog(@"%@", @"將要結束拖拽");
}
/// @param scrollView 滾動檢視
/// @param decelerate 是否減速
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSLog(@"%@ %d", @"完成拖拽方法,手指放開後呼叫", decelerate);
}
- 狀態列相關方法
結合 self.scrollView.scrollsToTop = YES;使用要告訴它點了狀態列對那個scrollView進行滾動
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
NSLog(@"%@", @"將要滾動到頂部,點選狀態列時呼叫");
return YES;
}
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
NSLog(@"%@", @"已經滾動到狀態列");
}
- 動畫相關方法
/**
The scroll view calls this method at the end of its implementations of the setContentOffset:animated: and scrollRectToVisible:animated: methods, but only if animations are requested.
滾動檢視會在實現了 setContentOffset:animated: & scrollRectToVisible:animated: 方法之後
呼叫此方法
同時必須在上述兩個方法中允許動畫
*/
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
NSLog(@"%@", @"呼叫動畫結束");
}
關於代理設計模式
- 自己想幹一件事,但是自己不能主動完成/不能完成,要找一個物件幫自己完成
scrollView知道被滾動了,但是不知道被滾動以後將要做什麼
手寫代理步驟
- 找人做事情的人
- 協議
- 協議中的方法
- 代理物件屬性
- 在需要做事情的’時候’,通過代理物件,執行協議中的方法
- 做事情的人
- 遵守協議
- 設定代理物件
- 實現代理方法,在代理方法中做事情
- 找人做事情的人
ScrollView-屬性
- contentSize: 內容大小,設定了才可以滾動
- contentOffset: 內容偏移位置
- contentInset: 內容間距
- pagingEnabled: 是否允許分頁
- bounces: 是否允許彈簧效果
- showsHorizontalScrollIndicator: 是否允許顯示水平指示器(滾動條)
- showsVerticalScrollIndicator: 是否允許顯示垂直指示器(滾動條)
- 滾動內容屬性
// 內容偏移位置
@property(nonatomic) CGPoint contentOffset; // default CGPointZero
// 內容大小,設定了才可以滾動
@property(nonatomic) CGSize contentSize; // default CGSizeZero
// 內容間距
@property(nonatomic) UIEdgeInsets contentInset;
- 委託屬性
@property(nullable,nonatomic,weak) id<UIScrollViewDelegate> delegate;
要想監聽滾動檢視的滾動 / 拖拽 / 縮放 / 狀態列互動
需要設定 delegate
實現相關協議方法
- 彈簧效果屬性
// 允許彈簧效果
@property(nonatomic) BOOL bounces; // default YES. if YES, bounces past edge of content and back again
// 始終允許垂直彈
@property(nonatomic) BOOL alwaysBounceVertical; // default NO. if YES and bounces is YES, even if content is smaller than bounds, allow drag vertically
// 始終允許水平彈
@property(nonatomic) BOOL alwaysBounceHorizontal;
- 分頁屬性
// 允許分頁
@property(nonatomic,getter=isPagingEnabled) BOOL pagingEnabled __TVOS_PROHIBITED;// default NO. if YES, stop on multiples of view bounds
- 指示器屬性
// 顯示水平指示器
@property(nonatomic) BOOL showsHorizontalScrollIndicator; // default YES. show indicator while we are tracking. fades out after tracking
// 顯示垂直指示器
@property(nonatomic) BOOL showsVerticalScrollIndicator; // default YES. show indicator while we are tracking. fades out after tracking
// 指示器間距
@property(nonatomic) UIEdgeInsets scrollIndicatorInsets; // default is UIEdgeInsetsZero. adjust indicators inside of insets
// 指示器樣式
@property(nonatomic) UIScrollViewIndicatorStyle indicatorStyle; // default is UIScrollViewIndicatorStyleDefault
在 scrollView 中指示器本質上就是 UIImageView
通過檢視檢視層次結構可以看到
- 縮放屬性
// 最小縮放比例
@property(nonatomic) CGFloat minimumZoomScale; // default is 1.0
// 最大縮放比例
@property(nonatomic) CGFloat maximumZoomScale; // default is 1.0. must be > minimum zoom scale to enable zooming
要允許縮放
必須設定以上兩個屬性
同時遵守協議
實現協議方法 -viewForZoomingInScrollView:
- 狀態列屬性
// 點選狀態列滾動到頂部
// default is YES. TVOS上此屬性禁用,
@property(nonatomic) BOOL scrollsToTop __TVOS_PROHIBITED;
一個檢視中,如果有多個 scrollView
只有唯一一個 scrollView 的 scrollsToTop 屬性設定為 YES,才支援點選狀態列滾動到頂部
雖然此屬性預設值即為YES不過還要要設定,不然不知道點了狀態列要對那個scrollView進行滾動
- 鍵盤屬性
// 鍵盤解除模式
@property(nonatomic) UIScrollViewKeyboardDismissMode keyboardDismissMode NS_AVAILABLE_IOS(7_0); // default is UIScrollViewKeyboardDismissModeNone
如果是 UITextView,通常需要將 alwaysBounceVertical 屬性設定為 YES
typedef NS_ENUM(NSInteger, UIScrollViewKeyboardDismissMode) {
// 無
UIScrollViewKeyboardDismissModeNone,
// 拖拽關閉鍵盤
UIScrollViewKeyboardDismissModeOnDrag, // dismisses the keyboard when a drag begins
// 必須要拖拽到鍵盤才可以關閉鍵盤,很少使用
UIScrollViewKeyboardDismissModeInteractive, // the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss
} NS_ENUM_AVAILABLE_IOS(7_0);
- 常用方法
// 動畫設定偏移位置
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated; // animate at constant velocity to new offset
// 動畫設定滾動區域
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated; // scroll so rect is just visible (nearest edges). nothing if rect completely visible
- 三種影象填充模式
- scale的意思是:縮放,在contentMode中出現的話,就是要改變圖形的大小了。
- aspect的意思是縱橫的比例,在contentMode中的意思是保持圖形的縱橫比,保持圖片不變形。
scale to fill:縮放圖片,使圖片充滿容器。因為沒有aspect,所以是不保持縱橫比的。圖片不是按比例縮放的。
scale aspect fit: 在保持縱橫比(aspect)的前提下,縮放圖片(scale),使圖片在容器內都顯示出來(fit)。
保證圖片完整顯示,但不保證能充滿容器。
scale aspect fill:在保持縱橫比(aspect)的前提下,縮放圖片(scale),使圖片充滿容器(fill)。保證圖片能
充滿容器,不保證圖片能完整顯示。
新特性檢視規則
新特性檢視
- 自動佈局的選擇?
- 如果是全屏的直接bounds,如果不是考慮使用自動佈局
- 並不是每次都需要現實新特性介面,所以留個後路,以後再改
- 建立控制元件時呼叫init或initWithFrame方法最後都會去呼叫物件父類的initWithFrame方法
隱藏狀態列
- 隱藏狀態來這些不屬於顯示也不屬於資料,所以應該再C中找.
- -(BOOL)prefersStatusBarHidden
傳遞資料思路對比
- View直接寫資料?(1)
- 控制器傳遞給View?(2)
- 可能面臨到檢視移植的問題,也就說,如果我另外一個專案也需要同樣的需求,那麼:
- 如果使用第一種方式,需要做的工作.
- 拷貝檔案,更改view內部中的圖片名稱.
- 如果使用第二種方式,需要做的工作.
- 拷貝檔案,在控制器重新寫資料,傳入view.
- 如果使用第一種方式,需要做的工作.
- 檢視只負責現實,控制器負責排程.
- 兩種方式,沒有對不對,只有合不合適.
將新特性陣列傳遞給新特性
- 新建一個裝滿imageName的陣列傳遞給檢視
設定scrollView的frame
- 建立scrollView並設定frame
ZFBGuideView *guideView = [[ZFBGuideView alloc] initWithFrame:self.view.bounds];
ZFBGuideView *guideView = [[ZFBGuideView alloc] init];
guideView.frame = self.view.bounds;
- 兩種寫法都會呼叫initWithFrame
- 重寫了initWithFrame並且同時重寫了init的方法,第一種形式的方法不會再呼叫init
- 設定子控制元件的frame應該使用layoutSubviews
- layoutSubviews一定要重寫父方法
- 約束的程式碼不能寫在layoutSubviews方法中,此方法會多次呼叫
scrollView顯示圖片並設定屬性
- setImageNames方法中新增imageView到scrollView中
- 並且設定影象和contentSize
- 分頁
- 水平和垂直指示器(方便使用subviews)
- 禁用彈性
設定更多按鈕的自動佈局
- 新增到imageView上
- 開啟使用者互動
- userInteractionEnabled(bool)
新增按鈕監聽/新特性移除動畫
- 通過transform和透明度做動畫
- 移除整個新特性檢視
使用程式碼建立pageControl
- 應該新增到新特性檢視上,如果新增到scrollView上會跟著滾動
- 禁用分頁的使用者互動
pageControl位置/設定總頁數
- 自動佈局設定pageControl位置
- 總頁數應該根據圖片數量來,所以寫在setImageNames方法中
設定pageControl當前頁數
- 在結束滾動的代理方法中,根據offset和scrollView的寬度進行計算
- 或者
- 在正在滾動的代理方法中,根據offset和scrollView的寬度進行計算(加0.4999再強轉)
拖拽細節/隱藏pageControl
- 需求的最右可以拖拽,思考怎麼樣增加?
- 根據頁數進行pageControl的隱藏和現實.