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

模仿的效果圖:

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

調(diào)整Toolbar背景圖位置
// Toolbar的高度int toolbarHeight = binding.titleToolBar.getLayoutParams().height;// Toolbar+狀態(tài)欄的高度final int headerBgHeight = toolbarHeight + StatusBarUtil.getStatusBarHeight(this);// 使背景圖向上移動(dòng)到圖片的最底端,保留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)聽圖片顯示,在顯示之后將其設(shè)置為透明色,然后在滑動(dòng)的時(shí)候漸變。這里值得注意的是在設(shè)置圖片時(shí)不要設(shè)置加載中的圖片,不然初始化時(shí)達(dá)不到透明的效果。
// 高斯模糊背景,加載后將背景設(shè)為透明Glide.with(this).load(NeteasePlaylistActivity.IMAGE_URL_MEDIUM)//.placeholder(R.drawable.stackblur_default).error(R.drawable.stackblur_default).bitmapTransform(new BlurTransformation(this, 14, 3))// 設(shè)置高斯模糊.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背景設(shè)為透明binding.titleToolBar.setBackgroundColor(Color.TRANSPARENT);// 背景圖初始化為全透明binding.ivTitleHeadBg.setImageAlpha(0);binding.ivTitleHeadBg.setVisibility(View.VISIBLE);return false;}}).into(binding.ivTitleHeadBg);
其中引入的庫應(yīng)為如下,將官方Glide的額外擴(kuò)展了,使其可以支持高斯模糊。
compile 'jp.wasabeef:glide-transformations:2.0.1'4、上下滑動(dòng),漸變背景圖透明度
由于NestedScrollView滾動(dòng)監(jiān)聽只能在API23以上才能使用,這里為了兼容需要額外處理,定義滾動(dòng)接口,具體:MyNestedScrollView
/*** 根據(jù)頁面滑動(dòng)距離改變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);}}}
這樣基本的效果就實(shí)現(xiàn)啦,其中如有需要還可以做些額外的處理,如當(dāng)背景圖不透明時(shí)切換標(biāo)題等~
實(shí)踐了很多實(shí)現(xiàn)這個(gè)頁面的方法,目前為止這個(gè)方案是最好的,效果體驗(yàn)幾乎是一樣,其中涉及到的知識(shí)點(diǎn)有:1、頁面跳轉(zhuǎn)共享元素曲線動(dòng)畫;2、透明狀態(tài)欄;3、Glide監(jiān)聽圖片加載狀態(tài)和加載固定大小圖片等;4、NestedScrollView在Api23下的滑動(dòng)兼容。
源碼地址:
https://github.com/youlookwhat/NeteaseMusicUI
到這里就結(jié)束啦。
