iOS仿支付寶首頁效果
代碼地址如下:
http://www.demodashi.com/demo/12776.html
首先看一下效果
狀態欄紅色是因為使用手機錄屏的原因。
1.問題分析
1.導航欄A有兩組控件,隨著tableView的向上滑動,這一組控件的透明度從1到0,然後另一組控件透明度從0到1,如此反復。
2.導航欄下面的一組控件B,隨著tableView向上滑動,也往上滑動,但是滑動值小於tableView的滑動值。透明度逐漸變成0,然後消失。
3.tableView的頭部有一個控件C,跟隨tableView一起滑動,滑動值相同。(很流暢,無卡頓)
4.tableView即控件D的右側滾動條從中間開始。
5.滑動控件B,C,D,tableView均能做出反應。
6.如果tableView滑動較少時,導航欄下面的控件B會根據滑動的多少自動折疊或者完全展開。
很多人看到第4條時,可能會認為tableView從中間開始,其實不一定是這樣。scrollview有一個屬性scrollIndicatorInsets可以設置滾動條的偏移。
我的思路
將控件B,C都加在tableView的視圖上面,這樣滑動的時候,可以直接跟隨tableView滾動(滑動的時候絕度絲滑),另外由於B,C是tableView的子視圖,當滑動的時候無法響應滑動手勢,然後傳遞給tableView滑動手勢響應,這應解決了問題3,5。這樣需要給tableView設置偏移,否則會被B,C擋住一部分。
然後給tableView的scrollIndicatorInsets設置偏移,這樣有一種tableView從中間開始的假象。解決了問題4。
創建各個組件的代碼
- (void)initView { CustrmNav * nav = [CustrmNav custrmNav]; //navBShadowView 背後不響應事件,只是上劃的時候顯示 NavBarBottomView * navBShadowView = [NavBarBottomView navBarBottomView]; navBShadowView.frame = CGRectMake(0, CGRectGetMaxY(nav.frame), Screen_Width, 80); [self.view addSubview:navBShadowView]; //navBottom 響應事件,在滑動 tableView下滑動到0以後出現 NavBarBottomView * navBottom = [NavBarBottomView navBarBottomView]; navBottom.frame = CGRectMake(0, -320, Screen_Width, 80); TabHeaderView * tabHeader = [TabHeaderView tabHeaderView]; tabHeader.frame = CGRectMake(0, -240, Screen_Width, 240); CGFloat backH = nav.height + navBottom.height; CGFloat contentY = tabHeader.height + navBottom.height; //增加背景色View UIView * backView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, Screen_Width, backH)]; backView.backgroundColor = MP_RGBColor(27, 107, 200); [self.view insertSubview:backView atIndex:0]; _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(nav.frame), Screen_Width, Screen_Height-nav.height-MP_TabBarHeight) style:UITableViewStylePlain]; _tableView.delegate = self; _tableView.dataSource = self; //設置偏移量 [_tableView setContentInset:UIEdgeInsetsMake(contentY , 0, 0, 0)]; //假裝tableView 從TabHeaderView 的下部開始的 _tableView.scrollIndicatorInsets = UIEdgeInsetsMake(contentY, 0, 0, 0); //背景透明 _tableView.backgroundColor = [UIColor clearColor]; [self.view addSubview:_tableView]; [_tableView addSubview:navBottom]; [_tableView addSubview:tabHeader]; //放在頂層的 nav 應在在最外層的view [self.view addSubview:nav]; MJRefreshNormalHeader *mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ [self refershAction]; }]; _tableView.mj_header = mj_header; [[SlideManger shareSlideManger] slideMangerCustomNav:nav navBottm:navBottom tabHeader:tabHeader navBottomShadowView:navBShadowView]; }
1.解決第一個問題,自定義導航欄,可以通過檢測tableView的滑動值,來改變A控件內的視圖的透明度來實現。
自定義導航欄代碼Xib布局
#import "CustrmNav.h"
@interface CustrmNav ()
@property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
@property (weak, nonatomic) IBOutlet UIImageView *plusup;
@property (weak, nonatomic) IBOutlet UIImageView *firend;
@property (weak, nonatomic) IBOutlet UIImageView *sao;
@property (weak, nonatomic) IBOutlet UIImageView *pay;
@property (weak, nonatomic) IBOutlet UIImageView *search;
@property (weak, nonatomic) IBOutlet UIImageView *get;
@property (weak, nonatomic) IBOutlet UIImageView *plusdown;
@end
@implementation CustrmNav
+ (id)custrmNav {
NSString * className = NSStringFromClass([self class]);
UINib * nib = [UINib nibWithNibName:className bundle:nil];
CustrmNav * nav = [nib instantiateWithOwner:nil options:nil].firstObject;
[nav updateAlpha:0.0];
nav.frame = CGRectMake(0, 0, Screen_Width, MP_NavBarHeight);
return nav;
}
- (void)updateAlpha:(float)alpha {
//上部分
_sao.alpha = (alpha-0.5) * 2;
_pay.alpha = (alpha-0.5) * 2;
_plusup.alpha = (alpha-0.5) * 2;
_get.alpha = (alpha-0.5) * 2;
_search.alpha = (alpha-0.5) * 2;
//下部分
_searchBar.alpha = 1 - alpha * 2;
_plusdown.alpha = 1 - alpha * 2;
_firend.alpha = 1 - alpha * 2;
//當滑到一定的位置,背景變成有色
if (alpha >= 1.0) {
self.backgroundColor = MP_RGBColor(27, 107, 200);
} else {
self.backgroundColor = [UIColor clearColor];
}
}
2.解決問題二,我是為B控件又創建了一個分身B1放到tabelView的背後視圖上。當向上滑動的時候,B隱藏B1顯示,然後根據tableView的滑動距離,改變B1的Y值。另外改變裏面的小組件的透明度
處理各個組件的透明度以及動畫效果管理類
#import "SlideManger.h"
#import <UIKit/UIKit.h>
#import "CustrmNav.h"
#import "NavBarBottomView.h"
@interface SlideManger ()<NSCopying, NSMutableCopying>
@property(nonatomic,weak)NavBarBottomView * navBottmView;
@property(nonatomic,weak)NavBarBottomView * navBShadowView;
@property(nonatomic,weak)UIView * tabHeader;
@property(nonatomic,weak)CustrmNav * customNav;
@end
static SlideManger * _slideManger = nil;
@implementation SlideManger
+ (id)shareSlideManger {
return [[self alloc] init];
}
+ (id)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (_slideManger == nil) {
_slideManger = [super allocWithZone:zone];
}
});
return _slideManger;
}
- (id)copyWithZone:(NSZone *)zone {
return _slideManger;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
return _slideManger;
}
- (void)slideMangerCustomNav:(UIView *)customNav navBottm:(UIView *)navBottmView tabHeader:(UIView *)tabHeader navBottomShadowView:(UIView *)navBShadowView {
if (navBottmView) {
_navBottmView = (NavBarBottomView *)navBottmView;
}
if (tabHeader) {
_tabHeader = tabHeader;
}
if (customNav) {
_customNav = (CustrmNav *)customNav;
}
if (navBShadowView) {
_navBShadowView = (NavBarBottomView *)navBShadowView;
}
}
//滑動的時候
- (void)tableViewSlide:(CGFloat)slide {
if (_navBShadowView && _tabHeader) {
//得到真實的偏移量,讓slideY從0開始算起
CGFloat slideY = slide + _navBShadowView.height + _tabHeader.height;
// NSLog(@"******%f",slideY);
[self handleTabHeader:slideY];
[self handleCustomNavNavBottom:slideY];
}
}
//tableView 停止的時候
- (void)tabViewEndSlide:(CGFloat)slide scrollView:(UIScrollView *)scrollView {
if (_navBShadowView && _tabHeader) {
//得到真實的偏移量
CGFloat slideY = slide + _navBShadowView.height + _tabHeader.height;
if (slideY > 0) {
if (slideY >= _navBShadowView.height/2 && slideY < _navBShadowView.height) {
//自動滑到上面
[scrollView setContentOffset:CGPointMake(0, -_tabHeader.height) animated:YES];
} else if (slideY < _navBShadowView.height/2) {
//自動滑下去
[scrollView setContentOffset:CGPointMake(0, -(_navBShadowView.height + _tabHeader.height)) animated:YES];
}
}
}
}
//處理 TabHeader 跟隨 tableView 滑動
- (void)handleTabHeader:(CGFloat)slide {
static BOOL isDown = NO;
if (slide <= 0) {
_navBottmView.hidden = NO;
_navBShadowView.hidden = YES;
//tableView往下滑的時候,禁止 _tabHeader與_navBottmView一起下滑
_tabHeader.y = -_tabHeader.height + slide;
_navBottmView.y = -(_navBShadowView.height + _tabHeader.height) + slide;
isDown = YES;
} else {
_navBottmView.hidden = YES;
_navBShadowView.hidden = NO;
if (isDown) {
_tabHeader.y = -_tabHeader.height;
isDown = NO;
}
}
}
//處理customnav 的漸變色問題 以及navbottom 影子 的位置 漸變色問題
- (void)handleCustomNavNavBottom:(CGFloat)slide {
if (slide >= 0) {
CGFloat halfNavBottomH = _navBShadowView.height/2;
CGFloat alpValue = (_navBShadowView.height - slide)?(_navBShadowView.height - slide):0;
[_navBShadowView updateAlpha:alpValue/_navBShadowView.height];
[_customNav updateAlpha:slide/_navBShadowView.height];
if (slide<= _navBShadowView.height) {
_navBShadowView.y = _customNav.height - slide/2;
} else {
_navBShadowView.y = _customNav.height - halfNavBottomH;
}
} else {
[_navBShadowView updateAlpha:1.0];
[_customNav updateAlpha:0.0];
_navBShadowView.y = _customNav.height;
}
}
@end
6.解決問題六,主要是scrollView的 代理的滾動停止的方法和拖拽停止的方法確定不會再滾動的時候。依據滾動停止tableView滑動量來確定是展開還是折疊。
//tableView 停止的時候
- (void)tabViewEndSlide:(CGFloat)slide scrollView:(UIScrollView *)scrollView {
if (_navBShadowView && _tabHeader) {
//得到真實的偏移量
CGFloat slideY = slide + _navBShadowView.height + _tabHeader.height;
if (slideY > 0) {
if (slideY >= _navBShadowView.height/2 && slideY < _navBShadowView.height) {
//自動滑到上面
[scrollView setContentOffset:CGPointMake(0, -_tabHeader.height) animated:YES];
} else if (slideY < _navBShadowView.height/2) {
//自動滑下去
[scrollView setContentOffset:CGPointMake(0, -(_navBShadowView.height + _tabHeader.height)) animated:YES];
}
}
}
}
項目結構圖
iOS仿支付寶首頁效果
代碼地址如下:
http://www.demodashi.com/demo/12776.html
註:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權
iOS仿支付寶首頁效果