iOS小米遙控器的手勢監聽及UI實現,ios小米遙控器ui

來源:互聯網
上載者:User

iOS小米遙控器的手勢監聽及UI實現,ios小米遙控器ui


這篇文章通過執行個體實現了一個類似小米手勢遙控器的功能頁面。

如下所示:






觸摸事件的響應通過對系統的觸摸實踐監聽來進行。

通過一個數組來對點的集合進行緩衝和分析。


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    if (!self.allowsInteraction) return;    UITouch *touch = [touches anyObject];    CGPoint start = [touch locationInView:self.view];        [_gestureManager beginMonitorWithPoint:start];    [self showLightAtPoint:start];        NSLog(@"touch begin");}- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{    if (!self.allowsInteraction) return;        UITouch *touch = [touches anyObject];    CGPoint point = [touch locationInView:self.view];        __weak typeof(&*self) weakSelf = self;    [_gestureManager updateMonitorWithPoint:point action:^{        [weakSelf showLightAtPoint:point];    }];}

在觸摸開始和移動的時候,通過一個類來對手勢相關方法的觸發和管理及其他行為。即成員_gestureManager。


- (void)beginMonitorWithPoint:(CGPoint)point{    [self addPoint:point];}- (void)updateMonitorWithPoint:(CGPoint)point action:(dispatch_block_t)actionBlock{    _curTime++;    int delta = (int)(_curTime - _lastSpawnTime);        if (delta >= TIME_GAP) {        if (actionBlock) {            actionBlock();        }                _lastSpawnTime = _curTime;        [self addPoint:point];    }}

在開始監聽後,我們不需要把系統傳遞的每個點都進行觸發貼圖顯示點的軌跡,所以設定了成員來設定間隙位,已達到對點的密集程度進行控制。

- (void)endMonitor{    _curTime = 0;    _lastSpawnTime = 0;    [self pathAnalysis];    [self.pointPath removeAllObjects];}


在觸摸結束,結束這次監聽的時候,對這些成員進行了重設,分析手勢,並清空了點數組。

下面則開始進行分析手勢,分析的思路比較簡單。

計算起始點和終點之間的差值,對x,y進行分析,判斷方向,再判斷有無突出(是否是返回,功能等手勢)


- (void)pathAnalysis{    int count = self.pointPath.count;    NSLog(@"points count: %d", count);        if (count > JUDGE_CONTAIN) {        goto SendNone;    } else if (count == 1) {        [self sendDelegateResult:MonitorResultTypeChosen];    } else {        CGPoint start = valueToPoint([self.pointPath firstObject]);        CGPoint end   = valueToPoint([self.pointPath lastObject]);        int deltaX = pSub(start, end).x;        int deltaY = pSub(start, end).y;                int midIndex = count/2;        CGPoint mid = valueToPoint(self.pointPath[midIndex]);                if (abs(deltaX) > JUDGE_X && abs(deltaY) < JUDGE_Y) { // horizontal direction                        if (deltaX < 0) {  //right direction                if (![self checkIsAlwaysCorrectDirection:MonitorResultTypeRight start:0 end:self.pointPath.count-1]) goto SendNone;                if (pSub(start, mid).y > JUDGE_Y/2) {                    if ([self checkTrackIsMenu]) [self sendDelegateResult:MonitorResultTypeMenu];                    else goto SendNone;                } else if (abs(pSub(start, mid).y) < JUDGE_Y) {                    [self sendDelegateResult:MonitorResultTypeRight];                } else goto SendNone;            } else {    //left                if (![self checkIsAlwaysCorrectDirection:MonitorResultTypeLeft start:0 end:self.pointPath.count-1]) goto SendNone;                                if (pSub(start, mid).y > JUDGE_Y/2) {                    if ([self checkTrackIsMenu]) {                        [self sendDelegateResult:MonitorResultTypeMenu];                    } else goto SendNone;                } else if (abs(pSub(start, mid).y) < JUDGE_Y) {                    [self sendDelegateResult:MonitorResultTypeLeft];                } else goto SendNone;                            }        } else if (abs(deltaX) < JUDGE_X && abs(deltaY) > JUDGE_Y) { // vertical direction                        if (deltaY < 0) {   // down                if (![self checkIsAlwaysCorrectDirection:MonitorResultTypeDownwards start:0 end:self.pointPath.count-1]) goto SendNone;                if (pSub(start, mid).x > JUDGE_X/2) {                    if ([self checkTrackIsBack]) [self sendDelegateResult:MonitorResultTypeBack];                    else goto SendNone;                } else if (abs(pSub(start, mid).x) < JUDGE_X) {                    [self sendDelegateResult:MonitorResultTypeDownwards];                } else goto SendNone;            } else {            // up                if (![self checkIsAlwaysCorrectDirection:MonitorResultTypeUpwards start:0 end:self.pointPath.count-1]) goto SendNone;                if (abs(pSub(start, mid).x) < JUDGE_X) [self sendDelegateResult:MonitorResultTypeUpwards];                else goto SendNone;            }        } else goto SendNone;    }    return;    SendNone:    [self sendDelegateResult:MonitorResultTypeNone];    return;}

還有一些需要用到的函數

UIKIT_STATIC_INLINE UIImageView * quickImageView(NSString * imgName) {    UIImageView *iv = [[UIImageView alloc] initWithImage:ImageCache(imgName)];    return iv;}UIKIT_STATIC_INLINE CGPoint pSub(CGPoint a, CGPoint b) {    return CGPointMake(a.x - b.x, a.y - b.y);}UIKIT_STATIC_INLINE NSValue * pointToValue(CGPoint a) {    return [NSValue valueWithCGPoint:a];}UIKIT_STATIC_INLINE CGPoint valueToPoint(NSValue *v) {    return [v CGPointValue];}

因為這些函數調用頻率都比較高,所以就聲明為內聯靜態了。


那些檢驗是否一個方向,或者是否突出的方法則如下所示:

- (BOOL)checkIsAlwaysCorrectDirection:(MonitorResultType)direct start:(int)start end:(int)end{    PathLogicBlock block;    switch (direct) {        case MonitorResultTypeRight:        {            block = ^(CGPoint v) {                BOOL ret = (v.x >= 0)? NO: YES;                return ret;            };        }            break;        case MonitorResultTypeLeft:        {            block = ^(CGPoint v) {                BOOL ret = (v.x <= 0)? NO: YES;                return ret;            };        }            break;        case MonitorResultTypeUpwards:        {            block = ^(CGPoint v) {                BOOL ret = (v.y <= 0)? NO: YES;                return ret;            };        }            break;        case MonitorResultTypeDownwards:        {            block = ^(CGPoint v) {                BOOL ret = (v.y >= 0)? NO: YES;                return ret;            };        }            break;        default: {return NO;}            break;    }        for (int i = start; i+POINT_GAP < end; i += POINT_GAP) {                CGPoint s = valueToPoint(self.pointPath[i]);        CGPoint e = valueToPoint(self.pointPath[i+POINT_GAP]);                CGPoint d = pSub(s, e);                if (!block(d)) {return NO;}    }        return YES;}

這裡通過block設定條件,然後在遍曆中進行檢查及返回BOOL值。


其他也多用遍曆進行判斷,大部分分析都在一次遍曆以內。例如檢查是不是快顯功能表手勢或者返回手勢。

- (BOOL)checkTrackIsMenu{    int start = 0;    int end = self.pointPath.count-1;    BOOL flag = NO;            while (valueToPoint(self.pointPath[start]).y >= valueToPoint(self.pointPath[start+1]).y) {start++;}    while (valueToPoint(self.pointPath[end]).y >= valueToPoint(self.pointPath[end-1]).y) {end--;}        if (abs(start-end) < 2*POINT_GAP) { flag = YES; }        return flag;}- (BOOL)checkTrackIsBack{    int start = 0;    int end = self.pointPath.count-1;    BOOL flag = NO;        while (valueToPoint(self.pointPath[start]).x >= valueToPoint(self.pointPath[start+1]).x) {start++;}    while (valueToPoint(self.pointPath[end]).x >= valueToPoint(self.pointPath[end-1]).x) {end--;}        if (abs(start-end) < 2*POINT_GAP) { flag = YES; }        return flag;}


在圖片顯示方面,我對要用到的圖片在Controller載入之後進行了預先載入。

- (void)loadGestureManager{    _gestureManager = [MIGestureManager sharedManager];    _gestureManager.delegate = self;    [_gestureManager preloadResources];}//gesture manager method- (void)preloadResources{    for (int i = 0; i < INITIAL_COUNT; i++) {        UIImageView *iv = quickImageView(PointImage);        [self.imageSet addObject:iv];    }        _upImageView     = quickImageView(UpwardsImage);    _downImageView   = quickImageView(DownwardsImage);    _leftImageView   = quickImageView(LeftImage);    _rightImageView  = quickImageView(RightImage);    _homeImageView   = quickImageView(HomeImage);    _backImageView   = quickImageView(BackImage);    _menuImageView   = quickImageView(MenuImage);    _chosenImageView = quickImageView(chosenImages[0]);        NSMutableArray *aniArr = [NSMutableArray array];    for (int i = 0; i < 4; i++) {        UIImage *image = ImageCache(chosenImages[i]);        [aniArr addObject:image];    }    _chosenImageView.animationImages = aniArr;    _chosenImageView.animationDuration = 0.7;    _chosenImageView.animationRepeatCount = 1;}

視圖層次問題:


我們看小米遙控器的效果是都在一個網格下面,這裡就是在顯示點軌跡的視圖上覆蓋了一層網格視圖,以達到那樣的效果。


原始碼地址:Rannie/MIRemoteControl


當然,這個項目裡也有很多要解決的問題,在項目Readme.md中也有提到:


1.點的集合通過系統內建的NSMutableArray來維護,由於不能存結構體,導致需要不停的封包拆包動作如下:

static inline NSValue * pointToValue(CGPoint a) {
return [NSValue valueWithCGPoint:a];
}

static inline CGPoint valueToPoint(NSValue *v) {
return [v CGPointValue];
}
可以通過自己實現資料結構來維護點循序集合。


2.貼圖使用的是UIImageView,可以通過輕量級一些的layer設定content來實現。


3.這裡監聽的是控制器中的touch事件,也可以通過子類化UIGestureRecognizer來監聽UITouch,需要匯入一個UIGestureRecognizer子類化的一個標頭檔即可監聽touch事件。具體可以看Using UIGestureRecognizer with Swift Tutorial


4.點的路徑分析比較簡單,如果對統計有研究會有更出色的分析公式。



以上就是本篇部落格全部內容,歡迎指正和評論。


小米手機遙控器怎使用

1、下載並安裝小米遙控器進入介面,是一個模仿傳統遙控器的介面,可以上下左右,可以確定,下面三個是安卓系統的按鍵,基本和小米盒子內建的遙控器一樣。
小米遙控器
2、向右拉,彈出不同的操作介面選擇,包括按鍵、手勢、手柄和體感,上方還有搜尋,體感筆者測試良久由於家裡路由器不怎麼好,所以總是卡頓,希望會玩的朋友指導指導,這裡就不介紹了。
3、先看設定,可以選取震動反饋、體感控制、反向投屏和遙控器鍵盤。如果不喜歡每次點擊手機都震動,關了震動反饋就行,其他的建議開啟。
4、遊戲手柄的的介面,配合玩遊戲很帶勁,特別是對一些老遊戲機的模擬器。
5、手勢操作筆者感覺最好用的一個,因為只要在螢幕上畫畫手勢就可以操作手機,相比傳統方式不用看手機的虛擬鍵位。
6、手指向四個方向滑動分別對應不同的方向鍵。
7、搖動手機是回到主介面,橫著畫折線是返回鍵,豎著畫折線是菜單鍵,手指單機是確認。
8、可以把搜尋到的視頻直接傳到小米盒子播放,但是最好家裡的路由器能好些,否則有卡頓的危險,如果手機不能連線路由器了,請在手機刪除網路後重新輸入密碼串連即可。
以上就是小編為大家介紹的用手機來控制小米盒子的方法,這裡主要是大家要下載並安裝小米遙控器這款應用,不管是什麼品牌的手機都可以下載安裝後,進行對小米盒子的控制,怎麼樣,學會了吧。
 
小米2s是否有防竊聽功可以?

嗨!
可以用第三方軟體進行支援
更詳細的描述問題有助於網友理解你遇到的麻煩,協助你更準確的解決問題。謝謝你支援小米手機!
小米企業平台[官方認證]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.