欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android RecyclerView实现RadioButton绑定事件

程序员文章站 2022-05-14 13:05:06
...

最近项目忙,今天终于抽出时间写一个小功能的blog供大家参考。

需求,直接上图:

Android RecyclerView实现RadioButton绑定事件

比较简单的需求,就是实现一个底部弹出,供用户选择,选择是单选。底部弹出类似一个列表,有不同项,这里是人名和邮箱两项,还有一项是一个单选,选中以后将值填入主页面对应的空上。
实现可以有很多,我选择的是列表+Dialog底部弹出,单选按钮触发相应的回调事件将值回传给调用方直至返回到目标调用方(一会详细说这个)。

详细实现流程:
1. 主页面就是我们的填写送审单信息页面,有四个输入项,一个按钮,其中三个输入项都是要单选列表内容;
2. 主页面会调用一个自己实现的Dialog,从底部出现,然后设置回调值,在主页面接受这个值填到主页面相应的位置上;
3. Dialog调用一个RecyclerViewAdapter实现一个列表功能装载我要展示的数据;
4. 选中一个列表项item中的单击按钮,触发回调传值的事件;

网上没有一个完整的例子,实现这样一个需求,所以我完整的写一下,供大家参考:

  1. 主页面的调用:
/**
     * 根据列表返回值,设置姓名和邮箱
     * @param name
     * @param email
     * @param rank 因为接口的返回值是一二级混合的,所以需要区分出来
     */
    private void fillApprovePersonCallBack(final TextView name, final TextView email, final int rank) {

        Subscribe(getTbiApplication().getApiService(ApiApproveService.newEdition.class).getApprovePerson(orderNo), new IApiReturn<List<CApprove>>() {
            @Override
            public void run(ApiResult<List<CApprove>> apiResult) {
                if (apiResult.getCode() == ApiCodeEnum.SUCCESS.getCode()) {
                    List<CApprove> approves = new ArrayList<>();
                    List<CApprove> list = apiResult.getContent();
                    for (CApprove ca: list) {
                        if (rank == ca.getApverLevel()) {
                            approves.add(ca);
                        }
                    }
                    final DialogApprove dialog = new DialogApprove();
                    dialog.showDialogForApprovePerson(CApplyActivity.this, approves, new CommonCallback<CApprove>() {
                        @Override
                        public void onCallBack(CApprove data) {
                            if (1 == rank) {
                                firstApprovePerson = data;
                            } else {
                                secondApprovePerson = data;
                            }
                            name.setText(data.getApprovePersonName());
                            email.setText(data.getApprovePersonEmail());
                        }
                    });

                } else {
                    DialogUtil.showToastCust(CApplyActivity.this, apiResult.getMessage());
                }
            }
        });
    }

代码应该还好理解,区分了一下一二级审批的数据,这个是通过接口访问服务端的回传数据,重点在Dialog。这里就是Dialog的调用,传入了一个回调函数,回调函数很简单就是一个接口方法,用于将值抓回来。

  1. Dialog的实现:
    private RecyclerView approvalReasonRecyclerView;

    private Button selectBusinessReasonButton;

/**
     * 审批人的弹出框
     * @param ctx
     * @param callback
     */
    public void showDialogForApprovePerson(final Activity ctx, List<CApprove> cApproves, final CommonCallback<CApprove> callback) {
        //传入一个Style,可以自己定义样式
        final Dialog mAlertDialog = new Dialog(ctx, R.style.MyDialogStyle);
        //内容
        LayoutInflater inflater = LayoutInflater.from(ctx);
        //引用Dialog的布局,后面贴出代码
        View view = inflater.inflate(R.layout.dialog_c_approval_person, null);
        view.setTranslationX(mAlertDialog.getWindow().getAttributes().width);

        //弹出框列表的处理
        approvalReasonRecyclerView = (RecyclerView) view.findViewById(R.id.dialog_c_approval_person_rv);
        //这里实现一个RecyclerView的Adapter,也给它传入一个回调,以往我们都是展示多,涉及到交互的话可以用这种方式抓回列表的值
        CApprovePersonAdapter approvePersonAdapter = new CApprovePersonAdapter(new CommonCallback<CApprove>() {
            @Override
            public void onCallBack(CApprove data) {
                callback.onCallBack(data);
                mAlertDialog.dismiss();
            }
        });
        //习惯处理
        approvePersonAdapter.setDatas(cApproves);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ctx);
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        approvalReasonRecyclerView.setLayoutManager(linearLayoutManager);
        approvalReasonRecyclerView.setAdapter(approvePersonAdapter);

        //取消按钮的处理
        selectBusinessReasonButton = (Button) view.findViewById(R.id.dialog_c_approval_person_btn_cancel);
        selectBusinessReasonButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                CApprove approve = new CApprove("");
                callback.onCallBack(approve);
                mAlertDialog.dismiss();
            }
        });

        //控制Dialog的出现方式
        mAlertDialog.getWindow().getAttributes().gravity = Gravity.BOTTOM;
        mAlertDialog.getWindow().setWindowAnimations(R.style.alertTranStyle);
        mAlertDialog.show();
        mAlertDialog.getWindow().setContentView(view);
        mAlertDialog.getWindow().setLayout(ctx.getResources().getDisplayMetrics().widthPixels, mAlertDialog.getWindow().getAttributes().height);

    }

这里实现的RecyclerView的Adapter,区别于只需要展示的列表,这里还需要列表与外部的数据交互,因此给它传入一个回调,以往我们都是展示多,涉及到交互的话可以用这种方式抓回列表的值。这个处理在网上的资料中有时候说的就不明确了,所以小伙伴到这里可能会不知道该如何组织自己的数据,其实想通了就很简单,在这提个醒。

Dialog Layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dialog_c_approval_person"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:orientation="vertical">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/dialog_c_approval_person_rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:scrollbars="vertical" />
    </LinearLayout>

    <Button
        android:id="@+id/dialog_c_approval_person_btn_cancel"
        style="?android:borderlessButtonStyle"
        android:layout_width="match_parent"
        android:layout_height="44dp"
        android:layout_marginTop="10dp"
        android:background="@color/white"
        android:text="@string/c_approval_btn_cancel"
        android:textColor="@color/base_main_txt"
        android:textSize="16sp" />

</LinearLayout>

Layout可以直接用,很简单。

  1. 说说列表的实现。关键一个问题是,由于是单选,我们要注意Layout中要有RadioGroup标签包裹,实现互斥,同时我们要注意,因为是动态生成的列表item,原布局文件中只有一组Item内容显示+RadioButton,所以我们需要记录一下用户此刻点击了哪一个Item来回传它的值。
package com.tbi.app.tbishop.adapter.company;

import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioButton;
import android.widget.TextView;

import com.tbi.app.lib.core.CommonCallback;
import com.tbi.app.tbishop.R;
import com.tbi.app.tbishop.adapter.EasyRecyclerViewAdapter;
import com.tbi.app.tbishop.entity.company.CApprove;

import org.xutils.view.annotation.ContentView;
import org.xutils.view.annotation.ViewInject;
import org.xutils.x;

/**
 * 员工送审Adapter
 * Created by Kevin Shi on 17/5/16.
 */

public class CApprovePersonAdapter extends EasyRecyclerViewAdapter<CApprove> {

    private int mySelectedItem  = -1;

    private CommonCallback<CApprove> callBack;

    public CApprovePersonAdapter(CommonCallback<CApprove> callBack) {
        this.callBack = callBack;
    }

    @Override
    public RecyclerView.ViewHolder onCreate(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem_dialog_c_approval_person, parent, false);
        return new CApprovePersonAdapter.CApprovePersonHolder(view);
    }

    @Override
    public void onBind(RecyclerView.ViewHolder viewHolder, int RealPosition, CApprove data) {

    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
        CApprovePersonAdapter.CApprovePersonHolder holder = (CApprovePersonAdapter.CApprovePersonHolder) viewHolder;
        CApprove approve = getmDatas().get(position);
        holder.approveName.setText(approve.getApprovePersonName());
        holder.approveEmail.setText(approve.getApprovePersonEmail());
        // 这里使用到下面holder中提到的方法中设置的mySelectedItem值,这个值是用户选择的item对应的位置
        // 这个方法也包含绑定每一个Item要显示的值。第一次是没有任何被选中的Item的
        // 可见首先是渲染所有的Item,一旦用户选择了一个,还会回来执行这个方法,将选中的Item进行选中处理
        // 此处就正好可以写我们的回调,把值穿出去
        if (position == mySelectedItem) {
            holder.radioButton.setChecked(true);
            Log.d("CApprovePersonAdapter", approve.getApprovePersonName());
            Log.d("CApprovePersonAdapter", approve.getApprovePersonEmail());
            callBack.onCallBack(approve);
        } else {
            holder.radioButton.setChecked(false);
        }
    }

    @ContentView(R.layout.listitem_dialog_c_approval_person)
    class CApprovePersonHolder extends EasyViewHolder implements View.OnClickListener{

        @ViewInject(R.id.dialog_c_approval_person_tv_name)
        TextView approveName;

        @ViewInject(R.id.dialog_c_approval_person_tv_email)
        TextView approveEmail;

        @ViewInject(R.id.dialog_c_approval_person_radiobtn)
        RadioButton radioButton;

        // 在holder的构造函数中加入单选按钮的监听
        public CApprovePersonHolder(View itemView) {
            super(itemView);
            x.view().inject(this, itemView);
            radioButton.setOnClickListener(this);
        }

        // 这个方法是监听触发的事件,先获得选择item的位置,然后也是调用了一个RecyclerView中的方法
        // notifyItemRangeChanged,我理解就是在你穿入的item项数据范围内扫描,告诉程序去哪找你选择的Item对应的数据
        @Override
        public void onClick(View v) {
            mySelectedItem = getAdapterPosition();
            notifyItemRangeChanged(0, getmDatas().size());
        }
    }

}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="85dp"
    android:layout_centerVertical="true"
    android:background="@color/white"
    android:orientation="vertical">

    <RadioGroup
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true">

        <LinearLayout
            android:id="@+id/dialog_c_approval_person_ll"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:orientation="vertical"
            android:paddingLeft="@dimen/spacing_medium">

            <TextView
                android:id="@+id/dialog_c_approval_person_tv_name"
                style="@style/txt_main_sp16"
                android:layout_marginBottom="8dp"
                android:text="" />

            <TextView
                android:id="@+id/dialog_c_approval_person_tv_email"
                style="@style/txt_main_sp13"
                android:text="" />


            <RadioButton
                android:id="@+id/dialog_c_approval_person_radiobtn"
                style="@style/dialog_item_radiobtn"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <View
                style="@style/seg_list_line"
                android:layout_alignParentBottom="true"
                android:layout_marginLeft="@dimen/spacing_medium" />

        </LinearLayout>

    </RadioGroup>

</RelativeLayout>

我自己封装了一个EasyRecyclerViewAdapter,其实他就是继承RecyclerView.Adapter,这个网上有资源,大家可以照搬,或者就直接继承RecyclerView.Adapter也是可以的,大同小异。

虽然用了EasyRecyclerViewAdapter,但是我的主要处理方法还是用得RecyclerView的接口方法来自己实现的,这点大家要是用网上的资源就要注意了,我这点是自己写的实现。

我的主体注释已经写到相应的方法位置上了,大家可以参考,至此我实现了两次回调,所以获取选中的值以后,也有按照逆序一层一层的将值传回到主页面的Activity处理中。所以我在文章开始的时候说了“单选按钮触发相应的回调事件将值回传给调用方直至返回到目标调用方(一会详细说这个)“这句话。

OK,匆忙完成,大家有疑问可以给我留言,我会在看到的第一时间回复,谢谢大家能看到这里。