探索iPhone控制中心交互實(shí)現(xiàn)

【項(xiàng)目Github地址】
先展示一張效果圖:

Untitled.gif

從圖片上可以看出都是彈簧效果忧勿,自然而然就會(huì)想到用系統(tǒng)的UIScrollView類來實(shí)現(xiàn)。
接下來我將仔細(xì)的一步步的教你完成這個(gè)項(xiàng)目孕暇。
首先咱們先創(chuàng)建一個(gè)工程蜓氨,打開ViewController.m文件,我們先簡單創(chuàng)建一個(gè)UIScrollView突倍,讓他的contentSize為兩倍的屏幕寬度腔稀,再加入兩張圖片。
代碼如下:

#import "ViewController.h"

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
#define kLeftRightMargin 8
#define kBottomMargin 16
#define kImageViewWidth (kScreenWidth - kLeftRightMargin*2)
#define kImageViewHeight (kImageViewWidth*392/344.5)
#define kImageViewY (kScreenHeight - kBottomMargin - kImageViewHeight)

@interface ViewController () <UIScrollViewDelegate>
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIImageView *leftView;
@property (nonatomic, strong) UIImageView *rightView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor lightGrayColor];
    self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
    self.scrollView.delegate = self;
    self.scrollView.contentSize = CGSizeMake(kScreenWidth*2, kScreenHeight);
    self.scrollView.pagingEnabled = YES;
    self.scrollView.showsHorizontalScrollIndicator = NO;
    self.scrollView.showsVerticalScrollIndicator = NO;
    [self.view addSubview:self.scrollView];
    
    self.leftView = [[UIImageView alloc] initWithFrame:CGRectMake(kLeftRightMargin, kImageViewY, kImageViewWidth, kImageViewHeight)];
    self.leftView.backgroundColor = [UIColor yellowColor];
    self.leftView.layer.cornerRadius = 15;
    self.leftView.layer.masksToBounds = YES;
    [self.scrollView addSubview:self.leftView];
    
    self.rightView = [[UIImageView alloc] initWithFrame:CGRectMake(kLeftRightMargin+kScreenWidth, kImageViewY, kImageViewWidth, kImageViewHeight)];
    self.rightView.backgroundColor = [UIColor greenColor];
    self.rightView.layer.cornerRadius = 15;
    self.rightView.layer.masksToBounds = YES;
    [self.scrollView addSubview:self.rightView];
}
@end

運(yùn)行之后羽历,你將看到如下圖的效果:


初始化工程.gif

但是你們也會(huì)發(fā)現(xiàn)有如下的反應(yīng)焊虏,向上向下并沒有彈性效果:


上下沒有彈性.gif

因?yàn)榇藭r(shí)scrollView的高度和它contentSize的高度是相同的,所以它在橫向上是可以滾動(dòng)的秕磷,而縱向上就不可以了诵闭。但是我們想要縱向也有彈性效果,腫么辦?如果你熟悉UIScrollView疏尿,你就曉得有一個(gè)屬性可以讓它簡單實(shí)現(xiàn)了瘟芝。
咱們?cè)趧?chuàng)建scrollView的地方加入一行代碼:

...
self.scrollView.alwaysBounceVertical = YES; // <--
[self.view addSubview:self.scrollView];

效果圖如下:

上下彈性.gif

但此時(shí)可能你會(huì)發(fā)現(xiàn)另一個(gè)問題,此時(shí)的scrollView滾動(dòng)的方向沒有限制:

方向無限制.gif

那咱們就去UIScrollView頭文件里去瞧瞧褥琐,說不定蘋果爸爸已經(jīng)給我們預(yù)設(shè)了解決辦法了也說不定模狭。
很快你就會(huì)看到有這樣一個(gè)屬性定義

@property(nonatomic,getter=isDirectionalLockEnabled) BOOL directionalLockEnabled;         // default NO. if YES, try to lock vertical or horizontal scrolling while dragging

那就用起來:

    self.scrollView.alwaysBounceVertical = YES;
    self.scrollView.directionalLockEnabled = YES; // <--
    [self.view addSubview:self.scrollView];

突然很神奇般的,好像是有效了踩衩。至少我在iOS10.3的模擬器上是沒問題嚼鹉,但是如果你在真機(jī)上運(yùn)行的話,試試你就會(huì)發(fā)現(xiàn)驱富,當(dāng)你滑動(dòng)角度在45°左右的時(shí)候锚赤,前面設(shè)置的方向鎖屬性就不生效沒用了。

仍然存在問題.gif

蘋果官方也承認(rèn)這個(gè)是個(gè)BUG了褐鸥。在stackoverflow上也有在討論這個(gè)問題线脚。
我在上面選擇了一個(gè)解決方式,實(shí)現(xiàn)UIScrollViewdelegate叫榕,代碼如下:

@interface ViewController () <UIScrollViewDelegate>
...
@property (nonatomic, assign) CGPoint beginDragPoint;
@end
@implementation ViewController
...
#pragma mark - UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    _beginDragPoint = scrollView.contentOffset;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.contentOffset.x == _beginDragPoint.x) {
        self.scrollView.contentOffset = CGPointMake(_beginDragPoint.x, (self.scrollView.contentOffset.y));
    } else {
        self.scrollView.contentOffset = CGPointMake((self.scrollView.contentOffset.x), _beginDragPoint.y);
    }
}
@end

接下來說說另一個(gè)問題浑侥,手勢(shì)向下移動(dòng)過程中,手指移動(dòng)多少視圖就移動(dòng)多少晰绎,而我們寫的工程卻還是彈性的寓落。

系統(tǒng)向下移.gif

工程向下移.gif

我的思路就是,那么就讓scrollViewcontentSize高度大于本身的高度吧荞下,那么也能手移動(dòng)多少伶选,他就移動(dòng)多少了。那高度設(shè)為多少合適呢尖昏?你可以先自己嘗試看看仰税,我最終的結(jié)果是兩倍的本身高度,感覺非常巧妙抽诉,最后視圖消失與否都通過pagingEnabled已經(jīng)搞定了陨簇。
修改代碼如下:

// #define kImageViewY (kScreenHeight - kBottomMargin - kImageViewHeight)
#define kImageViewY (kScreenHeight*2 - kBottomMargin - kImageViewHeight)

    self.scrollView.delegate = self;
//    self.scrollView.contentSize = CGSizeMake(kScreenWidth*2, kScreenHeight);
    self.scrollView.contentSize = CGSizeMake(kScreenWidth*2, kScreenHeight*2); // <--
    self.scrollView.contentOffset = CGPointMake(0, kScreenHeight); // <--
    self.scrollView.pagingEnabled = YES;

效果圖如下:

消失出現(xiàn).gif

好了,基本大功告成了迹淌。但是還有一個(gè)致命的問題河绽,一般人找不到解決辦法,我也是不斷嘗試才發(fā)現(xiàn)原來還可以這么整巍沙。
問題就是葵姥,當(dāng)手指在非視圖區(qū)域移動(dòng)時(shí),視圖是不會(huì)動(dòng)不會(huì)有反應(yīng)的句携,一旦移動(dòng)到靠近視圖的時(shí)候榔幸,視圖才開始移動(dòng)的。如圖:

非視圖區(qū).gif

先分析一下,UIScrollView的滾動(dòng)時(shí)因?yàn)閮?nèi)部封裝的pan手勢(shì)削咆,那我們可不可以拿到手勢(shì)調(diào)用的方法牍疏,重寫它,然后判斷如果手指沒有到達(dá)位置時(shí)拨齐,手勢(shì)的UIGestureRecognizerStateChanged事件就不傳遞給父類鳞陨,父類就不能處理,那么視圖就不會(huì)移動(dòng)了瞻惋。
我們先來找找事件方法:

WechatIMG10.jpeg

打斷點(diǎn)發(fā)現(xiàn)厦滤,手勢(shì)屬性里有個(gè)SEL方法handlePan:,嗯歼狼,應(yīng)該就是它了掏导,創(chuàng)建一個(gè)UIScrollView的子類重寫這個(gè)方法吧。

// 創(chuàng)建類
@interface LYScrollView : UIScrollView
@end
@implementation LYScrollView
- (void)handlePan:(UIPanGestureRecognizer *)pan {
    NSLog(@"%s", __func__);
}
@end
.
.
#import "LYScrollView.h"
// 替換創(chuàng)建方法
// @property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) LYScrollView *scrollView;
...
// self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView = [[LYScrollView alloc] initWithFrame:self.view.bounds];

很是令人欣慰啊羽峰,方法回調(diào)了趟咆。


屏幕快照 2017-03-06 上午11.03.54.png

可是問題又出現(xiàn)了,當(dāng)滿足條件的時(shí)候梅屉,我要把事件還給父類的值纱,可是編譯器通過不了:

屏幕快照 2017-03-06 上午11.07.20.png

(個(gè)人想的比較挫的解決方法啊,有好的方式麻煩告知下哈坯汤。)
再創(chuàng)建一個(gè)中間類虐唠,聲明一個(gè)handlePan:方法。玫霎。凿滤。

@interface MyScrollView : UIScrollView
- (void)handlePan:(UIPanGestureRecognizer *)pan;
@end
@interface LYScrollView : MyScrollView
@end
// 去除`.m`文件因?yàn)闆]有實(shí)現(xiàn)該方法而有的警告問題
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincomplete-implementation"
@implementation MyScrollView
#pragma clang diagnostic pop
@end

最終方法實(shí)現(xiàn)如下:

@implementation LYScrollView {
    BOOL _canMove;
}

- (void)handlePan:(UIPanGestureRecognizer *)pan {
    CGPoint point = [pan locationInView:pan.view];
    
    if (pan.state == UIGestureRecognizerStateBegan) {
        [pan setTranslation:CGPointZero inView:pan.view];
        [super handlePan:pan];
    } else if (pan.state == UIGestureRecognizerStateChanged) {
        
        // 一旦手指位置到達(dá)視圖時(shí)妈橄,則開始移動(dòng)
        if (!_canMove && point.y > kImageViewY) {
            _canMove = YES;
            [pan setTranslation:CGPointZero inView:pan.view];
        }
        
        if (_canMove) {
            [super handlePan:pan];
        }
        
    } else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) {
        _canMove = NO;
        [pan setTranslation:CGPointZero inView:pan.view];
        [super handlePan:pan];
    }
}
@end

這邊需要[pan setTranslation:CGPointZero inView:pan.view];調(diào)用一下庶近,將手勢(shì)的位置初始化為零后,再傳給父類眷蚓,不然就位置突變了鼻种。

最終效果.gif

大問題都解決完啦,剩下的背景色漸變沙热、出現(xiàn)消失叉钥、再封裝等實(shí)現(xiàn)就不在這里贅述了,可去看下工程代碼篙贸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末投队,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子爵川,更是在濱河造成了極大的恐慌敷鸦,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異扒披,居然都是意外死亡值依,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門碟案,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愿险,“玉大人,你說我怎么就攤上這事价说×究鳎” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵鳖目,是天一觀的道長矮台。 經(jīng)常有香客問我,道長辈灼,這世上最難降的妖魔是什么傲须? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮惦费,結(jié)果婚禮上兵迅,老公的妹妹穿的比我還像新娘。我一直安慰自己薪贫,他們只是感情好恍箭,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瞧省,像睡著了一般扯夭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鞍匾,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天交洗,我揣著相機(jī)與錄音,去河邊找鬼橡淑。 笑死构拳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的梁棠。 我是一名探鬼主播置森,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼符糊!你這毒婦竟也來了凫海?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤男娄,失蹤者是張志新(化名)和其女友劉穎行贪,沒想到半個(gè)月后把兔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瓮顽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年县好,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暖混。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缕贡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拣播,到底是詐尸還是另有隱情晾咪,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布贮配,位于F島的核電站谍倦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏泪勒。R本人自食惡果不足惜昼蛀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望圆存。 院中可真熱鬧叼旋,春花似錦、人聲如沸沦辙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽油讯。三九已至详民,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陌兑,已是汗流浹背沈跨。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诀紊,地道東北人谒出。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像邻奠,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子为居,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫碌宴、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,059評(píng)論 4 62
  • 持續(xù)一周多蒙畴,終于把自己的個(gè)人成長經(jīng)歷寫完了贰镣。這是第四次寫了吧呜象。記得第一次寫,是做咨詢碑隆,寫到動(dòng)情處恭陡,哭的稀里嘩啦。第...
    綻蕊向陽閱讀 1,762評(píng)論 4 1
  • 要明白什么是跨域上煤,先要了解什么是同源策略休玩,它的含義是指: A網(wǎng)頁設(shè)置的 Cookie,B網(wǎng)頁不能打開劫狠,除非這兩個(gè)網(wǎng)...
    書中有涼氣閱讀 799評(píng)論 0 50
  • 一個(gè)人的財(cái)富多少拴疤,個(gè)人的分析能力是重要決定因素之一的。一個(gè)人擁有分析能力独泞,不管起點(diǎn)多低或高呐矾,都有機(jī)會(huì)獲得財(cái)富。 之...
    Amanda_w閱讀 298評(píng)論 0 1
  • 1.你的未來五年的職業(yè)規(guī)劃是什么 我的短期職業(yè)規(guī)劃是找到一份工作懦砂,并努力勝任這份工作蜒犯。長期的職業(yè)規(guī)劃是,希望通過在...
    mengyudezheng閱讀 318評(píng)論 1 3