Android ListDialog 通过反射修改单选dialog的布局

本文介绍了如何通过源码分析和反射技术修改Android原生DialogSingleChoice的布局,以去掉右侧的RadioButton。展示了从查找源码到实现目标效果的完整过程,并提供了相关代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

朋友让帮忙实现一个单选的ListDialog,原生的DialogSingleChoice很符合要求,但是不需要右边的RadioButton,于是就研究了一下DialogSingleChoice,之后通过源码找到了修改DialogSingleChoice布局的方法。经测试2.3.3    4.1   4.4.2系统版本下都是同样的效果。

首页看一下效果,默认SingleChoiceDialog样式

通过代码反射字段修改后的样式

接下来上代码,首先来点初始化数据

	private String[] items;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		items= new String[] { "小张", "小杉", "小艳", "小马","小钟" };
		showDialog();
	}

接下来上通过反射修改dialog样式的部分

	public void showDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setSingleChoiceItems(items, 0,
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
						Toast.makeText(MainActivity.this, items[which], 0)
								.show();
					}
				});
		builder.setCancelable(false);
		try {
			//得到AlertDialog私有变量P
			Field fieldP = builder.getClass().getDeclaredField("P");
			//设置私有变量P为可以访问
			fieldP.setAccessible(true);
			//得到P的对象
			Object p = fieldP.get(builder);
			//得到P中的mIsSingleChoice字段
			Field declaredField = p.getClass().getDeclaredField(
					"mIsSingleChoice");
			declaredField.setAccessible(true);
			//将P身上的mIsSingleChoice字段设置为false
			declaredField.set(p, false);
		} catch (Exception e) {
			e.printStackTrace();
		}
		builder.create().show();
	}

注释写得很详细我就不赘述了。

接下来说说我是如何找源码的。

首先进入到dialog的setSingleChoiceItems源码中,我们注意到有一个变量P.mIsSingleChoice = true,这个P变量记录了dialog是一个单选dialog,接着我们去找找AlertController.AlertParams P的源码,eclipse不能直接跳入,直接用工具把这个类搜出来。

        private final AlertController.AlertParams P;    
        public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener) {
            P.mItems = items;
            P.mOnClickListener = listener;
            P.mCheckedItem = checkedItem;
            P.mIsSingleChoice = true;
            return this;
        }

打开AlertController.AlertParams直接搜索mIsSingleChoice在哪里用到了,搜到如下代码

                int layout = mIsSingleChoice 
                        ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout;

在找到定义这两个资源ID的代码

        mSingleChoiceItemLayout = a.getResourceId(
                com.android.internal.R.styleable.AlertDialog_singleChoiceItemLayout,
                com.android.internal.R.layout.select_dialog_singlechoice);
        mListItemLayout = a.getResourceId(
                com.android.internal.R.styleable.AlertDialog_listItemLayout,
                com.android.internal.R.layout.select_dialog_item);

首先看一下默认mIsSingleChoicetrue为true的布局select_dialog_singlechoice,这是一个带有CheckBox的自定义TextView

<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:textColor="@android:color/primary_text_light_disable_only"
    android:gravity="center_vertical"    android:paddingLeft="12dip"
    android:paddingRight="7dip"
    android:checkMark="@android:drawable/btn_radio"
    android:ellipsize="marquee"/>


mIsSingleChoice为false的布局select_dialog_singlechoice,就是一个TextView

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:textColor="?android:attr/textColorAlertDialogListItem"
    android:gravity="center_vertical"
    android:paddingLeft="16dip"
    android:paddingRight="16dip"
    android:ellipsize="marquee"
/>

源代码看完了,然后就是通过开头反射那部分代码,去修改mIsSingleChoice属性为false,从而让dialog item去加载textview的这个布局,达到我们想要的效果。


才发现,其实使用builder.setItems(items, listener)方法就可以达到上述效果,不记得这个API了,- =不过也可以作为查看源码和反射的学习。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值