【问题标题】:Android ListView with RadioButton/CheckBox in singleChoice mode and a custom row layout单选模式下带有 RadioButton/CheckBox 和自定义行布局的 Android ListView
【发布时间】:2011-06-18 01:26:28
【问题描述】:

我有一个 ListView,它处于 singleChoice 模式。我想要的只是在侧面显示一个 RadioButton,当单击它时会突出显示它被选中,当单击另一个按钮时,它会隐藏并选择新的按钮。

我查看了 Mark 的书,第 8 章,“开始喜欢列表”和他的 RateList 示例
但这并不能解决我的问题。 请帮帮我。

【问题讨论】:

  • 嗨,你知道怎么做吗?

标签: android listview radio-button listviewitem


【解决方案1】:

编辑

值得一提的是,我的列表项有一个自定义布局:有一个图标、一个标题、一个描述,然后是复选框或单选按钮(取决于它是单选还是多选列表)。我的示例解决方案是,因此由不少于三个不同的部分描述:

  1. 自定义列表项
  2. 甜蜜的爱情:CheckableLinearLayout 实现
  3. ListView 配置示例

  4. 还有一个好处:

  5. Adapter::getView() 实施示例。

那么让我们来看看魔法吧?

listitem.xml

<com.dbm.CheckableLinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:id="@+id/myIcon" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAppearance="@android:style/TextAppearance.Medium"
            android:textStyle="bold"
            android:ellipsize="end"
            android:id="@+id/myTitle" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAppearance="@android:style/TextAppearance.Small"
            android:textStyle="italic"
            android:ellipsize="end"
            android:id="@+id/myDescr" />
    </LinearLayout>

    <CheckedTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@android:id/text1" />

</com.dbm.CheckableLinearLayout>

CheckableLinearLayout.java

public class CheckableLinearLayout extends LinearLayout implements Checkable {

    private CheckedTextView mCheckedTextView;
    private final Drawable mCheckDrawable;
    private final Drawable mRadioDrawable;
    private boolean mIsChecked;


       /**
        * Constructor.
        *
        * @param context The context to operate in.
        * @param attrs The attributes defined in XML for this element.
        */
    public CheckableLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray typedArray = null;

        // Cache the check box drawable.
        typedArray = context.getTheme().obtainStyledAttributes(new int[] {android.R.attr.listChoiceIndicatorMultiple});

        if ((typedArray != null) && (typedArray.length() > 0)) {
            mCheckDrawable = typedArray.getDrawable(0);
        }
        else {
            // Fallback if the target theme doesn't define a check box drawable.
            // Perhaps an application specific drawable should be used instead of null.
            mCheckDrawable = null;
        }

        // Careful with resources like this, we don't need any memory leaks.
        typedArray.recycle();

        // Cache the radio button drawable.
        typedArray = context.getTheme().obtainStyledAttributes(new int[] {android.R.attr.listChoiceIndicatorSingle});

        if ((typedArray != null) && (typedArray.length() > 0)) {
            mRadioDrawable = typedArray.getDrawable(0);
        }
        else {
            // Fallback if the target theme doesn't define a radio button drawable.
            // Perhaps an application specific drawable should be used instead of null
            mRadioDrawable = null;
        }

        // Careful with resources like this, we don't need any memory leaks.
        typedArray.recycle();

        mIsChecked = false;
    }


    /*
     * (non-Javadoc)
     * @see android.widget.Checkable#isChecked()
     */
    public boolean isChecked() {
        return mIsChecked;
    }


    /*
     * (non-Javadoc)
     * @see android.view.View#onAttachedToWindow()
     */
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        // Check if there is a valid GUI element that can visualize the current check-state.
        if (mCheckedTextView != null) {
            ViewParent p = getParent();

            // Check if the parent of this list item is a ListView
            if (p instanceof ListView) {
                int choiceMode = ((ListView) p).getChoiceMode();

                // Decide which check-state notation to visualize (check box, radio button or none).
                switch (choiceMode) {
                    case ListView.CHOICE_MODE_MULTIPLE:
                        mCheckedTextView.setCheckMarkDrawable(mCheckDrawable);
                        break;

                    case ListView.CHOICE_MODE_SINGLE:
                        mCheckedTextView.setCheckMarkDrawable(mRadioDrawable);
                        break;

                    default:
                        mCheckedTextView.setCheckMarkDrawable(null);
                        break;
                }
            }
        }
    }


    /*
     * (non-Javadoc)
     * @see android.view.View#onFinishInflate()
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mCheckedTextView = (CheckedTextView) findViewById(android.R.id.text1);
    }


    /*
     * (non-Javadoc)
     * @see android.widget.Checkable#setChecked(boolean)
     */
    public void setChecked(boolean checked) {
        mIsChecked = checked;

        if (mCheckedTextView != null) {
            mCheckedTextView.setChecked(mIsChecked);
        }
    }


    /*
     * (non-Javadoc)
     * @see android.widget.Checkable#toggle()
     */
    public void toggle() {
        setChecked(!mIsChecked);
    }

}

exampleListView.xml

注意!如果您将android:choiceMode 属性设置为"multipleChoice",您将自动获得复选框,如果您将其设置为"singleChoice",您将自动获得单选按钮,前提是您使用上述实现。

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

    <ListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:choiceMode="singleChoice"
        android:id="@+id/myList" />

</LinearLayout>

奖励:MyCustomAdapter::getView()

这个依赖于光标。当然,您可以根据自己的需要实施它。

private final class ViewHolder {
    public ImageView iconView;
    public TextView titleView;
    public TextView descriptionView;
}


/*
 * (non-Javadoc)
 * @see android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup)
 */
public View getView(int position, View convertView, ViewGroup parent) {
    View view = null;

    // Only do something if the requested position exists within the Cursor.
    if (mCursor.moveToPosition(position)) {
        ViewHolder viewHolder;
        view = convertView;

        if (view == null) {
            // Create and initialize a new view if not created already for this position.
            view = mLayoutInflater.inflate(R.layout.listitem, null);

            // Don't "find view by id" each and every time, but rather save a reference
            // to them and associate the references with the list item itself by storing 
            // them in the list items "tag" attribute. When the view is re-used later on, 
            // you already have a reference to its views and don't need to find them 
            // again, which is a time-consuming operation.
            viewHolder = new ViewHolder();
            viewHolder.iconView = (ImageView) view.findViewById(R.id.myIcon);
            viewHolder.titleView = (TextView) view.findViewById(R.id.myTitle);
            viewHolder.descriptionView = (TextView) view.findViewById(R.id.myDescr);

            view.setTag(viewHolder);
        }
        else {
            // Get the references to the views for this, already existing list item.
            viewHolder = (ViewHolder) view.getTag();
        }

        // Create a bitmap from the byte array in the database.
        byte[] buffer = mCursor.getBlob(mIconColumnIndex);
        Bitmap icon = null;

        // Try to decode the byte array if it exists.
        if (buffer != null) {
            icon = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
        }

        // Update the views with new data.
        viewHolder.iconView.setImageBitmap(icon);

        String title = mCursor.getString(mTitleColumnIndex);
        viewHolder.titleView.setText(title);

        String description = mCursor.getString(mDescriptionColumnIndex);
        viewHolder.descriptionView.setText(description);
    }

    // Return a view showing the correct data for the item at 'position'.
    return view;
}

原始答案:

我可以推荐这个链接:

http://tokudu.com/2010/android-checkable-linear-layout/

当我处于您的确切位置时,我本人对此感到非常高兴 :-) 如果仍有任何不清楚的地方,请随时指定您的问题,我很乐意帮助或协助提供更多代码示例(就像前面提到过:我几天前才担任您的职位)。

【讨论】:

  • 非常感谢。我阅读了tokudu.com/2010/android-checkable-linear-layout链接,但现在我的浏览器无法打开它。但我理解它有些困难,无法解决我的问题,如果你能,请写在这里更详细
  • 注意:该链接无法在我的浏览器中打开。提前致谢
  • 亲爱的 dbm 我等待您的答复。请帮忙。
  • 耐心我亲爱的朋友!我有一份全职工作,一个妻子和两个孩子,他们的优先级都比这个社区高,除此之外,我怀疑我们坐在截然不同的时区:-) 但是,我已经修改了上面的答案。如果有不清楚的地方请告诉我:-)
  • 我读了你上面的代码,很困惑。你在哪里创建你的raidobuttons,你的单选组对象在哪里?
【解决方案2】:

我使用了dbm's answer,它对我来说很好,除了一件事:

您应该在onAttachedToWindow() 方法中启动CheckedTextView,而不是在onFinishInflate(). 这是因为onAttachedToWindow() 调用了之前 onFinishInflate() 并且使用上面的解决方案您将永远看不到任何可绘制对象CheckedTextView——调用onAttachedToWindow()时为空。

【讨论】:

  • 谢谢Darkmine,我改变了初始化,但我又遇到了第一行和最后一行没有显示选项按钮的问题!点击监听器,......一切正常,除了在这两行中显示那些单选按钮。您能提出任何解决方案吗?
猜你喜欢
  • 2011-05-14
  • 2014-05-03
  • 2012-08-13
  • 1970-01-01
  • 1970-01-01
  • 2016-09-06
  • 1970-01-01
  • 1970-01-01
  • 2012-07-02
相关资源
最近更新 更多