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


    0.效果图

    效果图依次为发现界面顶部,包含首页轮播图,水平滚动的按钮,推荐歌单;然后是发现界面推荐单曲,点击单曲就是直接进入播放界面;最后是全局播放控制条上点击播放列表按钮显示的播放列表弹窗。

    1.整体分析

    整体使用RecycerView实现,每个不同的块是一个Item,例如:轮播图是一个Item,按钮也是,推荐歌单和下面的歌单是,推荐单曲,还有最后的自定义首页那块也是一样。

    提示:之所以把推荐歌单下面的歌单和推荐歌单标题放一个Item,主要是首页要实现自定义顺序功能,更方便管理。

    2.轮播图

    2.1 布局

    
    <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 bannerImageAdapter = new BannerImageAdapter(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 布局

    
    <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 布局

    
    <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 布局

    
    <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 {
    
        ...
    
        @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()));
        }
    }
    
    
    折叠

    感谢你的阅读,更多文章请关注我们,点击,评论,转发支持。

  • 相关阅读:
    haas506 2.0开发教程-sntp(仅支持2.2以上版本)
    备战数学建模45-粒子群算法优化BP神经网络(攻坚站10)
    docker去掉sudo权限方法
    redis 通信协议(RESP),最简单的应用层协议,没有之一
    JCTC:基于PWmat中的混合溶剂模型精确计算离子溶解自由能
    应届生Java面试经验总结
    DynamicProgramming 动态规划
    黑马笔记---常见算法与Lambda表达式
    uniapp 实现双击点赞出现特效
    抽象类的规则
  • 原文地址:https://www.cnblogs.com/woblog/p/16513959.html