博客園第三方客戶端-i博客園正式發佈App Store

来源:http://www.cnblogs.com/polobymulberry/archive/2016/02/18/5189378.html
-Advertisement-
Play Games

博客園第三方客戶端-i博客園正式發佈App Store 1. 前言 算來從15年8月到現在自學iOS已經快7個月了,雖然中間也是斷斷續續的,不過竟然堅持下來了。年後要找實習啦,於是萌生了一個想法 —— 寫一個app練練手。這次我沒弄後臺了,直接使用了博客園的open api(嘿嘿)。之前也做過一個a


博客園第三方客戶端-i博客園正式發佈App Store

1. 前言


算來從15年8月到現在自學iOS已經快7個月了,雖然中間也是斷斷續續的,不過竟然堅持下來了。年後要找實習啦,於是萌生了一個想法 —— 寫一個app練練手。這次我沒弄後臺了,直接使用了博客園的open api(嘿嘿)。之前也做過一個app,叫做魔界-魔術,前後端都是我弄的,不過後端使用的是Bmob後端雲(一個Baas服務),但是作為第一個app,代碼上感覺很混亂,而且基本上都是用的第三方控制項。這次的i博客園是我完全獨立開發的(包括UI設計),整體使用的是MVC模式,並且儘量不去使用別人第三方控制項(雖然還是用了。後面會提到具體使用)。

先放出幾張app的gif預覽圖片:

1 2 3

Appstore地址:

大家可以在AppStore搜索i博客園。或者掃描下麵二維碼:

2016-02-18-1009004908

 

2. 使用的資料和工具


  • 博客園官方open web api網址:
  1. http://wcf.open.cnblogs.com/news/help (新聞)
  2. http://wcf.open.cnblogs.com/blog/help (博客)
  • 使用到的第三方控制項
    • AFNetworking
    • SDWebImage
    • HMSegmentedControl(Segmented Control)
    • RESideMenu (側滑控制器視圖)
    • MJRefresh
    • Masonry (AutoLayout)
    • UITableView+FDTemplateLayoutCell (動態計算UITableViewCell的高度)
    • XMLDictionary (解析XML文件,因為博客園web api傳回來的是xml數據)
  • UI資源和工具

3. 解決的問題


問題一:實現引導頁(不是啟動頁)上的RippleButton(有水波漣漪動畫的按鈕,第一張gif圖片上的那個粉紅色按鈕)

解決思路:

1. 使用UIBesierPath構建一個圓形的path

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:pathFrame cornerRadius:self.layer.cornerRadius];

2. 將上面的path賦值給circleShape(CAShapeLayer對象)的path屬性,同時添加該circleShape到RippleButton(UIView類型)上

CAShapeLayer *circleShape = [CAShapeLayer layer];
circleShape.path = path.CGPath;
[self.layer addSublayer:circleShape];

3. 這時,就可以使用Core Animation來操作RippleButton的layer了,細節我就不詳細說了,無非是通過動畫控制圓圈的scale和alpha

CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
scaleAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(2.5, 2.5, 1)];

CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
alphaAnimation.fromValue = @1;
alphaAnimation.toValue = @0;

CAAnimationGroup *animation = [CAAnimationGroup animation];
animation.animations = @[scaleAnimation, alphaAnimation];
animation.duration = 1.0f;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[circleShape addAnimation:animation forKey:nil];

4. 但是如果僅僅添加一個circleShape,那麼不會有多個水波散開的效果。於是我又將上述123步代碼封裝成createRippleEffect函數,並添加到定時器中

- (void)setupRippleTimer
{
    __weak __typeof__(self) weakSelf = self;
    NSTimeInterval repeatInterval = self.repeatInterval;
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, repeatInterval * NSEC_PER_SEC, 0);
    
    __block NSInteger count = 0;
    dispatch_source_set_event_handler(self.timer, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            count ++;
            // 水波紋重覆次數,預設-1,表示永久
            if (self.repeatCount != -1 && count > weakSelf.repeatCount) {
                [weakSelf stopRippleEffect];
                return;
            }
            [weakSelf createRippleEffect];
        });
    });
}

問題二:48小時閱讀和十日推薦中使用了UICollectionView,自定義了UICollectionViewLayout,實現輪盤旋轉的效果(部分代碼參考了AWCollectionViewDialLayout

解決思路:

1. 首先得知道自定義UICollectionViewLayout的具體流程

實現自定義的UICollectionViewLayout的具體流程請參考這篇文章,很詳細!

2. 整個自定義UICollectionViewLayout實現過程中,最核心的要數layoutAttributesForElementsInRect這個函數了

2.1 首先根據rect的y值來計算出哪幾個cell在當前rect中:

// 在rect這個區域內有幾個cell,返回每個cell的屬性
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSMutableArray *layoutAttributes = [NSMutableArray array];
    
    CGFloat minY = CGRectGetMinY(rect);
    CGFloat maxY = CGRectGetMaxY(rect);
    // 獲取到rect這個區域的cells的firstIndex和lastIndex,這兩個沒啥用,主要是為了獲取activeIndex
    NSInteger firstIndex = floorf(minY / self.itemHeight);
    NSInteger lastIndex = floorf(maxY / self.itemHeight);
    NSInteger activeIndex = (firstIndex + lastIndex) / 2; // 中間那個cell設為active
    // maxVisiableOnScreeen表示當前屏幕最多有多少cell
    // angularSpacing表示每隔多少度算一個cell,因為這裡是輪盤,每個cell其實看做一個扇形
    NSInteger maxVisiableOnScreeen = 180 / self.angularSpacing + 2;
    
    // firstItem和lastItem就表示哪幾個cell處於當前rect
    NSInteger firstItem = fmax(0, activeIndex - (NSInteger)maxVisiableOnScreeen/2);
    NSInteger lastItem = fmin(self.cellCount, activeIndex + (NSInteger)maxVisiableOnScreeen/2);
    if (lastItem == self.cellCount) {
        firstItem = fmax(0, self.cellCount - (NSInteger)maxVisiableOnScreeen);
    }
    // 計算rect中每個cell的UICollectionViewLayoutAttributes
    for (NSInteger i = firstItem; i < lastItem; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *attributes= [self layoutAttributesForItemAtIndexPath:indexPath];
        [layoutAttributes addObject:attributes];
    }
    
    return layoutAttributes;
}

2.2 計算每個cell的UICollectionViewLayoutAttributes

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    // 預設offset為0
    CGFloat newIndex = (indexPath.item + self.offset);
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    attributes.size = self.cellSize;
    
    CGFloat scaleFactor, deltaX;
    CGAffineTransform translationT;
    CGAffineTransform rotationT;
    
    switch (self.wheetAlignmentType) {
        case WheetAlignmentTypeLeft:
            scaleFactor = fmax(0.6, 1 - fabs(newIndex * 0.25));
            deltaX = self.cellSize.width / 2;
            attributes.center = CGPointMake(-self.radius + self.xOffset, self.collectionView.height/2+self.collectionView.contentOffset.y);
            rotationT = CGAffineTransformMakeRotation(self.angularSpacing * newIndex * M_PI / 180);
            translationT = CGAffineTransformMakeTranslation(self.radius + deltaX * scaleFactor, 0);
            break;
        case WheetAlignmentTypeRight:
            scaleFactor = fmax(0.6, 1 - fabs(newIndex * 0.25));
            deltaX = self.cellSize.width / 2;
            attributes.center = CGPointMake(self.radius - self.xOffset  + ICDeviceWidth, self.collectionView.height/2+self.collectionView.contentOffset.y);
            rotationT = CGAffineTransformMakeRotation(-self.angularSpacing * newIndex * M_PI / 180);
            translationT = CGAffineTransformMakeTranslation(- self.radius - deltaX * scaleFactor, 0);
            break;
        case WheetAlignmentTypeCenter:
            // 待實現
            break;
        default:
            break;
    }
    
    CGAffineTransform scaleT = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
    attributes.alpha = scaleFactor; // alpha和scaleFactor一致
    // 先scale縮小,在translation到對應位置(因為是扇形,每個cell的x值和對應位置有關),最後rotation(形成弧形)
    attributes.transform = CGAffineTransformConcat(scaleT, CGAffineTransformConcat(translationT, rotationT));
    attributes.zIndex = indexPath.item;
    
    return attributes;
}

問題三:實現帶動畫的TabBarItem

解決思路:

不詳細說了,我將代碼提交到了Github - animated-tab-bar-Objective-CPJXAnimatedTabBarController is a Objective-C version of RAMAnimatedTabBarController(https://github.com/Ramotion/animated-tab-bar))。

主要就是自定義UITabBarItem,以及自定義UITabBarItem的AutoLayout構建。代碼封裝的很好,尤其動畫實現部分,結構很清晰,符合OOP思想。

問題四:博客園使用的xml形式的open web api。解析困難。

解決思路:

這裡我還是使用MVC思路,使用AFNetworking獲取到XML數據,再使用XMLDictionary來解析XML數據(本質是NSXMLParserDelegate),並將其轉化為Model(需要自己實現)。

關於NSXMLParserDelegate可以參考這篇文章 - iOS開發之解析XML文件

問題五:設計部分,不是很擅長,每個頁面的佈局都需要想很久,儘量做得簡潔,有科技風。

解決思路:

基本上就是多看別人app設計,模仿,或者自己想啊想。也是第一次用Sketch,話說還挺好用的。

4. 存在問題和TODO


  • 分享到微信微博等等,準備使用友盟。
  • 涉及到UIWebView界面的排版,很醜。不是很懂CSS、JS、HTML5。之前為了一個圖片適配搞了半天,其實只要在<head>中加上"img{max-width:100%%;height:auto;}"就行。懇請大家指點一下我。
  • 使用自定義TabBarItem後,隱藏TabBar很麻煩。
  • 離線閱讀
  • ……

5. 後記


自己親手去寫代碼確實感覺上是不一樣,很多細節問題,雖然不難,但是很有挑戰性。代碼目前很挫,後面修改規範點,準備放到Github上。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 是CApropertyAnimation的子類,跟CABasicAnimation的區別是:CABasicAnimation只能從一個數值(fromValue)變到另一個數值(toValue),而CAKeyframeAnimation會使用一個NSArray保存這些數值,就可以實現CALayer的某
  • 什麼是JRebel for Android? 一款Android studio插件——允許你修改正在運行中的應用程式,而且不必重新部署或重啟。支持所有運行Android 4.0及以上版本的手機和平板。由ZeroTurnaround開發。這是一款收費插件,每年49美元,免費試用21天。 通常在開發過程
  • Ios中的定位功能是通過 Core Location框架實現的。它和地圖開發框架是相互獨立的。在Core Location中主要實現了定位和地理編碼的功能! 下麵我們就來介紹一下它的屬性,方法和代理方法! 屬性: desiredAccuracy:定位精度,是一個枚舉類型 //kCLLocationA
  • package com.example.yanlei.picture; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.Menu; import androi
  • ZXing的二維碼功能的提取lib下載地址:https://github.com/xuyisheng/ZXingLib 1.掃描二維碼: 我們掃描就是要用到這個CaptureActivity類,直接把上面下載地址裡面下載了裡面的libzxing作為Module,如下圖: 首先加上許可權: <!-- 相
  • 抖動效果在開發中比較少用到,不過有時使用了確有個很好的裝逼效果,用的時候就例如一些用戶錯誤操作之類的 效果如下,不過gif看到的效果沒實際的好看 上代碼 1 - (void)shakeAnimationForView:(UIView *) view 2 3 { 4 // 獲取到當前的View 5 6
  • 第十一章 Android的線程和線程池 從用途上來說,線程分為子線程和主線程,主線程主要處理和界面相關的事情,而子線程往往用於執行耗時的操作。AsyncTask,IntentService,HandlerThread都可以扮演線程的角色。 AsyncTask封裝了線程池和Handler,主要是為了方
  • 分類:C#、Android、VS2015; 創建日期:2016-02-18 1、主界面運行截圖 2、MainActivity.cs文件中對應的代碼 chItems.Add(new Chapter() { ChapterName = "第10章 擴展組件庫和其他視圖", ChapterItems = ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...