仿网易云音乐Android端歌手资料页面的实现
来源:互联网 发布:python 量化论坛 编辑:程序博客网 时间:2024/06/16 06:53
最近项目首页需要用到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() { @Override public 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; } @Override protected 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() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { currentPosition = position; displayFragments.get(position).setScrolledY(currScrollY); } @Override public void onPageScrollStateChanged(int state) { } });
在Fragment基类中
public abstract void setScrolledY(int scrolledY);
在含有RecyclerView的Fragment中
@Override public void setScrolledY(int scrolledY) { if(rcvGoodsList != null) { if (this.scrolledY >= scrolledY) { int scrollDistahan'yorollBy(0, scrollDistance); } else { rcvGoodsList.scrollBy(0, scrolledY); } } }
@Override public void setScrolledY(int scrolledY) { if (osvHomeRecommend != null) { osvHomeRecommend.scrollTo(0, scrolledY); } }
这样就实现了滑动距离的同步,最后一个问题是下拉刷新与列表上滑手势的冲突,在这里我使用的是SwipeRefreshLayout来实现下拉刷新,因此对于此冲突的解决办法就是自定义SwipeRefreshLayout,重写onInterceptTouchEvent,加入监听,如果Header伸缩距离没有恢复到0,就不触发下拉刷新。
@Override public boolean onInterceptTouchEvent(MotionEvent event) { if (listener != null && !listener.onInterceptTouchEvent(event)) { return false; } return super.onInterceptTouchEvent(event); }
设定监听器
srlRefresh.setOnInterceptTouchEventListener(new CusSwipeRefreshLayout.OnInterceptTouchEventListener() { @Override public boolean onInterceptTouchEvent(MotionEvent event) { return currScrollY == 0; } });
这样基本的效果就已经实现了,在网易云音乐的页面中还有一个可以横向滑动的列表,这里也需要在ViewPager中对水平滑动的事件进行拦截判断,只不过我暂时用不上就没有实现了,原理同下拉刷新,代码都在Github上,这里只列出了一些实现思路相关的代码,仅供参考
- 仿网易云音乐Android端歌手资料页面的实现
- Android仿网易云音乐转盘的实现
- Qt音乐进度条的实现仿网易云音乐
- 关于scrapy采集网易云音乐歌手遇到的问题
- 仿网易云音乐部分UI实现
- Android仿网易云音乐播放界面
- Android仿网易云音乐播放界面
- 仿网易云音乐
- 仿网易云音乐的播放进度条
- 仿网易云音乐的滑动效果
- 仿网易云音乐MV的webapp
- 仿网易云音乐MV的webapp
- 仿网易云的音乐播放器
- iOS-VLCKit实现仿网易云音乐播放音乐
- Android仿网易云音乐播放页面 背景虚化碟片效果
- Android漂亮的音乐歌词控件,仿网易云音乐滑动效果
- 高仿网易云音乐客户端的Home页面切换Tabhost-IT蓝豹
- 如何实现列表滑动标签置顶效果(以天天动听、网易云音乐、虾米音乐的歌手页为例)
- WindowFrom之ListBox实例
- hdu 1115 Lifting the Stone【多边形重心】
- linux服务器部署jenkins,让代码定时自动编译
- 迷之RxJava(四)—— Retrofit和RxJava的基情
- Microsoft SQL Server 数据库的索引运算分析
- 仿网易云音乐Android端歌手资料页面的实现
- 决策树 算法
- python网络爬虫学习(二)一个爬取百度贴吧的爬虫程序
- 使用Autolayout实现UITableView的Cell动态布局和高度动态改变
- 使用AsyncTask异步任务下载数据
- VS2010:指定的平台工具集(v110)未安装或无效
- hrtimer的简单使用 + 原理和实现
- 复制一个对象
- android模拟器无法使用camera拍照