如何为此按钮设置点击监听器
How to set click listener to this Button
我无法让它工作我希望在这个 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>
由于您的 Fragment
是从 PreferenceFragmentCompat
扩展而来的,因此您不应尝试设置 View.OnClickListener
,而应改写 PreferenceFragmentCompat.onPreferenceTreeClick()
。根据documentation,这个方法是...
Called when a preference in the tree rooted at this PreferenceScreen has been clicked.
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 库中)因为替换了 CheckBox
小部件使用您的自定义 Button
只需要设置 android:widgetLayout
属性,就像您在代码片段中所做的那样:
<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();
}
});
}
}
}
正如@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"/>
见最后一行。这样你就不需要为按钮创建额外的 class 并且你可以轻松访问你在 PreferencesFragment
class.
中的任何方法和变量
我确信有更好的方法可以通过单击按钮以某种方式触发首选项单击,但至少这很有效。
我一直在寻找一个简单的答案并找到了一种方法。只需在 xml
文件中为按钮设置 onClick
属性,并在首选项片段的父级 activity 中实现该方法。 (在 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>
然后我在首选项片段的父 activity 中实现了 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 首选项中使用按钮的人有所帮助。
我无法让它工作我希望在这个 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>
由于您的 Fragment
是从 PreferenceFragmentCompat
扩展而来的,因此您不应尝试设置 View.OnClickListener
,而应改写 PreferenceFragmentCompat.onPreferenceTreeClick()
。根据documentation,这个方法是...
Called when a preference in the tree rooted at this PreferenceScreen has been clicked.
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 库中)因为替换了 CheckBox
小部件使用您的自定义 Button
只需要设置 android:widgetLayout
属性,就像您在代码片段中所做的那样:
<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();
}
});
}
}
}
正如@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"/>
见最后一行。这样你就不需要为按钮创建额外的 class 并且你可以轻松访问你在 PreferencesFragment
class.
我确信有更好的方法可以通过单击按钮以某种方式触发首选项单击,但至少这很有效。
我一直在寻找一个简单的答案并找到了一种方法。只需在 xml
文件中为按钮设置 onClick
属性,并在首选项片段的父级 activity 中实现该方法。 (在 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>
然后我在首选项片段的父 activity 中实现了 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 首选项中使用按钮的人有所帮助。