一直以來,無論是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,第四步
- 將需要動的元件的屬性loadStyle,設定為需要的型別,不需要動的元件不用做額外的操作;
- (可選)新增屬性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 樣式提取出來,這樣就實現了骨架屏。
前端的骨架屏實現和優化,建議讀者閱讀以下連結文章: