渡劫篇:设置界面的开发利器Preference Library,触摸事件浅析走起~

531 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

接下来会对Preference Library官方库进行一个系列讲解,本篇文章是Preference Library系列的第八篇,主要是介绍Preference Library的触摸事件分发机制。

历史文章

练气篇:设置界面的开发利器Preference Library,了解一下~

筑基篇:设置界面的开发利器Preference Library,了解一下~

金丹篇:设置界面的开发利器Preference Library,了解一下~

元婴篇:设置界面的开发利器Preference Library,了解一下~

化神篇:设置界面的开发利器Preference Library,了解一下~

炼虚篇:设置界面的开发利器Preference Library,了解一下~

合体篇:设置界面的开发利器Preference Library,源码浅析一下

Preference的触摸事件是如何执行的?

上一篇文章合体篇:设置界面的开发利器Preference Library,源码浅析一下 有讲过,Preference Library就是基于RecyclerView实现的多布局列表,所以Preference的点击事件的设置应该就是在PreferenceGroupAdapter中,最终定位到onBindViewHolder()方法:

@Override
public void onBindViewHolder(@NonNull PreferenceViewHolder holder, int position) {
    final Preference preference = getItem(position);
    holder.resetState();
    preference.onBindViewHolder(holder);
}

紧接着分发到了PreferenceonBindViewHolder()方法:

public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
    View itemView = holder.itemView;

    itemView.setOnClickListener(mClickListener);
    //...
}

很清晰的看到,Preference设置项的点击事件就在这里设置的,即itemView.setOnClickListener(),我们看下mClickListener这个对象:

private final View.OnClickListener mClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        performClick(v);
    }
};

一直往下走,最终调用到了performClick()方法:

public void performClick() {
    //1.
    if (!isEnabled() || !isSelectable()) {
        return;
    }
    //2.
    onClick();
    //3.
    if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) {
        return;
    }

    PreferenceManager preferenceManager = getPreferenceManager();
    //4.
    if (preferenceManager != null) {
        PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager
                .getOnPreferenceTreeClickListener();
        if (listener != null && listener.onPreferenceTreeClick(this)) {
            return;
        }
    }
    //5.
    if (mIntent != null) {
        Context context = getContext();
        context.startActivity(mIntent);
    }
}

上面核心有五点,接下来一步步进行分析:

1. 判断能否触发点击

public boolean isEnabled() {
    return mEnabled && mDependencyMet && mParentDependencyMet;
}

public boolean isSelectable() {
    return mSelectable;
}

核心的两个属性mEnabledmSelectable可以在xml中进行配置,是否允许该设置项点击 :

<SwitchPreferenceCompat
    app:enabled="false"
    app:selectable="false"/>

或者可以通过setEnabled()/setSelectable()在代码中动态设置。

2. onClick()第一个响应点击事件

protected void onClick() {}

Preference的子类可以选择性重写该方法,比如SwitchPreferenceCompat的父类TwoStatePreference就重写了该方法,实现了右边的按钮切换刷新:

protected void onClick() {
    super.onClick();

    final boolean newValue = !isChecked();
    if (callChangeListener(newValue)) {
        setChecked(newValue);
    }
}

最终调用setChecked()方法通知RecyclerView的适配器调用notifyItemChanged()单刷该设置项,非常的优雅。

3. OnPreferenceClickListener.onPreferenceClick()第二个响应点击事件

这个对象我们可以通过外部调用setOnPreferenceClickListener()进行传入,来响应这个点击事件:

public void setOnPreferenceClickListener(
        @Nullable OnPreferenceClickListener onPreferenceClickListener) {
    mOnClickListener = onPreferenceClickListener;
}

如果重写的这个对象的onPreferenceClick()方法返回true,就结束点击事件分发了,下面的逻辑都不会走了。

这个监听器是单独为某个Preference设置的,私有的,不被其他的Preference共享。

4. PreferenceManager.OnPreferenceTreeClickListener第三个响应点击事件

这个对象也可以通过外部进行传入,调用PreferenceManager.setOnPreferenceTreeClickListener()就行:

public void setOnPreferenceTreeClickListener(
        @Nullable OnPreferenceTreeClickListener listener) {
    mOnPreferenceTreeClickListener = listener;
}

和上面一样,如果这个对象的setOnPreferenceTreeClickListener()返回true,就结束点击事件分发了,下面的逻辑都不会走了。

这个监听器是设置项之间共享的,因为它被PreferenceManager持有,而PreferenceManager又是全局的对象。

5. Intent第四个响应点击事件

这个Intent就是之前我们在讲的在xml配置的跳转intent:

<Preference
    app:persistent="false"
    app:icon="@drawable/ic_launcher_foreground"
    app:key="develop"
    app:title="开发者选项">

    <intent
        android:targetClass="com.example.m3demo.DevelopActivity"
        android:targetPackage="com.example.m3demo" />
</Preference>

当然了这个intent也支持代码动态设置,不过从上面就可以看出,这个intent响应点击事件的优先级比较低,得前面的两个监听器都不拦截才能得到执行的机会。

总结

本篇文章主要讲解了Preference点击事件是如何分发实现的,以及响应点击事件对象之间的优先级,哪个先响应,哪个优先级最低,希望本篇文章能对你有所帮助。