Alin
Alin

Reputation: 1044

Custom Preference - Button not clickable

I'm working on a settings screen and I'm using Android's Preference API to build the interface. One of the preference will be a button - and I've done it by adding a custom layout to the preference. It works - the button is displayed as I want it but the problem is that when setting OnPreferenceClickListener nothing happens. It's not triggered.

I've tried adding beforeDescendants on the button layout root but no luck. Also tried to add focusable false to the button but still no luck.

Can anyone please share some tips on how I can make the preference button respond? Thanks!

Upvotes: 2

Views: 1296

Answers (4)

Krahmal
Krahmal

Reputation: 325

Similar to @Emanuel Moecklin 's answer, in 2022 androidx Preference you can use:

class FooterPreference(context: Context, attrs: AttributeSet): Preference(context, attrs) {

    override fun onBindViewHolder(holder: PreferenceViewHolder?) {
        super.onBindViewHolder(holder)
        holder?.itemView?.findViewById<Button>(R.id.btn)?.setOnClickListener {
            Timber.d("button clicked")
        }
    }
}
<packageName.FooterPreference
        app:layout="@layout/layout_preference_footer" />

Upvotes: 0

Al&#233;cio Carvalho
Al&#233;cio Carvalho

Reputation: 13657

Override the 'onClick()' from Preference method and make sure your custom layout does NOT have:

 android:clickable="true"

You don't need anything else special, but if your layout contains a view with android:clickable="true" it messes it up completely.

Upvotes: 0

Emanuel Moecklin
Emanuel Moecklin

Reputation: 28856

onPreferenceClick is triggered when the Prefererence has been clicked not when you click the button. If you want to catch the button click you need to set a OnClickListener on the button itself. The problem is to retrieve the inflated button since the Preference class doesn't have a findViewById method or anything similar. Here's how I'd do it:

  1. Create a custom Preference class and override the onCreateView
  2. In the onCreateView method you grab the inflated layout from the super class and find the Button
  3. Add an OnClickListener to the button
  4. Use your custom Preference class in your preference layout file

public class CustomPreference extends Preference  {

    public CustomPreference(Context context) {
        super(context);
    }

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

    public CustomPreference(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected View onCreateView(ViewGroup parent) {
        View preferenceView = super.onCreateView(parent);

        setOnClickListener(preferenceView);

        return preferenceView;
    }

    private void setOnClickListener(View preferenceView) {
        if (preferenceView != null && preferenceView instanceof ViewGroup) {
            ViewGroup widgetFrameView = ((ViewGroup)preferenceView.findViewById(android.R.id.widget_frame));
            if (widgetFrameView != null) {
                // find the button
                Button theButton = null;
                int count = widgetFrameView.getChildCount();
                for (int i = 0; i < count; i++) {
                    View view = widgetFrameView.getChildAt(i);
                    if (view instanceof Button) {
                        theButton = (Button)view;
                        break;
                    }
                }

                if (theButton != null) {
                    // set the OnClickListener
                    theButton.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            // do whatever you want to do
                        }
                    });
                }
            }
        }
    }
}

This replaces the Preference in your xml file:

<yourpackage.CustomPreference
    android:key="your_id"
    android:title="@string/your_title"
    android:summary="@string/your_summary"/>

Upvotes: 4

Michele La Ferla
Michele La Ferla

Reputation: 6884

I would use something similar to the code below to implement this:

@Override
protected View onCreateView (ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater)   getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View customRow = inflater.inflate(R.layout.preferences_station_list_row, null);
    ((ImageButton) customRow.findViewById(R.id.pref_delete_station)).setOnClickListener(new OnClickListener() {      
        @Override
        public void onClick(View v) {
           //perform whatever you need to button to do here.
        }
    });

    customRow.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            showDialog(null);
        }
    });
    customRow.setClickable(true);
    return customRow;
}

Has this solved your issue?

Upvotes: 1

Related Questions