仿网易云音乐Android端歌手资料页面的实现
最近項目首頁需要用到Banner + tab + ViewPager切換的效果,在思考實現的過程中我突然發現,這個效果與網易云音樂Android端的歌手資料頁面十分相似,因此好好把玩了一下網易云音樂,然后模仿出了一個效果類似的頁面,這里就將界面元素完全替換為模仿網易云音樂,作為一個demo拿來分享。
項目地址:網易云音樂歌手資料頁面Demo
說一下實現思路:
頁面分為三個部分,最上方是透明的自定義導航欄(Toolbar),下面是帶有歌手圖片和PagerSlidingTabStrip的Header,最下方是帶有各個子頁面的ViewPager。在滑動的過程中是不能夠改變ViewPager里面滑動組件的高度的,不然會導致滑動距離判斷出現異常,因此ViewPager實際上是占滿整個屏幕的。為了保證上面的Header不會把列表項擋住,在各個Fragment中加入一個與Header高度一樣的空View作為占位。這樣基本上就完成了基本頁面的樣式。水平滑動基本上是沒什么問題了。
接下來就要解決上下滑動時Header的伸縮距離與ViewPager內滑動元素的滾動同步的問題。
列表頁面使用RecyclerView,各種控件組合的頁面使用ScrollView,這些控件的滑動距離與Header伸縮的距離是1:1的,而滑動距離與Header變色實際上也是一次函數關系,因此只需要檢測到RecyclerView和ScrollView的滑動距離,就可以根據這個值的變化來改變頭部,RecyclerView可以通過addOnScrollChangedListener來監測滑動距離:
rcvGoodsList.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrolled(RecyclerView recyclerView, final int dx, final int dy) {super.onScrolled(recyclerView, dx, dy);scrolledX += dx;scrolledY += dy;if(HomeListFragment.this.isResumed()) {doOnScrollChanged(scrolledX, scrolledY, dx, dy);}}});scrolledX和scrolledY分別記錄了RecyclerView的滑動距離,并通過設定在Fragment中的Listener傳遞給上層。
對于ScrollView則需要繼承重寫,并為其添加滑動距離監測的方法:
public class ObservableScrollView extends ScrollView {public interface OnScrollChangedListener {void onScrollChanged(ScrollView scrollView, int scrolledX, int scrolledY, int dx, int dy);}private int scrolledX;private int scrolledY;private OnScrollChangedListener listener;public ObservableScrollView(Context context) {super(context);}public ObservableScrollView(Context context, AttributeSet attrs) {super(context, attrs);}public ObservableScrollView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public void setOnScrollChangedListener(OnScrollChangedListener listener) {this.listener = listener;}@Overrideprotected void onScrollChanged(int l, int t, int oldl, int oldt) {super.onScrollChanged(l, t, oldl, oldt);int dl = l - oldl;int dt = t - oldt;scrolledX += dl;scrolledY += dt;if(listener != null) {listener.onScrollChanged(this, getScrollX(), getScrollY(), dl, dt);}} }
/*** 初始化滑動參數,k值* */private void initSlidingParams() {int headerSize = getResources().getDimensionPixelOffset(R.dimen.home_header_size);int navBarHeight = getResources().getDimensionPixelOffset(R.dimen.nav_bar_height);int tabStripHeight = getResources().getDimensionPixelOffset(R.dimen.tabstrip_height);slidingDistance = headerSize - navBarHeight - tabStripHeight;Log.d("HomeFragment", "slidingDistance" + slidingDistance);}/*** 根據頁面滑動距離改變Header方法* */private void scrollChangeHeader(int scrolledY) {if (scrolledY < 0) {scrolledY = 0;}if (scrolledY < slidingDistance) {rlNavBar.setBackgroundColor(Color.argb(scrolledY * 192 / slidingDistance, 0x00, 0x00, 0x00));llHeader.setPadding(0, -scrolledY, 0, 0);currScrollY = scrolledY;} else {rlNavBar.setBackgroundColor(Color.argb(192, 0x00, 0x00, 0x00));llHeader.setPadding(0, -slidingDistance, 0, 0);currScrollY = slidingDistance;}}
對于這個問題,我又看了一眼網易云音樂的頁面,發現它的做法是在切換時把各個列表的滑動距離都設定為當前Header的滑動距離,so,我也采取了這樣的方法
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Overridepublic void onPageSelected(int position) {currentPosition = position;displayFragments.get(position).setScrolledY(currScrollY);}@Overridepublic void onPageScrollStateChanged(int state) {}});在Fragment基類中
public abstract void setScrolledY(int scrolledY);在含有RecyclerView的Fragment中 @Overridepublic void setScrolledY(int scrolledY) {if(rcvGoodsList != null) {if (this.scrolledY >= scrolledY) {int scrollDistahan'yorollBy(0, scrollDistance);}else {rcvGoodsList.scrollBy(0, scrolledY);}}}
這樣就實現了滑動距離的同步,最后一個問題是下拉刷新與列表上滑手勢的沖突,在這里我使用的是SwipeRefreshLayout來實現下拉刷新,因此對于此沖突的解決辦法就是自定義SwipeRefreshLayout,重寫onInterceptTouchEvent,加入監聽,如果Header伸縮距離沒有恢復到0,就不觸發下拉刷新。
@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {if (listener != null && !listener.onInterceptTouchEvent(event)) {return false;}return super.onInterceptTouchEvent(event);}
設定監聽器
srlRefresh.setOnInterceptTouchEventListener(new CusSwipeRefreshLayout.OnInterceptTouchEventListener() {@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {return currScrollY == 0;}});這樣基本的效果就已經實現了,在網易云音樂的頁面中還有一個可以橫向滑動的列表,這里也需要在ViewPager中對水平滑動的事件進行攔截判斷,只不過我暫時用不上就沒有實現了,原理同下拉刷新,代碼都在Github上,這里只列出了一些實現思路相關的代碼,僅供參考
總結
以上是生活随笔為你收集整理的仿网易云音乐Android端歌手资料页面的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 更改NavMenu 导航菜单激活时的背景
- 下一篇: 小程序抢购页面倒计时定时器