nsiderTalon
nsiderTalon

Reputation: 51

Custom preference broken in Honeycomb/ICS

I'm using a custom preference that I use the title, summary, and an icon in. The pref is used to select an item (skin, app, etc.), then the it will summarize the current choice. Here's the preference working correctly (top) and my issue on Honeycomb/ICS:

http://imgur.com/vKPOu

http://imgur.com/EiMBr

Space is being made for the preference, but even the default title/summary aren't showing up, and the intent for item selection isn't firing off either. Here's the preference layout:

<?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="fill_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:gravity="center_vertical"
    android:paddingRight="?android:attr/scrollbarSize">
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dip"
        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>
   <ImageView
       android:id="@+id/icon"
       android:layout_width="48dp"
       android:layout_height="48dp"
       android:layout_gravity="center" />
</LinearLayout> 

And the custom preference itself:

import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

public class SelectedAppPreference extends Preference {
    private Drawable mIcon;

    public SelectedAppPreference(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        final PackageManager pm = context.getPackageManager();
        String packageName = context.getSharedPreferences("appPrefs", Context.MODE_PRIVATE).getString("selected_app_package", null);

        this.setLayoutResource(R.layout.icon_pref);
        try {
            this.mIcon = pm.getApplicationIcon(packageName);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
    }

    public SelectedAppPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        final PackageManager pm = context.getPackageManager();
        String packageName = context.getSharedPreferences("appPrefs", Context.MODE_PRIVATE).getString("selected_app_package", null);

        this.setLayoutResource(R.layout.icon_pref);
        try {
            this.mIcon = pm.getApplicationIcon(packageName);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onBindView(final View view) {
        super.onBindView(view);

        final ImageView imageView = (ImageView)view.findViewById(R.id.icon);
        if ((imageView != null) && (this.mIcon != null)) {
            imageView.setImageDrawable(this.mIcon);
        }
    }

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

    public Drawable getIcon() {
        return this.mIcon;
    }
}

Nothing too exciting in the preference itself. I have a feeling that the issue is in the preference layout xml, but I'm not sure what exactly is not working correctly. I can confirm that the preference works fine on Android 2.1, 2.2, and 2.3 devices, and I've had issues on 3.2 and 4.0. Any suggestions?

Upvotes: 4

Views: 2370

Answers (2)

user1076637
user1076637

Reputation: 768

The third party custom preference I fixed is taken from this site

https://github.com/attenzione/android-ColorPickerPreference/tree/master/src/net/margaritov/preference/colorpicker

My code (in ColorPickerPreference.setPreviewColor()) looks like

widgetFrameView.setVisibility(View.VISIBLE);
final boolean preApi14 = android.os.Build.VERSION.SDK_INT < 14;
final int rightPaddingDip = preApi14 ? 8 : 5;

widgetFrameView.setPadding(
                      widgetFrameView.getPaddingLeft(),
                      widgetFrameView.getPaddingTop(),
                      (int)(mDensity * rightPaddingDip),
                      widgetFrameView.getPaddingBottom()
                );

where

float mDensity = getContext().getResources().getDisplayMetrics().density;

This is with minSdkVersion = 8 and no targetSdkVersion. If you set targetSdkVersion to 14 or more you may need to change the '5' to something else until the custom preference element on the right aligns nicely with the standard ones (e.g. check boxes).

Upvotes: 2

user1076637
user1076637

Reputation: 768

I had similar problem with a third party custom preference and fixed it by making the widget frame visible. It was invisible by default in ICS. Dont' know how it maps to your custom preference.

// This line was in the original code.
LinearLayout widgetFrameView = ((LinearLayout) mView
                    .findViewById(android.R.id.widget_frame));
...
// This line fixed the visibility issue
widgetFrameView.setVisibility(View.VISIBLE);

Also had to realign the view to make it consistent with the rest of ICS controls.

Upvotes: 6

Related Questions