3.Android高仿网易云音乐-首页复杂发现界面布局和功能/RecyclerView复杂布局
0.效果图

效果图依次为发现界面顶部,包含首页轮播图,水平滚动的按钮,推荐歌单;然后是发现界面推荐单曲,点击单曲就是直接进入播放界面;最后是全局播放控制条上点击播放列表按钮显示的播放列表弹窗。
1.整体分析
整体使用RecycerView实现,每个不同的块是一个Item,例如:轮播图是一个Item,按钮也是,推荐歌单和下面的歌单是,推荐单曲,还有最后的自定义首页那块也是一样。
提示:之所以把推荐歌单下面的歌单和推荐歌单标题放一个Item,主要是首页要实现自定义顺序功能,更方便管理。
2.轮播图
2.1 布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="wrap_content"
android:layout_margin="@dimen/padding_outer">
<com.youth.banner.Banner
android:id="@+id/banner"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,0.389"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
2.2 显示数据
//banner
BannerData data = (BannerData) d;
Banner bannerView = holder.getView(R.id.banner);
BannerImageAdapter<Ad> bannerImageAdapter = new BannerImageAdapter<Ad>(data.getData()) {
@Override
public void onBindView(BannerImageHolder holder, Ad data, int position, int size) {
ImageUtil.show(getContext(), (ImageView) holder.itemView, data.getIcon());
}
};
bannerView.setAdapter(bannerImageAdapter);
bannerView.setOnBannerListener(onBannerListener);
bannerView.setBannerRound(DensityUtil.dip2px(getContext(), 10));
//添加生命周期观察者
bannerView.addBannerLifecycleObserver(fragment);
bannerView.setIndicator(new CircleIndicator(getContext()));
按钮
3.1 布局
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="@dimen/padding_outer"
android:scrollbars="none">
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingHorizontal="@dimen/padding_meddle">
</LinearLayout>
</HorizontalScrollView>
3.2 显示数据
LinearLayout container = holder.getView(R.id.container);
if (container.getChildCount() > 0) {
//已经添加了
return;
}
//横向显示5个半
float containerWidth = ScreenUtil.getScreenWith(container.getContext()) - DensityUtil.dip2px(container.getContext(), 10 * 2);
int itemWidth = (int) (containerWidth / 5.5);
DiscoveryButtonBinding binding;
LinearLayout.LayoutParams layoutParams;
for (IconTitleButtonData it : data.getData()) {
binding = DiscoveryButtonBinding.inflate(LayoutInflater.from(getContext()));
binding.icon.setImageResource(it.getIcon());
binding.title.setText(it.getTitle());
if (it.getIcon() == R.drawable.day_recommend) {
SuperViewUtil.show(binding.more);
//显示日期
binding.more.setText(String.valueOf(SuperDateUtil.currentDay()));
}
//设置点击事件
binding.getRoot().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
layoutParams = new LinearLayout.LayoutParams(itemWidth, ViewGroup.LayoutParams.WRAP_CONTENT);
container.addView(binding.getRoot(), layoutParams);
}
4.推荐歌单
4.1 布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/item_discovery_title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/padding_outer"
android:paddingBottom="@dimen/d5" />
</LinearLayout>
4.2 显示数据
private void bindSheetData(BaseViewHolder holder, SheetData data) {
//设置标题,将标题放到每个具体的item上,好处是方便整体排序
holder.setText(R.id.title, R.string.recommend_sheet);
//显示更多容器
holder.setVisible(R.id.more, true);
holder.getView(R.id.more).setOnClickListener(v -> {
});
RecyclerView listView = holder.getView(R.id.list);
if (listView.getAdapter() == null) {
//设置显示3列
GridLayoutManager layoutManager = new GridLayoutManager(listView.getContext(), 3);
listView.setLayoutManager(layoutManager);
sheetAdapter = new SheetAdapter(R.layout.item_sheet);
//item点击
sheetAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
if (discoveryAdapterListener != null) {
discoveryAdapterListener.onSheetClick((Sheet) adapter.getItem(position));
}
}
});
listView.setAdapter(sheetAdapter);
GridDividerItemDecoration itemDecoration = new GridDividerItemDecoration(getContext(), (int) DensityUtil.dip2px(getContext(), 5F));
listView.addItemDecoration(itemDecoration);
}
sheetAdapter.setNewInstance(data.getData());
}
5. 底部
5.1 布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="@dimen/padding_outer"
android:gravity="center_horizontal"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView
android:id="@+id/refresh_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/refresh"
android:gravity="center_vertical"
android:text="@string/click_refresh"
android:textColor="@color/link"
android:textSize="@dimen/text_small" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/padding_small"
android:text="@string/change_content"
android:textColor="@color/black80"
android:textSize="@dimen/text_small" />
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.button.MaterialButton
android:id="@+id/custom"
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
android:layout_width="wrap_content"
android:layout_height="@dimen/d30"
android:layout_marginTop="@dimen/padding_outer"
android:backgroundTint="?attr/colorSurface"
android:insetTop="0dp"
android:insetBottom="0dp"
android:text="@string/custom_discovery"
android:textColor="@color/black80"
android:textSize="@dimen/text_small"
app:cornerRadius="@dimen/d15"
app:elevation="0dp"
app:strokeColor="@color/black80"
app:strokeWidth="@dimen/d0_5" />
</LinearLayout>
5.2 显示数据
holder.getView(R.id.refresh_button).setOnClickListener(v -> discoveryAdapterListener.onRefreshClick());
holder.getView(R.id.custom).setOnClickListener(v -> discoveryAdapterListener.onCustomDiscoveryClick());
6.迷你控制条
他是一个自定义Fragment,哪里要显示就放到哪里就行了。
7.播放列表弹窗
/**
* 播放列表对话框
*/
public class MusicPlayListDialogFragment extends BaseViewModelBottomSheetDialogFragment<FragmentDialogAudioPlayListBinding> {
...
@Override
protected void initListeners() {
super.initListeners();
//删除所有按钮点击
binding.deleteAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//关闭对话框
dismiss();
//删除全部音乐
getMusicListManager().deleteAll();
}
});
//item中子控件点击
//删除按钮点击
adapter.addChildClickViewIds(R.id.delete);
adapter.setOnItemChildClickListener(new OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
//由于这里只有一个按钮点击
//所以可以不判断
if (R.id.delete == view.getId()) {
//删除按钮点击
removeItem(position);
}
}
});
//循环模式点击
binding.loopModel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//更改循环模式
getMusicListManager().changeLoopModel();
//显示循环模式
showLoopModel();
}
});
//设置item点击事件
adapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
//关闭dialog
//可以根据具体的业务逻辑来决定是否关闭
dismiss();
//播放点击的这首音乐
getMusicListManager().play(getMusicListManager().getDatum().get(position));
}
});
}
private void removeItem(int position) {
adapter.removeAt(position);
//从列表管理器中删除
getMusicListManager().delete(position);
showCount();
}
/**
* 显示循环模式
*/
private void showLoopModel() {
PlayListUtil.showLoopModel(getMusicListManager().getLoopModel(), binding.loopModel);
}
private void showCount() {
binding.count.setText(String.format("(%d)", getMusicListManager().getDatum().size()));
}
}
感谢你的阅读,更多文章请关注我们,点击,评论,转发支持。
3.Android高仿网易云音乐-首页复杂发现界面布局和功能/RecyclerView复杂布局的更多相关文章
- 2.Android高仿网易云音乐-引导界面和广告界面实现
效果图 效果图依次为图片广告,视频广告,引导界面. 系列文章目录导航 目录 1.实现分析 广告界面就是显示图片和视频,所以可以放一个图片控件,视频控件,然后跳过按钮,提示按钮,WiFi预加载提示都是放 ...
- Android高仿网易云音乐-启动界面实现和动态权限处理
效果 实现分析 基本上没有什么难点,就是布局,然后显示用户协议对话框,动态处理权限,判断是否显示引导界面,是否显示广告界面等. 布局 <?xml version="1.0" ...
- 新鲜出炉高仿网易云音乐 APP
我的引语 晚上好,我是吴小龙同学,我的公众号「一分钟GitHub」会推荐 GitHub 上好玩的项目,一分钟 get 一个优秀的开源项目,挖掘开源的价值,欢迎关注我. 项目中成长是最快的,如何成长,就 ...
- Android项目实战之高仿网易云音乐项目介绍
这一节我们来讲解这个项目所用到的一些技术,以及一些实现的效果图,让大家对该项目有一个整体的认识,推荐大家收藏该文章,因为我们发布文章后会在该文章里面加入链接,这样大家找着就很方便. 目录 第1章 前期 ...
- 用vuejs仿网易云音乐(实现听歌以及搜索功能)
前言 前端时间学了vue,一开始看了vue1.0,后来实在觉得技术总得实践,就直接上手vue2.0.然后花了将近一周时间做了一个网易云音乐的小项目.一开始觉得项目比较小,没必要用vuex所以就没有使用 ...
- Android项目实战之高仿网易云音乐创建项目和配置
这一节我们来讲解创建项目:说道大家可能就会说了,创建项目还有谁不会啊,还需要讲吗,别急听我慢慢到来,肯定有你不知道的. 使用项目Android Studio创建项目我们这里就不讲解了,主要是讲解如何配 ...
- 《云阅》一个仿网易云音乐UI,使用Gank.Io及豆瓣Api开发的开源项目
CloudReader 一款基于网易云音乐UI,使用GankIo及豆瓣api开发的符合Google Material Desgin阅读类的开源项目.项目采取的是Retrofit + RxJava + ...
- 实现 60fps 的网易云音乐首页
网易云音乐是一款很优秀的音乐软件,我也是它的忠实用户.最近在研究如何更好的开发TableView,接着我写了一个Model驱动的小框架 - MDTable.为了去验证框架的可用性,我选择了网易云音乐的 ...
- C# WPF 低仿网易云音乐(PC)Banner动画控件
原文:C# WPF 低仿网易云音乐(PC)Banner动画控件 由于技术有限没能做到一模一样的动画,只是粗略地做了一下.动画有点生硬,还有就是没做出网易云音乐的立体感.代码非常简单粗暴,而且我也写有很 ...
随机推荐
- 图文详解:小白也能看懂的 Kubernetes
Kubernetes 这个单词来自于希腊语,含义是舵手或领航员 .其词根是 governor 和 cybernetic.K8s 是它的缩写,用 8 字替代了"ubernete". ...
- web框架的本质、MVC框架MTV框架的介绍
1.web框架的本质 所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端,基于请求做出响应,客户都先请求,服务端做出对应的响应,按照http协议的请求协议发送请 ...
- Golang 函数 方法 接口的简单介绍
函数 函数是基本的代码块,通常我们会将一个功能封装成一个函数,方便我们调用,同时避免代码臃肿复杂. 函数的基本格式 func TestFunc(a int, b string) (int, strin ...
- 那些年你啃过的ConcurrentHashMap
前言 我是fancy,一个年纪轻轻bug量就累计到3200个的程序员,同事们都夸我一个人养活了整个测试组. 最近迷上了并发编程.并发这玩意怎么说呢,就是你平时工作用不到,一用就用在面试上.这不,又卷起 ...
- Nvidia Triton使用教程:从青铜到王者
1 相关预备知识 模型:包含了大量参数的一个网络(参数+结构),体积10MB-10GB不等 模型格式:相同的模型可以有不同的存储格式(可类比音视频文件),目前主流有torch.tf.onnx和trt, ...
- 如何生成一个java文档
如何生成一个java文档 众所周知,一个程序给别人看可能可以看懂,几万行程序就不一定了.在更多的时候,我们并不需要让别人知道我们的程序是怎么写的,只需要告诉他们怎么用的.那么,api文档就发挥了它的作 ...
- CSAPP 之 ShellLab 详解
前言 本篇博客将会详细介绍 CSAPP 之 ShellLab 的完成过程,实现一个简易(lou)的 shell.tsh 拥有以下功能: 可以执行外部程序 支持四个内建命令,名称和功能为: quit:退 ...
- 【Windbg】记一次线程卡主的问题
测试告诉我们定时任务没有执行了,排查相关日志,只有开始执行,没有执行结束.估计是什么地方卡主了. 所以dump分析日志 先检查一下加载情况 !eeversion 线程卡主了,先看线程 !runaway ...
- 20212115 实验二 《python程序设计》实验报告
实验二 计算器设计 #20212115 2021-2022-2 <python程序设计> 实验报告二 课程: 课程:<Python程序设计>班级: 2121姓名: 朱时鸿学号: ...
- Public Round #1
传送门 [PR #1]删数 题意:写的很清楚了,略 思路: 首先转化为差分数组,两个连续数相同,删掉,乘二放进去. 发现能互相转化的两个数,符号,值\(/lowbit\)都一样. 把能相互转化的数归为 ...