客戶端骨架屏實現

xiangzhihong發表於2019-01-04

一直以來,無論是Web還是iOS、Android的應用中,為了提升應用的載入等待這段時間的使用者感知體驗,各種技術層出不窮。其中,尤以菊花圖以及由它衍生各種載入動畫最為突出。

對於菊花圖我們自不必多說,現在對於載入的設計體驗有了比菊花載入體驗更棒的方法,即大家常看到的Skeleton Screen Loading,中文叫做骨架屏。

所謂Skeleton Screen Loading,即表示在頁面完全渲染完成之前,使用者會看到一個佔位的樣式,用以描繪了當前頁面的大致框架,載入完成後,最終骨架屏中各個佔位部分將被真實的資料替換。很多專案中都有相關的應用,如餓了麼h5版本、知乎、facebook等網站中都有應用。 其效果如下圖所示:

在這裡插入圖片描述

iOS

iOS實現Skeleton效果的第三方庫有很多,當然也可以自己建立一個,而骨架屏最核心的就是佔位和屬性動畫。在實現方面,本文介紹幾種主流的實現方式:

SkeletonView

實現原理

對UIView進行擴充套件,增加skeletonable、skeletonLayer等屬性。呼叫showSkeleton方法,對屬性skeletonable為true的檢視進行遍歷,找到其最上層的、skeletonable為true的子View,然後建立skeletonLayer新增到上面,構成骨架圖,動效效果亦是在skeletonLayer層。需要隱藏效果時,呼叫hideSkeleton,同樣進行遍歷,移除skeletonLayer。

簡單的說,在顯示佔位的時候,將tableView的代理設定為通過某個物件,這個物件根據cell的Idenfier建立cell並新增佔位顯示。關閉顯示佔位的時候,將代理tableView的代理切回ViewController,正常顯示。

特點

  • 不需手動寫佔位控制元件,不需處理圓角等問題,佔位效果與實際控制元件佈局一致。
  • 缺點是有的控制元件是自適應大小,在未獲得資料之前,控制元件位置是錯誤的,導致佔位效果有問題。

Somo

同樣是擴充套件UIView,新增屬性somoContainer,表示佔位檢視的容器檢視,其中每個佔位區域都是一個SomoView。對於想要顯示佔位效果的View,需實現協議,在協議方法中返回SomoView列表。將這些SomoView新增到somoContainer,並顯示。

特點

  • 避免了上述自適應控制元件無資料時大小不正確的問題。
  • 需要手工指定每個佔位區域,且每個佔位區域是UIView級別,不是CALayer。

TABAnimated

除此之外,TABAnimated也是一個被使用的比較多的,同樣TABAnimated也是擴充套件的UIView。在ios中整合TABAnimated需要經歷以下幾步:

1,Install

pod search TABAnimated
複製程式碼

2,第二步(可選)

可以選擇在appDelegate的didFinishLaunchingWithOptions方法全域性設定動畫屬性,設有預設屬性。例如:

// 設定TABAnimated相關屬性
[[TABViewAnimated sharedAnimated]initWithAnimatedDuration:0.3 withColor:tab_kBackColor];
複製程式碼

3,第三步,設定animatedStyle屬性

在需要動畫的view上,將屬性animatedStyle設定為TABTableViewAnimationStart,不需要動畫的view不用做額外的操作。

// UIView和UICollectionView列舉
typedef NS_ENUM(NSInteger,TABViewAnimationStyle) {
    TABViewAnimationDefault = 0,               // 預設,沒有動畫
    TABViewAnimationStart,                     // 開始動畫
    TABViewAnimationRuning,                    // 動畫中
    TABViewAnimationEnd,                       // 結束動畫
    TABCollectionViewAnimationStart,           // CollectionView 開始動畫
    TABCollectionViewAnimationRunning,         // CollectionView 動畫中
    TABCollectionViewAnimationEnd              // CollectionView 結束動畫
};

// UITableView列舉
typedef NS_ENUM(NSInteger,TABViewAnimationStyle) {
    TABViewAnimationDefault = 0,    // 沒有動畫,預設
    TABViewAnimationStart,          // 開始動畫
    TABViewAnimationEnd             // 結束動畫
};
複製程式碼
// UITableView例子
- (UITableView *)mainTV {
    if (!_mainTV) {
        _mainTV = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
        _mainTV.animatedStyle = TABTableViewAnimationStart;  // 開啟動畫
        _mainTV.delegate = self;
        _mainTV.dataSource = self;
        _mainTV.rowHeight = 100;
        _mainTV.backgroundColor = [UIColor whiteColor];
        _mainTV.estimatedRowHeight = 0;
        _mainTV.estimatedSectionFooterHeight = 0;
        _mainTV.estimatedSectionHeaderHeight = 0;
        _mainTV.separatorStyle = UITableViewCellSeparatorStyleNone;
    }
    return _mainTV;
}

// UIView例子
- (TestHeadView *)headView {
    if (!_headView) {
        _headView = [[TestHeadView alloc]initWithFrame:CGRectMake(0, 0, tab_kScreenWidth, 90)];
        _headView.animatedStyle = TABViewAnimationStart;  //開啟動畫
    }
    return _headView;
}
複製程式碼

4,第四步

  1. 將需要動的元件的屬性loadStyle,設定為需要的型別,不需要動的元件不用做額外的操作;
  2. (可選)新增屬性tabViewWidth,其為動畫開啟時該元件的寬度,有較為合理預設值;
typedef enum {
    TABViewLoadAnimationDefault = 0, //預設沒有動畫
    TABViewLoadAnimationShort,       //動畫先變短再變長
    TABViewLoadAnimationLong         //動畫先變長再變短
}TABViewLoadAnimationStyle;          //view動畫型別列舉
複製程式碼
{
        UILabel *lab = [[UILabel alloc]init];
        [lab setFont:tab_kFont(15)];
        lab.loadStyle = TABViewLoadAnimationLong;
        lab.tabViewWidth = 100;
        [lab setTextColor:[UIColor blackColor]];
        [lab setText:@""];
        
        titleLab = lab;
        [self.contentView addSubview:lab];
 }
複製程式碼

5,第五步

在獲取到資料後,停止動畫。

//停止動畫,並重新整理資料
_mainTV.animatedStyle = TABTableViewAnimationEnd;
[_mainTV reloadData];
    
_headView.animatedStyle = TABViewAnimationEnd;
[_headView initWithData:headGame];
複製程式碼

示例原始碼連結:iOS骨架屏示例

Android

在Android中,骨架屏的實現也後很多的第三方框架,常見的有以下幾個庫:

ShimmerRecyclerView

ShimmerRecyclerView是一個帶有閃光和指示效果的庫,其執行效果如下圖:

在這裡插入圖片描述

在這裡插入圖片描述

原始碼地址:github.com/sharish/Shi…

Skeleton

Skeleton也是一個使用得比較廣泛的庫,它現在使用快閃記憶體動畫的記憶體優化版本,因此速度更快,您也可以設定更大的佈局動畫。

在這裡插入圖片描述

在這裡插入圖片描述

專案原始碼:github.com/ethanhua/Sk…

spruce-android

Spruce 是一個輕量級動畫庫,可幫助編排螢幕上的動畫,該庫同時還支援 iOS。

在這裡插入圖片描述

原始碼地址:github.com/willowtreea…

前端

在前端中,通過 puppeteer 在服務端操控 headless Chrome 開啟開發中的需要生成骨架屏的頁面,在等待頁面載入渲染完成之後,在保留頁面佈局樣式的前提下,通過對頁面中元素進行刪減或增添,對已有元素通過層疊樣式進行覆蓋,這樣達到在不改變頁面佈局下,隱藏圖片和文字,通過樣式覆蓋,使得其展示為灰色塊。然後將修改後的 HTML 和 CSS 樣式提取出來,這樣就實現了骨架屏。

前端的骨架屏實現和優化,建議讀者閱讀以下連結文章:

eleme骨架屏外掛實現原理

page-skeleton-webpack-plugin

相關文章