(原)IOS之Metro實現,擁有windows磁帖效果(一),iosmetro

來源:互聯網
上載者:User

(原)IOS之Metro實現,擁有windows磁帖效果(一),iosmetro

IOS之Metro實現,擁有windows磁帖效果(一) 

無廢話-上渣圖

  所有轉出“部落格園”的朋友請您註明出處:http://www.cnblogs.com/xiaobajiu/p/4084717.html

  扁平化來襲,微軟的metro風格看起來很有科技感。於是想寫個IOS的metro控制項。搞了一段時間,有了模樣。我的想法是metro和wp8的差不多,展示資訊通過旋轉來展示,觸摸metro它會撬動或者吸彈。點擊metro會執行事件,長按磁帖又可以執行其他事件。

  結構:metro最外層是骨架層,該層的作用是站住位置,內部的大小變化和metro的拖拽都不會影響到外部的結構。骨架外是蒙板層和內容層。蒙板層在下方作用是metro主題色,內容層存放要展示的兩面視圖。值得注意的是蒙板層在不設定主題的情況下是隱藏的。

metro結構-大圖

  那麼直接進入朋友最關心的部位,動畫。IOS的動畫是廉價的,不像Windows,其他平台都像拿筆在畫,IOS就像印表機在刷圖。IOS上主要的繪圖相關的有Quartz2D,核心動畫等應付簡單的旋轉和伸縮的畫使用UIViewAnimation就足夠了,而且代碼簡短。旋轉的效果竟然只要一行: view.layer.transform= CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z) 這樣子就可以實現旋轉效果。下面是一段完整的磁帖旋轉代碼的截取:

/** *  (private)metro的旋轉動畫 */- (void)revolveMetro{    _isViewDleaying= NO;    [UIView animateWithDuration:_turnTimes[_currentViewID] delay:0.0 options:UIViewAnimationOptionCurveEaseIn|UIViewAnimationOptionAllowUserInteraction animations:^{        _isAnimating= YES;//修改動畫狀態        _container.layer.transform= CATransform3DMakeRotation(M_PI_2, 1.0, 0.0, 0.0);        if(!_maskingView.hidden)            _maskingView.layer.transform= CATransform3DMakeRotation(M_PI_2, 1.0, 0.0, 0.0);    } completion:^(BOOL finished) {        ((UIView*)self.views[_currentViewID]).hidden= YES;        ((UIView*)self.views[[self nextIndexNowNextView]]).hidden= NO;        [UIView animateWithDuration:_turnTimes[_currentViewID] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{            _container.layer.transform= CATransform3DMakeRotation(- M_PI_4/2, 1.0, 0.0, 0.0);            if(!_maskingView.hidden)                _maskingView.layer.transform= CATransform3DMakeRotation(- M_PI_4/2, 1.0, 0.0, 0.0);        } completion:^(BOOL finished) {            [UIView animateWithDuration:_turnTimes[_currentViewID] delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{                _container.layer.transform= CATransform3DMakeRotation(0, 1.0, 0.0, 0.0);                if(!_maskingView.hidden)                    _maskingView.layer.transform= CATransform3DMakeRotation(0, 1.0, 0.0, 0.0);            } completion:^(BOOL finished) {                _isAnimating= NO;//修改動畫狀態            }];        }];    }];}

   一共組合了三次動畫,每個動畫都可以通過options選項設定很多有用的屬性。比如動畫時間曲線,簡單說就是動畫隨漸漸的快慢,它畫到座標軸上就是各種曲線。在磁帖的旋轉中有切換圖片的這種情況,有很多方法可以做比如我沒有用的一個方法: [view exchangeSubviewAtIndex:0 withSubviewAtIndex:1]; 這個方法可以直接交換父圖層中子級索引0和1的兩個子圖層的位置。從而達到切換圖層的目的。我使用的是隱藏圖層的方法,目的是不想打亂圖層順序,方便找到某圖層。

  除了metro的旋轉還有一個動畫效果就是metro被觸摸的時候的傾斜效果。通過觀察wp8,觸摸點離中心點越遠下沉力度越大。但是靠近中心地區又是下沉效果而不是傾斜效果。通過觀察還能發現到這個動畫效果的觸發應該是在觸摸到metro的時候觸發。那麼這個動畫效果可以在 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 這個函數中執行。

  那麼還剩一個繁瑣的問題就是傾斜的計算的問題。諾以幾何中心為對稱軸來進行旋轉,只加以控制旋轉的角度即可實現在metro一條通過幾何中心的直線上觸摸時根據到幾何中心的距離來計算應該旋轉多少角度。而旋轉所繞對稱軸就是上一句所說的通過幾何中心的直線(觸摸點和幾何中心的連線)旋轉90度所得直線。

  可以建立一個結構結構體來代表這種向量:

/** *  帶權值的向量 */struct MetroVector{    CGFloat x;    CGFloat y;    CGFloat power;//權值標明metro下沉力度<-[0.0,1.0]};typedef struct MetroVector MetroVector;

  下一步是當觸摸metro時獲得觸摸點a。由a和中心o計算出一條向量V1,V1旋轉90度既是傾斜所需的對稱軸V2。直接將V2的x,y填入旋轉函數中即可。值得注意的是 view.layer.transform= CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)這個函數的x,y,z值的取值區間是[0.0,1.0]。關於力度我採用的是線段ao的長度,對比的是o到metro任意角的距離即對角線的半長。兩隻相除得到一個0~1的數即可衡量力度。

  計算向量V2的代碼:

/** *  (private)計算metro點擊時 3D傾斜的對稱軸的向量 * *  @param view       觸摸的視圖 *  @param touchPoint 其中的觸摸點 */- (MetroVector)getVectorByTouchedView:(UIView*)view in:(CGPoint)touchPoint{    MetroVector vector;    CGFloat width= view.frame.size.width;    CGFloat height= view.frame.size.height;    CGFloat diagonal= sqrt(width* width+ height* height);//對角線    vector.x= touchPoint.x- width/2;//以幾何中心為原點的向量    vector.y= touchPoint.y- height/2;    CGFloat lenTouchBetweenCenter= sqrt(vector.x*vector.x+ vector.y* vector.y);//觸摸點到幾何中心的距離    CGFloat max= MAX(vector.x, vector.y);//取最大值,做除數,使得兩者最大值為1.0    CGFloat temp= vector.x;//交換x,y值,其中之一取反(表示將向量轉動90度,成為圖層的轉軸)    vector.x= - vector.y/max;    vector.y=  temp/max;    CGFloat len4maxPower= diagonal/2;//取對角線二分之一作為力度最大的衡量    vector.power= lenTouchBetweenCenter/ len4maxPower;    return vector;}

有了V2那麼傾斜就可以直接上代碼了

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    [super touchesBegan:touches withEvent:event];    if(self.isAnimating) return;//允許摸,不允許再次動畫    CGPoint touchPos= [(UITouch*)[touches anyObject] locationInView:self];    //中心地區    CGSize viewSize= self.frame.size;    CGRect centerRect= CGRectMake(viewSize.width/4, viewSize.height/4, viewSize.width/2, viewSize.height/2);    if(CGRectContainsPoint(centerRect, touchPos)){//是否在中心地區,是則下沉動畫        [UIView animateWithDuration:macroTouchOneAnimationInterval/5 delay:0.0 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionAllowUserInteraction animations:^{            _isAnimating= YES;            self.layer.transform= CATransform3DMakeScale(0.975, 0.975, 1.0);        } completion:^(BOOL finished) {            [UIView animateWithDuration:macroTouchOneAnimationInterval/2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{                self.layer.transform= CATransform3DMakeScale(1.0, 1.0, 1.0);            } completion:^(BOOL finished) {                _isAnimating= NO;                //..            }];        }];    }else{//偏斜動畫        MetroVector vecor=  [self getVectorByTouchedView:self in:touchPos];        [UIView animateWithDuration:macroTouchOneAnimationInterval delay:0.0 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionAllowUserInteraction animations:^{            _isAnimating= YES;            self.layer.transform= CATransform3DMakeRotation(randianFromAngle(30* vecor.power),vecor.x, vecor.y, 0.0);//        } completion:^(BOOL finished) {            [UIView animateWithDuration:macroTouchOneAnimationInterval/2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{                self.layer.transform= CATransform3DMakeRotation(0 ,vecor.x, vecor.y, 0.0);            } completion:^(BOOL finished) {                _isAnimating= NO;                //..            }];        }];    }}

  到目前為最為核心的動畫內容已經實現。還剩下觸摸事件的處理,和一堆所謂的商務邏輯和一些功能上的實現。我想在下一篇部落格另外介紹。並賦上代碼下載,吐槽那種複製框著滾而導致一百度一百坨雷同內容的行為。

  如有錯誤請朋友指正,以免誤人子弟。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.