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复杂布局的更多相关文章

  1. 2.Android高仿网易云音乐-引导界面和广告界面实现

    效果图 效果图依次为图片广告,视频广告,引导界面. 系列文章目录导航 目录 1.实现分析 广告界面就是显示图片和视频,所以可以放一个图片控件,视频控件,然后跳过按钮,提示按钮,WiFi预加载提示都是放 ...

  2. Android高仿网易云音乐-启动界面实现和动态权限处理

    效果 实现分析 基本上没有什么难点,就是布局,然后显示用户协议对话框,动态处理权限,判断是否显示引导界面,是否显示广告界面等. 布局 <?xml version="1.0" ...

  3. 新鲜出炉高仿网易云音乐 APP

    我的引语 晚上好,我是吴小龙同学,我的公众号「一分钟GitHub」会推荐 GitHub 上好玩的项目,一分钟 get 一个优秀的开源项目,挖掘开源的价值,欢迎关注我. 项目中成长是最快的,如何成长,就 ...

  4. Android项目实战之高仿网易云音乐项目介绍

    这一节我们来讲解这个项目所用到的一些技术,以及一些实现的效果图,让大家对该项目有一个整体的认识,推荐大家收藏该文章,因为我们发布文章后会在该文章里面加入链接,这样大家找着就很方便. 目录 第1章 前期 ...

  5. 用vuejs仿网易云音乐(实现听歌以及搜索功能)

    前言 前端时间学了vue,一开始看了vue1.0,后来实在觉得技术总得实践,就直接上手vue2.0.然后花了将近一周时间做了一个网易云音乐的小项目.一开始觉得项目比较小,没必要用vuex所以就没有使用 ...

  6. Android项目实战之高仿网易云音乐创建项目和配置

    这一节我们来讲解创建项目:说道大家可能就会说了,创建项目还有谁不会啊,还需要讲吗,别急听我慢慢到来,肯定有你不知道的. 使用项目Android Studio创建项目我们这里就不讲解了,主要是讲解如何配 ...

  7. 《云阅》一个仿网易云音乐UI,使用Gank.Io及豆瓣Api开发的开源项目

    CloudReader 一款基于网易云音乐UI,使用GankIo及豆瓣api开发的符合Google Material Desgin阅读类的开源项目.项目采取的是Retrofit + RxJava + ...

  8. 实现 60fps 的网易云音乐首页

    网易云音乐是一款很优秀的音乐软件,我也是它的忠实用户.最近在研究如何更好的开发TableView,接着我写了一个Model驱动的小框架 - MDTable.为了去验证框架的可用性,我选择了网易云音乐的 ...

  9. C# WPF 低仿网易云音乐(PC)Banner动画控件

    原文:C# WPF 低仿网易云音乐(PC)Banner动画控件 由于技术有限没能做到一模一样的动画,只是粗略地做了一下.动画有点生硬,还有就是没做出网易云音乐的立体感.代码非常简单粗暴,而且我也写有很 ...

随机推荐

  1. 详解 Java 17 中新推出的密封类

    Java 17推出的新特性Sealed Classes经历了2个Preview版本(JDK 15中的JEP 360.JDK 16中的JEP 397),最终定稿于JDK 17中的JEP 409.Seal ...

  2. 四、针对redis容灾切换导致"脑裂"的情况

    网上参考到别人博客说,redis容灾切换的时候,有几率出现脑裂的情况. 什么是脑裂: sentinel判断master宕机,切换slave为新master的过程中,业务数据还在持续往原master写入 ...

  3. 2.0 vue循环和方法调用

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. 485. Max Consecutive Ones - LeetCode

    Question 485. Max Consecutive Ones Solution 题目大意:给一个数组,取连续1的最大长度 思路:遍历数组,连续1就加1,取最大 Java实现: public i ...

  5. TypeError: this.getOptions is not a function

    我在vue ui界面中安装版本依赖包后报这个错误 less-loader/sass-loader安装的版本过高 解决办法 删除原有的版本依赖包,安装更低版本的依赖包. 如 @6.0.1为选择安装的版本 ...

  6. 剖析虚幻渲染体系(15)- XR专题

    目录 15.1 本篇概述 15.1.1 本篇内容 15.1.2 XR概念 15.1.2.1 VR 15.1.2.2 AR 15.1.2.3 MR 15.1.2.4 XR 15.1.3 XR综述 15. ...

  7. QT 基于QScrollArea的界面嵌套移动

    在实际的应用场景中,经常会出现软件界面战场图大于实际窗体大小,利用QScrollArea可以为widget窗体添加滚动条,可以实现小窗体利用滚动条显示大界面需求.实现如下: QT创建一个qWidget ...

  8. SRE,了解一下?35+岁程序员新选择

    摘要:随着云业务的发展,今后会有越来越多的工程师深入到SRE领域. 本文分享自华为云社区<浅谈SRE角色认知>,作者: SRE确定性运维. 一.什么是SRE? SRE(Site Relia ...

  9. powershell命令总结

    2021-07-21 初稿 ps命令采用动词-名词的方式命名,不区分大小写.默认当前文件夹为当前路径./.除去-match使用正则表达式匹配外,其他都使用*和?通配符. 速查 管道命令 前一个的输出作 ...

  10. 批处理(bat、cmd)命令总结

    2021-07-21 初稿 注释与回显 rem 回显 @取消单行回显 rem 注释有三种方式 :: %content% rem rem @取消单行回显,echo off取消后面的回显 @echo of ...