Android|使用BottomSheetDialog和RecyclerView实现底部弹出评论区功能

2023.03.31 补充该功能在 Fragment 中的使用方法:

Tip:使用Activity实现的直接看下面就行,不用看这一节代码

首先需要将CommentBottomDialog.javaActivity进行关联(我使用的是一个Activity管理多个Fragment),在Activity页将Fragment添加进容器 (有FragmentManager的话直接添加进容器即可,不用重新写一遍代码),下面是示例代码:

		//获取FragmentManager
        FragmentManager fragmentManager = getSupportFragmentManager();
        //开始事务
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        //将Fragment添加到容器视图中
        CommentBottomDialog commentBottomDialog = new CommentBottomDialog();
        fragmentTransaction.add(R.id.oneLayout, commentBottomDialog);
        //提交事务
        fragmentTransaction.commit();

这时,在需要使用该功能的地方使用如下代码即可:

	 	//创建MyBottomSheetDialogFragment的实例
        CommentBottomDialog bottomSheet = new CommentBottomDialog();
		//显示MyBottomSheetDialogFragment
        bottomSheet.show(getFragmentManager(), "bottomDialog");

错误分析:

如果Fragment尚未添加到Activity中,使用 getContext() 方法和 requireContext() 方法将会返回null,此时再调用 getFragmentManager() 方法或 getSupportFragmentManager() 方法就会导致空指向异常。
所以在Fragment页面中实现此功能,原先就有FragmentManager的情况下要先将CommentBottomDialog.java,这个我们定义的Fragment文件添加进Activity中去,就可以顺利取到FragmentManager了。


以下是原文章:

实现效果

效果图

实现过程

先使用BottomSheetDialog实现页面从底部弹出效果

创建一个类CommentBottomDialog.java并继承:BottomSheetDialogFragment重写 onCreateDialog 方法:

package com.example.bottomsheetdialog1;

import android.app.Dialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;

import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;

import org.jetbrains.annotations.NotNull;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class CommentsBottomDialog extends BottomSheetDialogFragment {

    @NonNull
    @NotNull
    @Override
    public Dialog onCreateDialog(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        if (getActivity() == null) return super.onCreateDialog(savedInstanceState);
        // 第二个参数是设置 dialog 的背景样式
        BottomSheetDialog dialog = new BottomSheetDialog(getActivity(), R.style.BottomSheetStyle);
        // 这个是设置 dialog 弹出动画
        Window window = dialog.getWindow();
        if (window != null) {
            window.setWindowAnimations(R.style.BottomSheetStyle);
        }

        // 设置 dialog 布局
        initView(dialog);
        return dialog;

    }

    private void initView(BottomSheetDialog dialog) {
        View root = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_comment, null);
        dialog.setContentView(root);
        //设置高度
        ViewGroup.LayoutParams params = root.getLayoutParams();
        params.height = (int) (0.9 *
                getResources().getDisplayMetrics().heightPixels);
        root.setLayoutParams(params);

        // 初始化 dialog 布局里的控件
        ImageView iv_close = root.findViewById(R.id.iv_close);

        // 点击关闭 dialog
        iv_close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog.dismiss();
            }
        });
    }
}

创建CommentBottomDialog.java对应的XML布局文件dialog_comment.xml

<?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="match_parent"
    android:background="@drawable/shape"
    android:padding="10dp"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/cardTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:textSize="16sp"
            android:textColor="#000000"
            android:text="评论" />

        <ImageView
            android:id="@+id/iv_close"
            android:src="@drawable/close"
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_alignParentRight="true"
            />
    </RelativeLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:background="#000000"/>
        
</LinearLayout>

values文件夹中创建styles.xml文件并在其中创建BottomSheetStyle布局样式:

    <!-- BottomDialog -->
    <style name="BottomSheetStyle" parent="Theme.AppCompat.Dialog">
        <!-- 背景透明 -->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!-- 边框 -->
        <item name="android:windowFrame">@null</item>
        <!-- 调暗 -->
        <item name="android:backgroundDimEnabled">true</item>
        <!-- 是否浮现在activity之上 -->
        <item name="android:windowIsFloating">true</item>
        <!-- 动画 -->
        <item name="android:windowEnterAnimation">@anim/popup_in</item>
        <item name="android:windowExitAnimation">@anim/popup_out</item>
    </style>

drawable文件夹中新建背景文件shape.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <!-- rectangle表示为矩形 -->

    <!-- 填充的颜色 -->
    <solid android:color="@color/white" />

    <!-- 边框的颜色和粗细 -->
    <stroke
        android:width="1dp"
        android:color="@color/white" />

    <!-- android:radius 关键点,圆角的半径 -->
    <corners
        android:radius="2dp"
        android:topLeftRadius="8dp"
        android:topRightRadius="8dp"
        android:bottomRightRadius="0dp"
        android:bottomLeftRadius="0dp" />

</shape>

res文件夹下创建anim文件夹并新建两个动画文件:

文件名:popup_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        android:fromYDelta="100%p"
        android:toYDelta="0"
        android:duration="400"/>

    <alpha android:fromAlpha="0"
        android:toAlpha="1.0"
        android:duration="400"/>

</set>

文件名:popup_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        android:fromYDelta="0"
        android:toYDelta="100%p"
        android:duration="500"/>

    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0"
        android:duration="500"/>

</set>

到此使用BottomSheetDialog实现底部弹出页面功能已经实现,直接调用以下代码即可:

CommentsBottomDialog bottomDialog = new CommentsBottomDialog();
bottomDialog.show(MainActivity.this.getSupportFragmentManager(), "bottomDialog");

再实现RecyclerView的功能

首先在弹窗布局文件dialog_comment.xml中加入RecyclerView控件:

<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:overScrollMode="never"
        />

创建Comments.java数据实体类:

package com.example.bottomsheetdialog1;

public class Comments {

    private String content;  //评论
    private int imageId;  //头像

    public Comments(String name, int imageId){
        this.content = name;
        this.imageId = imageId;

    }

    public String getName() {
        return content;
    }

    public int getImageId() {
        return imageId;
    }}

创建RecyclerView中要实现的布局文件comments_item.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <ImageView
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:id="@+id/image"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"/>

</LinearLayout>

创建适配器文件CommentsAdapter.java

package com.example.bottomsheetdialog1;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

import androidx.recyclerview.widget.RecyclerView;

public class CommentsAdapter extends RecyclerView.Adapter<CommentsAdapter.ViewHolder> {

    //数据源,在new此类的时候传入
    private List<Comments> mCommentsList;

    //静态内部类,每个条目对应的布局
    static class ViewHolder extends RecyclerView.ViewHolder {
        ImageView image;
        TextView content;

        public ViewHolder(View view) {
            super(view);
            image = (ImageView) view.findViewById(R.id.image);
            content = (TextView) view.findViewById(R.id.content);
        }

    }

    //CommentsAdapter的构造方法,加入了数据源参数,在构造的时候赋值给mCommentsList
    public CommentsAdapter(List<Comments> commentsList) {
        mCommentsList = commentsList;
    }

    //用于创建ViewHolder实例,并把加载的布局传入到ViewHolder的构造函数去
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.comments_item, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    //用于对子项的数据进行赋值,会在每个子项被滚动到屏幕内时执行。position得到当前项的Comments实例
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Comments comments = mCommentsList.get(position);
        holder.image.setImageResource(comments.getImageId());
        holder.content.setText(comments.getName());
    }

    //返回RecyclerView的子项数目
    @Override
    public int getItemCount() {
        return mCommentsList.size();
    }

}

先在CommentsBottomDialog.java文件中定义一个全局List

private List<Comments> commentsList = new ArrayList<>();

之后在CommentsBottomDialog.java文件中创建一个方法造一些假数据用于测试功能:

    //初始化数据
    private void fakedata() {
        for (int i = 0; i < 3; i++) {
            Comments comments1 = new Comments("Test1", R.drawable.src);
            commentsList.add(comments1);
            Comments comments2 = new Comments("Test2", R.drawable.src);
            commentsList.add(comments2);
            Comments comments3 = new Comments("Test3", R.drawable.src);
            commentsList.add(comments3);
            Comments comments4 = new Comments("Test4", R.drawable.src);
            commentsList.add(comments4);
            Comments comments5 = new Comments("Test5", R.drawable.src);
            commentsList.add(comments5);
            Comments comments6 = new Comments("Test6", R.drawable.src);
            commentsList.add(comments6);
            Comments comments7 = new Comments("Test7", R.drawable.src);
            commentsList.add(comments7);
            Comments comments8 = new Comments("Test8", R.drawable.src);
            commentsList.add(comments8);
            Comments comments9 = new Comments("Test9", R.drawable.src);
            commentsList.add(comments9);
            Comments comments10 = new Comments("Test10", R.drawable.src);
            commentsList.add(comments10);

        }
    }

之后在CommentsBottomDialog.java文件中的*initView()*方法中写入:

 //初始化数据
        fakedata();
        //RecyclerView获取他的对象
        RecyclerView recyclerView = root.findViewById(R.id.recycler_view);
        //LayoutManager用于指定RecyclerView的布局方式
        LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext());
        //给layoutManager的展示方式设置为竖直方向
        layoutManager .setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);
        CommentsAdapter adapter = new CommentsAdapter(commentsList);
        recyclerView.setAdapter(adapter);

至此,使用BottomSheetDialogRecyclerView实现底部弹出评论区功能已经实现

全部代码

Tips:这里只放出在实现RecyclerView功能时有改动代码的代码,其余没放出的代码并未改动

dialog_comment.xml

<?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="match_parent"
    android:background="@drawable/shape"
    android:padding="10dp"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/cardTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:textSize="16sp"
            android:textColor="#000000"
            android:text="评论" />

        <ImageView
            android:id="@+id/iv_close"
            android:src="@drawable/close"
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_alignParentRight="true"
            />
    </RelativeLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:background="#000000"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:overScrollMode="never"
        />

</LinearLayout>

CommentsBottomDialog.java

package com.example.bottomsheetdialog1;

import android.app.Dialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;

import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

public class CommentsBottomDialog extends BottomSheetDialogFragment {

    private List<Comments> commentsList = new ArrayList<>();

    @NonNull
    @NotNull
    @Override
    public Dialog onCreateDialog(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        if (getActivity() == null) return super.onCreateDialog(savedInstanceState);
        // 第二个参数是设置 dialog 的背景样式
        BottomSheetDialog dialog = new BottomSheetDialog(getActivity(), R.style.BottomSheetStyle);
        // 这个是设置 dialog 弹出动画
        Window window = dialog.getWindow();
        if (window != null) {
            window.setWindowAnimations(R.style.BottomSheetStyle);
        }

        // 设置 dialog 布局
        initView(dialog);
        return dialog;

    }

    private void initView(BottomSheetDialog dialog) {
        View root = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_comment, null);
        dialog.setContentView(root);
        //设置高度
        ViewGroup.LayoutParams params = root.getLayoutParams();
        params.height = (int) (0.9 *
                getResources().getDisplayMetrics().heightPixels);
        root.setLayoutParams(params);

        // 初始化 dialog 布局里的控件
        ImageView iv_close = root.findViewById(R.id.iv_close);

        // 点击关闭 dialog
        iv_close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog.dismiss();
            }
        });


        //初始化数据
        fakedata();
        //RecyclerView获取他的对象
        RecyclerView recyclerView = root.findViewById(R.id.recycler_view);
        //LayoutManager用于指定RecyclerView的布局方式
        LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext());
        //给layoutManager的展示方式设置为竖直方向
        layoutManager .setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);
        CommentsAdapter adapter = new CommentsAdapter(commentsList);
        recyclerView.setAdapter(adapter);

    }

    //初始化数据
    private void fakedata() {
        for (int i = 0; i < 3; i++) {
            Comments comments1 = new Comments("Test1", R.drawable.src);
            commentsList.add(comments1);
            Comments comments2 = new Comments("Test2", R.drawable.src);
            commentsList.add(comments2);
            Comments comments3 = new Comments("Test3", R.drawable.src);
            commentsList.add(comments3);
            Comments comments4 = new Comments("Test4", R.drawable.src);
            commentsList.add(comments4);
            Comments comments5 = new Comments("Test5", R.drawable.src);
            commentsList.add(comments5);
            Comments comments6 = new Comments("Test6", R.drawable.src);
            commentsList.add(comments6);
            Comments comments7 = new Comments("Test7", R.drawable.src);
            commentsList.add(comments7);
            Comments comments8 = new Comments("Test8", R.drawable.src);
            commentsList.add(comments8);
            Comments comments9 = new Comments("Test9", R.drawable.src);
            commentsList.add(comments9);
            Comments comments10 = new Comments("Test10", R.drawable.src);
            commentsList.add(comments10);

        }
    }

}

结语

部分内容借鉴此篇博客:http://t.csdn.cn/RkXnb / http://t.csdn.cn/XCfgH

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值