3.Android高仿網易雲音樂-首頁複雜發現介面佈局和功能/RecyclerView複雜佈局

2022-07-24 12:00:42

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()));
    }
}

感謝你的閱讀,更多文章請關注我們,點選,評論,轉發支援。