如何在偏好设置中添加图标

30
我正在制作一个扩展PreferenceActivity的应用程序,我想为每个Preference添加一个图标。
我看了一个类似的问题,并且这是获得更多声誉的答案:
CommonsWare说:设置应用程序使用一个私有自定义PreferenceScreen子类来具有图标--IconPreferenceScreen。 它有51行代码,包括评论,但还需要一些自定义属性。 最简单的选项是将所有内容克隆到您的项目中,即使您不喜欢它.
但我无法让它起作用。目前为止,我已经将IconPreferenceScreen类克隆到我的项目中。 我不知道在此之后该怎么做。我正在尝试创建一个新的IconPreferenceScreen,但无法让它工作...
    IconPreferenceScreen test = new IconPreferenceScreen();
    test.setIcon(icon);

你也可以在 GrepCode 上找到 int:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/4.4.2_r1/com/android/settings/IconPreferenceScreen.java?av=f - user3850566
9个回答

47
今天你可以只使用 API 11 可用的 android:icon 属性 :)

这是最佳解决方案,但不兼容Android 2.3,而今天它仍然拥有相当大的市场份额(超过10%)。 - Toni Alvarez
3
今天2.3版本并不重要(特别是当你的设备上没有任何图标时)。 - Vadim
10%的份额(超过1亿潜在客户)对我来说非常重要。 - Toni Alvarez
6
当你失去这个市场时,这是非常重要的。而当用户只是看不到其他的图标时,则并不重要。 - Vadim
有人知道在2.3中运行它会发生什么吗?会导致问题还是只是图标不显示?如果它悄悄地不显示图标而不会扭曲布局,那么我觉得在5-10%的设备上没有这个特性是可以接受的,毕竟在运行2.3的低端设备上,图标和位图占用内存... - AlexVPerl

19

经过多次尝试和错误,我终于做到了!

我必须执行以下步骤:

1 - 从Android本机设置应用程序中克隆IconPreferenceScreen类(感谢CommonWare)。

2 - 克隆Android设置应用程序中的布局文件preference_icon.xml。

3 - 在attrs.xml文件中声明IconPreferenceScreen样式属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="IconPreferenceScreen">
         <attr name="icon" format="reference" />
    </declare-styleable>
</resources>

4 - 在 preference.xml 文件中声明 IconPreferenceScreen:

<com.app.example.IconPreferenceScreen 
                android:title="IconPreferenceScreen Title"
                android:summary="IconPreferenceScreen Summary"
                android:key="key1" />

5 - 最后在首选项类中设置首选项的图标:

addPreferencesFromResource(R.xml.example);
IconPreferenceScreen test = (IconPreferenceScreen) findPreference("key1");
Resources res = getResources();
Drawable icon = res.getDrawable(R.drawable.icon1);
test.setIcon(icono1);

再次感谢CommonsWare告诉我从哪里开始,并对他的解释表示感谢。

这是克隆的IconPreferenceScreen类:

package com.app.example;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

public class IconPreferenceScreen extends Preference {

    private Drawable mIcon;

    public IconPreferenceScreen(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public IconPreferenceScreen(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setLayoutResource(R.layout.preference_icon);
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.IconPreferenceScreen, defStyle, 0);
        mIcon = a.getDrawable(R.styleable.IconPreferenceScreen_icon);
    }

    @Override
    public void onBindView(View view) {
        super.onBindView(view);
        ImageView imageView = (ImageView) view.findViewById(R.id.icon);
        if (imageView != null && mIcon != null) {
            imageView.setImageDrawable(mIcon);
        }
    }

    public void setIcon(Drawable icon) {
        if ((icon == null && mIcon != null) || (icon != null && !icon.equals(mIcon))) {
            mIcon = icon;
            notifyChanged();
        }
    }

    public Drawable getIcon() {
        return mIcon;
    }
}

这是克隆的 preference_icon.xml 布局:

<LinearLayout android:id="@+android:id/iconpref"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" 
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:gravity="center_vertical" 
    android:paddingRight="?android:attr/scrollbarSize">
    <ImageView android:id="@+id/icon" 
    android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:layout_marginLeft="6dip"
        android:layout_marginRight="6dip" 
        android:layout_gravity="center" />
    <RelativeLayout android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:layout_marginLeft="2dip"
        android:layout_marginRight="6dip" 
        android:layout_marginTop="6dip"
        android:layout_marginBottom="6dip" 
        android:layout_weight="1">
        <TextView android:id="@+android:id/title"
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:singleLine="true" 
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:ellipsize="marquee" 
            android:fadingEdge="horizontal" />
        <TextView android:id="@+android:id/summary"
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:layout_below="@android:id/title" 
            android:layout_alignLeft="@android:id/title"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:maxLines="2" />
    </RelativeLayout>
</LinearLayout>

为什么不使用自定义布局?http://developer.android.com/reference/android/preference/Preference.html#setWidgetLayoutResource%28int%29 - Nathan Fig
这对我不起作用。没有图标出现,当我进入偏好设置时,应用程序会崩溃。您知道如何在PreferenceScreen的标签上拥有图标吗? - Camille Sévigny
这个解决方案对我很有效。我不明白为什么你必须在首选项活动中设置图标,而IconPreferenceScreen需要花时间从attrs中提取它,但你确实需要这样做。 - Chiatar
5
你所发布的例子根本不是一个PreferenceScreen。你实际上只是向通用首选项的布局中添加了一个图像,当选择时它实际上不会执行任何操作。 - Justin Buser
这在我的ICS+上不起作用。请查看http://stackoverflow.com/questions/19786999/preference-with-icon-not-showing-in-ics - M Rajoy

11

实现你想要的最好、最简单的方法是将图标做成一个9-patch图,其中正确的边框为可伸缩区域。

假设你有一个EditTextPreference,并且想在标题和摘要前添加一个图标。

你可以创建一个MyEditTextPreference类,继承EditTextPreference并重写getView方法,将你的9-patch图作为背景资源添加进去。

以下是一个可行的示例代码:

public class MyEditTextPreference extends EditTextPreference {

    public MyEditTextPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public View getView(View convertView, ViewGroup parent) {
        View view = super.getView(convertView, parent);
        view.setBackgroundResource(R.drawable.my_icon);
        return view;
    }
}

由于这个图标是一个九宫格图标,图标将会拉伸其透明部分直到单元格的右侧,将图标放置在左侧。

这是一个非常干净简洁的解决方案。


7

虽然有点晚了,但也许对一些人有帮助。这个问题是:你只能添加分类的子元素图标,比如我的代码示例中只有编辑文本图标可以在屏幕上显示。

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
        android:title="@string/pref_profil"
        android:icon="@drawable/profile" // it wont show
        android:key="pref_key_storage_settings">

        <EditTextPreference
            android:key="edit_text_preference_1"
            android:selectAllOnFocus="true"
            android:singleLine="true"
            android:icon="@drawable/profile"
            android:title="Edit text preference" />

        <Preference
            android:key="pref_key_sms_delete_limit"
            android:summary="HELLO2"
            android:title="HELLO" />
    </PreferenceCategory>

</PreferenceScreen>

结果:

在此输入图片描述


我也注意到了这一点。所以PreferenceCategory不支持显示图标? - l33t
android:icon="@drawable/profile" 对我有用。谢谢。 - Biswajit Das

1

感谢:

以下方法对我有效:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="YOUR.PACKAGE.NAME">
    <application
        android:label="@string/app_name"
        android:icon="@drawable/icon">
        <activity
            android:name="AndroidMain"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

res/values/strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <string name="app_name">YOUR_APP_NAME</string>
    <string name="about">About</string>
</resources>

res/values/attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="IconPreference">
        <attr name="icon" format="reference" />
    </declare-styleable>
</resources>

res/layout/main.xml:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res/YOUR.PACKAGE.NAME"
    >
    <PreferenceCategory
        android:title="Main"
        android:key="mainPrefCat">
        <YOUR.PACKAGE.NAME.IconPreference
                android:title="Exit"
                android:summary="Quit the app."
                settings:icon="@drawable/YOUR_ICON"
                android:key="quitPref">
        </YOUR.PACKAGE.NAME.IconPreference>
    </PreferenceCategory>
</PreferenceScreen>

res/layout/preference_icon.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+android:id/widget_frame"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:gravity="center_vertical"
    android:paddingRight="?android:attr/scrollbarSize">
    <ImageView
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="6dip"
        android:layout_marginRight="6dip"
        android:layout_gravity="center" />
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="2dip"
        android:layout_marginRight="6dip"
        android:layout_marginTop="6dip"
        android:layout_marginBottom="6dip"
        android:layout_weight="1">
        <TextView android:id="@+android:id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal" />
        <TextView android:id="@+android:id/summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@android:id/title"
            android:layout_alignLeft="@android:id/title"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:maxLines="2" />
    </RelativeLayout>
</LinearLayout>

适当大小的图标如下:

res/drawable-hdpi/YOUR_ICON.png
res/drawable-mdpi/YOUR_ICON.png
res/drawable-ldpi/YOUR_ICON.png

AndroidMain.scala:

class AndroidMain extends PreferenceActivity {
  override def onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    addPreferencesFromResource(R.layout.main)
  }
}

IconPreference.scala:

class IconPreference(context: Context, attrs: AttributeSet, defStyle: Int) extends Preference(context, attrs, defStyle) {
    def this(context: Context, attrs: AttributeSet) = this(context, attrs, 0)

    setLayoutResource(R.layout.preference_icon);
    val a: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.IconPreference, defStyle, 0);
    val _icon: Drawable = a.getDrawable(R.styleable.IconPreference_icon);

    override def onBindView(view: View) {
        super.onBindView(view)
        val imageView: ImageView = view.findViewById(R.id.icon).asInstanceOf[ImageView]
        if (imageView != null && _icon != null) {
            imageView.setImageDrawable(_icon);
        }
    }
}

我使用的是Android 2.3.3,Scala 2.9.0.1以及来自Android SDK的标准图标(ANDROID_HOME\platforms\android-10\data\res\drawable-hdpi\ic_dialog_XXX.png)。 - W1M0R

1
我正在制作一个应用程序,其中PreferenceActivity是主要活动,我想为每个自定义首选项添加一个图标。像这张图片一样:
那不是一个PreferenceActivity。
如何在PreferenceScreen中添加图标?
对于您来说,简单点就直接创建您自己的活动即可保存首选项。
就我个人而言,我会跳过图标并使用常规的PreferenceScreen和PreferenceActivity系统。

@Tony_GPR:你知道 IconPreferenceScreen 是干什么用的吗? - CommonsWare
继承Preference类,提供添加图标的选项。我错了吗? - Toni Alvarez
3
这就是为什么我说“对你来说,创建自己的活动并偶然保存首选项会更简单。”你需要子类化想要使用的每种Preference类型并重新连接它,以便在其旁边添加图标。再次强烈建议你不要这样做。当涉及 UI 标准化时,Android 开发人员因在不应该添加图标的地方添加图标等操作而声名狼藉。用户和媒体成员抱怨说,与 iOS 不同,没有两个 Android 应用程序看起来和工作方式相同。请不要改动首选项。 - CommonsWare
@CommonsWare: “当涉及UI标准化时,Android开发人员有一个被认为是白痴的声誉”- 这相当严厉,伙计。但是为了辩护你,将图标添加到首选项屏幕除了装饰之外什么也不做 - 执行的部分是首选项选项的“文本”部分。 - ChuongPham
这在ICS+上对我来说不起作用。请查看http://stackoverflow.com/questions/19786999/preference-with-icon-not-showing-in-ics - M Rajoy
显示剩余3条评论

0

为了得到一个“合理”的答案,你可以使用Henrique Rocha所描述的9-patch方法,或者你可以使用以下方法:

创建一个新的Preference类,继承EditTextPreference并让它覆盖onCreateView方法。

@Override
protected View onCreateView(ViewGroup parent)
{
    View v = LayoutInflater.from(getContext()).inflate(R.layout.iconpreference, null);

    return v;
}

创建一个名为iconpreference的新布局XML,在此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:orientation="horizontal" >

    <ImageView android:layout_width="48dp"
        android:layout_height="48dp"
        android:src="@drawable/checkmark_black"/>

    <include layout="@layout/preference_holo" />

</LinearLayout>

就是这样!


0

-1

试试这个:

PreferenceScreen root = getPreferenceManager().createPreferenceScreen(this);
PreferenceScreen ps= getPreferenceManager().createPreferenceScreen(this);
ps.setKey("ps");
ps.setLayoutResource(R.layout.your_layout);
root.addPreference(ps);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接