Android网易云音乐
爱上学习啊 人气:0效果图
效果图依次为发现界面顶部,包含首页轮播图,水平滚动的按钮,推荐歌单;然后是发现界面推荐单曲,点击单曲就是直接进入播放界面;最后是全局播放控制条上点击播放列表按钮显示的播放列表弹窗。
整体分析
整体使用RecycerView实现,每个不同的块是一个Item,例如:轮播图是一个Item,按钮也是,推荐歌单和下面的歌单是,推荐单曲,还有最后的自定义首页那块也是一样。
提示:之所以把推荐歌单下面的歌单和推荐歌单标题放一个Item,主要是首页要实现自定义顺序功能,更方便管理。
轮播图
布局
<?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>
显示数据
//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()));
按钮
布局
<?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>
显示数据
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); }
推荐歌单
布局
<?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>
显示数据
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()); }
底部
布局
<?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>
显示数据
holder.getView(R.id.refresh_button).setOnClickListener(v -> discoveryAdapterListener.onRefreshClick()); holder.getView(R.id.custom).setOnClickListener(v -> discoveryAdapterListener.onCustomDiscoveryClick());
迷你控制条
他是一个自定义Fragment,哪里要显示就放到哪里就行了。
播放列表弹窗
/** * 播放列表对话框 */ 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())); } }
加载全部内容