這篇博客主要是對前一個案例進行優化。還有一個問題是,在自動布局Masonry結合ScrollView中,會碰到一些坑和技巧,也是我們主要解決的問題。項目代碼上傳至 https://github.com/chenyufeng1991/ShowHiddenKeyboard 。
今天要實現的效果如下:
。
由於大部分功能和之前的類似,我把重點放在ScrollView和Masonry的結合上。
(1)UI布局的思路是:最外面是一個ScrollView,然後裡面放一個取名為contentView的UIView,作為放置其他元素的容器。contentView的高度會隨著內部元素的總高度的變化而變化,也就是ScrollView需要滾動的總高度。
// 最外部的scrollView self.scrollView = [[UIScrollView alloc] init]; self.scrollView.backgroundColor = [UIColor orangeColor]; self.scrollView.scrollEnabled = YES; self.scrollView.userInteractionEnabled = YES; self.scrollView.bounces = NO; self.scrollView.delegate = self; self.automaticallyAdjustsScrollViewInsets = NO; [self.view addSubview:self.scrollView]; [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(weakSelf.view).offset(64); make.left.equalTo(weakSelf.view); make.right.equalTo(weakSelf.view); make.bottom.equalTo(weakSelf.view); }]; // 包含所有子View的容器 self.contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 64, [[UIScreen mainScreen] bounds].size.width, 200)]; self.contentView.backgroundColor = [UIColor redColor]; [self.scrollView addSubview:self.contentView]; [self.contentView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(weakSelf.scrollView); make.width.equalTo(weakSelf.scrollView); }];
在設置scrollView時建議加上self.automaticallyAdjustsScrollViewInsets = NO。這個參數比較坑爹,默認是YES,也就是默認在你使用scrollView的時候給你加了內邊距,而這個往往是我們不需要的。如果默認置為YES的話,發現UI怎麼都調不出我們想要的效果,往往會在頂部一部分。【ps:其實在這裡你也可以考慮到是導航欄的原因,看你個人需求是ScrollView是否要到達屏幕頂部還是只到達導航欄底部。】
(2)由於我要讓界面有滑動的效果,所以要讓ScrollView裡面的contentSize大於height,所以我在下面鋪了一張很長的圖片來模擬。
self.bottomImageView = [[UIImageView alloc] init]; self.bottomImageView.image = [UIImage imageNamed:@"bottom"]; [self.contentView addSubview:self.bottomImageView]; [self.bottomImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(weakSelf.collectionView.mas_bottom).offset(20); make.left.equalTo(weakSelf.contentView); make.right.equalTo(weakSelf.contentView); make.height.equalTo(@500); }];
(3)其實自動布局寫到這裡的時候,所有的設置都已經完成了。但是一運行代碼,發現並不是這樣的。ScrollView根本就不能滾動。原來想的是:contentView由於add了很多的元素,所以contentView的高度就應該是這些元素實際布局中的總和。Masonry理應有這種自動計算的功能,但事實卻不是這樣的。調試上面的代碼會發現contentView的高度居然是0. 查看約束設置代碼,我們的確沒有顯式的設置高度。很遺憾,Masonry沒有自動完成這個功能。所以需要在上面的子元素約束完成以後,實現如下代碼:
// 這裡要重新設置容器的高度,其實只要固定底部即可。 [self.contentView mas_updateConstraints:^(MASConstraintMaker *make) { make.bottom.equalTo(self.bottomImageView); }];更新contentView容器的約束。也就是添加了底部約束到那張長長的圖片的底部,這樣也就相當於設置了高度。這樣ScrollView就能正常滾動了。
(4)對於CollectionView的處理同前一個案例一樣,這裡不再贅述。由於添加了ScrollView,所以原先touchesEnded方法就不會被調用了,因為手勢操作首先會去觸發ScrollView中的操作。所以我們就要來實現ScrollViewDelegate中的方法來實現鍵盤隱藏。
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [self hideKeyboard]; }
UITapGestureRecognizer *tapView = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)]; [self.contentView addGestureRecognizer:tapView];
經過以上實現後,就能實現ScrollView、CollectionView和鍵盤之間的事件處理了,也就是上面Gif中的動效。其實實現的關鍵就是上面ScrollView和Masonry的結合上。