Android仿網(wǎng)易云音樂歌單詳情頁
效果圖對比:
網(wǎng)易云音樂App原圖:

模仿的效果圖:

基本布局:
FrameLayout
----- MyNestedScrollView // 為了Api23下的滑動兼容
---- LinearLayout // 內(nèi)容部分
----- RelativeLayout
---- ImageView // Toolbar后面的背景圖
---- Toolbar // 標題欄
由于篇幅原因,不能做詳細的介紹,這里就簡單介紹實現(xiàn)這種效果的思路:
實現(xiàn)思路:
1、Activity設置自定義Shared Element切換動畫
2、透明狀態(tài)欄(透明Toolbar,使背景圖上移)
3、Toolbar底部增加和背景一樣的高斯模糊圖,并上移圖片(為了使背景圖的底部作為Toolbar的背景)
4、上下滑動,通過NestedScrollView拿到移動的高度,同時調(diào)整Toolbar的背景圖透明度
1、Activity設置自定義元素共享切換動畫
大家可以發(fā)現(xiàn)頁面跳轉(zhuǎn)時圖片移動的是一個曲線路徑,我們可以定制View的過渡切換效果,這是Material Design中比較常見的用法,Api21以上才有效。需要在開啟頁面時使用:
ActivityOptions.makeSceneTransitionAnimation()其中定義共享的view和transitionName。然后在對應的Activity里創(chuàng)建ArcMotion對象。ArcMotion是PathMotion子類,是個曲線路徑,對應代碼片:
// Activity設置自定義 Shared Element切換動畫if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//定義ArcMotionArcMotion arcMotion = new ArcMotion();arcMotion.setMinimumHorizontalAngle(50f);arcMotion.setMinimumVerticalAngle(50f);//插值器,控制速度Interpolator interpolator = AnimationUtils.loadInterpolator(this, android.R.interpolator.fast_out_slow_in);//實例化自定義的ChangeBoundsCustomChangeBounds changeBounds = new CustomChangeBounds();changeBounds.setPathMotion(arcMotion);changeBounds.setInterpolator(interpolator);changeBounds.addTarget(binding.include.ivOnePhoto);//將切換動畫應用到當前的Activity的進入和返回getWindow().setSharedElementEnterTransition(changeBounds);getWindow().setSharedElementReturnTransition(changeBounds);}// 開啟Intent intent = new Intent(context, MovieDetailActivity.class);intent.putExtra("bean", positionData);ActivityOptionsCompat options =ActivityOptionsCompat.makeSceneTransitionAnimation(context,imageView, CommonUtils.getString(R.string.transition_book_img));//與xml文件對應ActivityCompat.startActivity(context, intent, options.toBundle());
值得注意的是:因為加載圖片要一點時間,切換頁面時就會出現(xiàn)閃爍的情況,而如果取的是緩存就不會有這樣的問題,所以這里有個小技巧,就是起初Glide加載的圖片就指定固定的大小(.override(120,120)),這樣圖片就會被緩存起來,等到跳轉(zhuǎn)時就取緩存。具體還請大家看項目源碼。
2、透明狀態(tài)欄
// 為頭部是View的界面設置狀態(tài)欄透明StatusBarUtil.setTranslucentImageHeader(this, 0, binding.titleToolBar);
其中內(nèi)容根布局不要設置android:fitsSystemWindows="true",這樣會額外添加一個狀態(tài)欄。其中StatusBarUtil,是一個為Android App 設置狀態(tài)欄的工具類。
3、Toolbar的背景圖
仔細分析后發(fā)現(xiàn)網(wǎng)易云音樂的Toolbar的背景其實顯示的是高斯模糊圖的底部,所以這里基本套路是Toolbar是透明的,后面背景圖取的是高斯模糊圖的底部一部分。

調(diào)整Toolbar背景圖位置
// Toolbar的高度int toolbarHeight = binding.titleToolBar.getLayoutParams().height;// Toolbar+狀態(tài)欄的高度final int headerBgHeight = toolbarHeight + StatusBarUtil.getStatusBarHeight(this);// 使背景圖向上移動到圖片的最底端,保留Toolbar+狀態(tài)欄的高度binding.ivTitleHeadBg.setVisibility(View.VISIBLE);ViewGroup.LayoutParams params = binding.ivTitleHeadBg.getLayoutParams();ViewGroup.MarginLayoutParams ivTitleHeadBgParams = (ViewGroup.MarginLayoutParams) binding.ivTitleHeadBg.getLayoutParams();int marginTop = params.height - headerBgHeight;ivTitleHeadBgParams.setMargins(0, -marginTop, 0, 0);binding.ivTitleHeadBg.setImageAlpha(0);
顯示Toolbar背景圖
監(jiān)聽圖片顯示,在顯示之后將其設置為透明色,然后在滑動的時候漸變。這里值得注意的是在設置圖片時不要設置加載中的圖片,不然初始化時達不到透明的效果。
// 高斯模糊背景,加載后將背景設為透明Glide.with(this).load(NeteasePlaylistActivity.IMAGE_URL_MEDIUM)//.placeholder(R.drawable.stackblur_default).error(R.drawable.stackblur_default).bitmapTransform(new BlurTransformation(this, 14, 3))// 設置高斯模糊.listener(new RequestListener<String, GlideDrawable>() {//監(jiān)聽加載狀態(tài)@Overridepublic boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {return false;}@Overridepublic boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {// Toolbar背景設為透明binding.titleToolBar.setBackgroundColor(Color.TRANSPARENT);// 背景圖初始化為全透明binding.ivTitleHeadBg.setImageAlpha(0);binding.ivTitleHeadBg.setVisibility(View.VISIBLE);return false;}}).into(binding.ivTitleHeadBg);
其中引入的庫應為如下,將官方Glide的額外擴展了,使其可以支持高斯模糊。
compile 'jp.wasabeef:glide-transformations:2.0.1'4、上下滑動,漸變背景圖透明度
由于NestedScrollView滾動監(jiān)聽只能在API23以上才能使用,這里為了兼容需要額外處理,定義滾動接口,具體:MyNestedScrollView
/*** 根據(jù)頁面滑動距離改變Header透明度方法*/private void scrollChangeHeader(int scrolledY) {if (scrolledY < 0) {scrolledY = 0;}float alpha = Math.abs(scrolledY) * 1.0f / (slidingDistance);Drawable drawable = binding.ivTitleHeadBg.getDrawable();if (drawable != null) {if (scrolledY <= slidingDistance) {// title部分的漸變drawable.mutate().setAlpha((int) (alpha * 255));binding.ivTitleHeadBg.setImageDrawable(drawable);} else {drawable.mutate().setAlpha(255);binding.ivTitleHeadBg.setImageDrawable(drawable);}}}
這樣基本的效果就實現(xiàn)啦,其中如有需要還可以做些額外的處理,如當背景圖不透明時切換標題等~
實踐了很多實現(xiàn)這個頁面的方法,目前為止這個方案是最好的,效果體驗幾乎是一樣,其中涉及到的知識點有:1、頁面跳轉(zhuǎn)共享元素曲線動畫;2、透明狀態(tài)欄;3、Glide監(jiān)聽圖片加載狀態(tài)和加載固定大小圖片等;4、NestedScrollView在Api23下的滑動兼容。
源碼地址:
https://github.com/youlookwhat/NeteaseMusicUI
到這里就結(jié)束啦。
