【问题标题】:How to set click listener to this Button如何为此按钮设置点击监听器
【发布时间】:2018-11-05 17:31:36
【问题描述】:

我无法让它工作我希望在这个preferences 屏幕上注销Button 有一个ClickListener

看起来是这样的:

这是代码,buttonView 始终为 NULL:

class PreferencesFragment : PreferenceFragmentCompat() {

    lateinit var activity: Context

    private var prefs: SharedPreferences = BleApplication.getInstance().getDefaultSharedPreferences()

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        activity = requireActivity()
    }


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val buttonView = view.findViewById<View>(R.id.btn_sign_out)

        if (buttonView != null) {
            buttonView.setOnClickListener {
                Toast.makeText(getActivity(), "You clicked me.", Toast.LENGTH_SHORT).show()
            }
        }
        // Hide the divider
/*        setDivider(ColorDrawable(Color.TRANSPARENT))
        setDividerHeight(0)*/
    }

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        addPreferencesFromResource(R.xml.app_prefs)
    }
}

我也尝试了 kotlinx.android.synthetic 但同样的问题

这是xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory
        android:layout="@layout/pref_category_text"
        android:title="@string/pref_category_remote_battery_title">

        <SwitchPreferenceCompat
            android:key="@string/pref_key_category_remote_battery_switch"
            android:title="@string/pref_category_remote_battery_switch_title"
            android:summary="@string/pref_category_remote_battery_switch_summ"/>

    </PreferenceCategory>

    <PreferenceCategory
        android:layout="@layout/pref_category_text"
        android:title="@string/pref_category_sign_out_title">

        <Preference
            android:key="@string/pref_key_category_signed_out"
            android:widgetLayout="@layout/pref_category_sign_out_button"
            android:title="@string/pref_category_sign_out_button_title"
            android:summary="@string/pref_category_sign_out_buttom_summ"/>

    </PreferenceCategory>

</PreferenceScreen>

这是"@layout/pref_category_sign_out_button" 布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_sign_out"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/buttonshape"
        android:text="@string/pref_category_sign_out_title" />
</LinearLayout>

【问题讨论】:

    标签: android kotlin preferencefragment clicklistener


    【解决方案1】:

    由于您的Fragment 是从PreferenceFragmentCompat 扩展而来的,因此您不应尝试设置View.OnClickListener,而应覆盖PreferenceFragmentCompat.onPreferenceTreeClick()。根据documentation,这个方法是...

    当单击以此 PreferenceScreen 为根的树中的首选项时调用。

    Java 代码示例:

    @Override
    onPreferenceTreeClick(Preference preference){
        if(preference.getKey().equals(getContext().getString(R.string.pref_key_category_signed_out))){
           // user clicked signout "button"
           // take appropriate actions
           // return "true" to indicate you handled the click
           return true;
        }
        return false;
    }
    

    Kotlin 中的代码示例(我希望我可以信任 Android Studio :P)

    override fun onPreferenceTreeClick(preferenceScreen: PreferenceScreen, preference: Preference): Boolean {
        return if (preference.key == context.getString(R.string.pref_key_category_signed_out)) {
            // user clicked signout "button"
            // take appropriate actions
            // return "true" to indicate you handled the click
            true
        } else false
    }
    

    这将使您能够捕获Preference 的点击事件,但不能捕获Button 的点击事件。

    为了做到这一点,可以使用自定义Preference 并覆盖onBindViewHolder(PreferenceViewHolder)。由于PreferenceViewHolder - 类似于RecyclerView.ViewHolder - 有一个字段itemView 包含膨胀的布局,这里是设置我们自己的View.OnClickListener 的好机会。

    SignOutPreference 扩展自 TwoStatePreference(在 com.android.support:preference-v7 库中),因为用您的自定义 Button 替换 CheckBox 小部件只需要设置android:widgetLayout 属性,就像您在代码 sn-p 中所做的一样:

    <PreferenceCategory
        android:layout="@layout/pref_category_text"
        android:title="@string/pref_category_sign_out_title">
    
        <your.package.name.SignOutPreference
            android:key="@string/pref_key_category_signed_out"
            android:widgetLayout="@layout/pref_category_sign_out_button"
            android:title="@string/pref_category_sign_out_button_title"
            android:summary="@string/pref_category_sign_out_buttom_summ"/>
    
    </PreferenceCategory>
    

    SignOutPreference.java

    public class SignOutPreference extends TwoStatePreference {
        public SignOutPreference(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public SignOutPreference(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public SignOutPreference(Context context) {
            super(context);
        }
    
        @Override
        public void onBindViewHolder(final PreferenceViewHolder holder) {
            super.onBindViewHolder(holder);
            Button button = holder.itemView.findViewById(R.id.btn_sign_out);
            if(button != null){
                button.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(holder.itemView.getContext(), "CLICKED!", Toast.LENGTH_SHORT).show();
                    }
                });
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      正如@0X0nosugar 提到的,您可以使用onPreferenceTreeClicked 方法以方便的方式处理所有点击:

      @Override
      onPreferenceTreeClick(Preference preference){
          if ((preference.getKey().equals(getContext().getString(R.string.pref_key_category_signed_out))){
             // user clicked signout "button"
             // take appropriate actions
             // return "true" to indicate you handled the click
             return true;
          }
          return false;
      }
      

      通过widgetLayout 使用自定义按钮时的问题是,当按钮单击不是首选项单击时,处理程序不会捕获它。解决此问题的一种方法是禁用按钮的内置点击,如下所示:

      <Button
          android:id="@+id/btn_sign_out"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:background="@drawable/buttonshape"
          android:text="@string/pref_category_sign_out_title"
          android:clickable="false"/>
      

      见最后一行。这样,您无需为按钮创建额外的类,您可以轻松访问 PreferencesFragment 类中的任何方法和变量。

      我确信有一种更好的方法可以从按钮点击中触发偏好点击,但至少这效果很好。

      【讨论】:

        【解决方案3】:

        我一直在寻找一个简单的答案并找到了一种方法。只需在xml文件中为按钮设置onClick属性,并在偏好片段的父活动中实现该方法。 (重要的是在 Activity 中实现它,而不是在 Preference Fragment 中实现它。否则它会给你带来崩溃)
        我想让我的 onClick 方法仅在按钮被触摸(单击)时起作用,而不是响应按钮外部区域的单击。到目前为止,这是唯一能像我想要的那样工作的方法。

        我的代码是在 Kotlin 中的,但是逻辑很简单,所以用 java 写起来并不难。

        这是我的button.xml,用于首选项的widgetLayout。看看我是怎么设置android:onClick=属性的。

        <?xml version="1.0" encoding="utf-8"?>
        <Button
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/btn"
            android:text="reset"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="@style/rippleEffect" //my custom ripple effect
            android:onClick="onClickMethod">
        </Button>
        

        然后我在偏好片段的父活动中实现了onClickMethod。这个回调方法应该是public,并有View作为输入参数。
        (有关更多信息,请阅读 -> How exactly does the android:onClick XML attribute differ from setOnClickListener?

        fun onClickMethod(view: View) {
            //do something
        }
        

        下面是我的preference.xml

        <Preference
            android:key="pref_key"
            android:title="Reset"
            android:summary="summary.."
            app:iconSpaceReserved="false"
            android:widgetLayout="@layout/button"/>
        

        我还尝试以编程方式设置ClickListener,但唯一没有错误的方法是在PreferenceClickListener 中设置按钮的ClickListener。这只工作了一半,因为我需要先触摸(单击)首选项来初始化按钮的ClickListener

        val view = findPreference<androidx.preference.Preference>("pref_key")
        var isFirst = true
        view?.setOnPreferenceClickListener {
            if (isFirst) {
                btn.setOnClickListener {
                    Toast.makeText(requireContext(), "button clicked!", Toast.LENGTH_SHORT).show()
                }
                isFirst = false
                it.summary = "unlocked"
            } else {
                isFirst = true
                it.summary = "locked - tap to unlock"
            }
            true
        }
        



        无论如何,这个答案对我来说效果很好,但我仍在寻找一种使用我的偏好键的方法,因为这种方法没有完全使用偏好属性,而只是作为一种布局。但现在我希望这对那些想要在 android 偏好中使用按钮的人有所帮助。

        【讨论】:

          猜你喜欢
          • 2020-08-17
          • 2020-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-30
          • 1970-01-01
          • 2022-08-15
          相关资源
          最近更新 更多