自定义SwitchPreference实现其中Switch控件的enabled属性的解绑

       最近项目遇到一个需求,就是将SwitchPreference调用setEnabled(false)时,当中的Switch控件的Enabled属性不受影响。通研究代码发现SwitchPreference继承于TwoStatePreference类,TwoStatePreference类继承于Preference类。在Preference类中存在一个setEnabledStateOnViews(View view,boolean enabled)方法:
    /**
     * Makes sure the view (and any children) get the enabled state changed.
     */
    private void setEnabledStateOnViews(View v, boolean enabled) {
        v.setEnabled(enabled);
        
        if (v instanceof ViewGroup) {
            final ViewGroup vg = (ViewGroup) v;
            for (int i = vg.getChildCount() - 1; i >= 0; i--) {
                setEnabledStateOnViews(vg.getChildAt(i), enabled);
            }
        }
    }
      方法很简单,就是通过递归来改变Preference中所有子控件的enabled属性,本来可以直接通过重新这个方法就实现,但是这个方法是private,所以无法再子类中重写该方法,接着看到Preference类中onBindView(View view)方法:
protected void onBindView(View view) {
        final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title);
        if (titleView != null) {
            final CharSequence title = getTitle();
            if (!TextUtils.isEmpty(title)) {
                titleView.setText(title);
                titleView.setVisibility(View.VISIBLE);
            } else {
                titleView.setVisibility(View.GONE);
            }
        }

        final TextView summaryView = (TextView) view.findViewById(
                com.android.internal.R.id.summary);
        if (summaryView != null) {
            final CharSequence summary = getSummary();
            if (!TextUtils.isEmpty(summary)) {
                summaryView.setText(summary);
                summaryView.setVisibility(View.VISIBLE);
            } else {
                summaryView.setVisibility(View.GONE);
            }
        }

        final ImageView imageView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
        if (imageView != null) {
            if (mIconResId != 0 || mIcon != null) {
                if (mIcon == null) {
                    mIcon = getContext().getDrawable(mIconResId);
                }
                if (mIcon != null) {
                    imageView.setImageDrawable(mIcon);
                }
            }
            imageView.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
        }

        final View imageFrame = view.findViewById(com.android.internal.R.id.icon_frame);
        if (imageFrame != null) {
            imageFrame.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
        }

        if (mShouldDisableView) {
            setEnabledStateOnViews(view, isEnabled());
        }
    }

       也就是在绑定视图的方法的最后调用了setEnabledStateOnViews(View view,boolean enabled)方法,再看看SwitchPreference类重写了onBindView(View view)

方法:

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

        View checkableView = view.findViewById(com.android.internal.R.id.switchWidget);
        if (checkableView != null && checkableView instanceof Checkable) {
            if (checkableView instanceof Switch) {
                final Switch switchView = (Switch) checkableView;
                switchView.setOnCheckedChangeListener(null);
            }

            ((Checkable) checkableView).setChecked(mChecked);

            if (checkableView instanceof Switch) {
                final Switch switchView = (Switch) checkableView;
                switchView.setTextOn(mSwitchOn);
                switchView.setTextOff(mSwitchOff);
                switchView.setOnCheckedChangeListener(mListener);
            }
        }

        syncSummaryView(view);
    }
       通过代码可以看到SwitchPreference重写该方法就是将Switch控件添加到Preference的视图当中。

       所以要实现Switch控件的Enabled属性跟SwitchPreference的Enabled属性解绑,可以这样:自定义一个BeamSwitchPreference类继承于SwitchPreference,重写

onBindView(View view)方法,然后自己在BeamSwitchPreference类自己的setEnabledStateOnViews(View view,boolean enabled)方法,在onBindView(View view)方法最后调用它。自定义的BeamSwitchPreference类如下

public class BeamSwitchPreference extends SwitchPreference{


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

    public BeamSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public BeamSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

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

    @Override
    protected void onBindView(View view) {
        //必须要调用onBindView,因为我们只需要在后面添加相应的方法
        super.onBindView(view);
        //如果是Switch,当enabled为false,通过调用自定义的setEnabledStateOnViews使其enabled不受影响
        if(!isEnabled()){
            setEnabledStateOnViews(view, isEnabled());
        }

    }

    private void setEnabledStateOnViews(View v, boolean enabled) {
        v.setEnabled(enabled);

        if (v instanceof ViewGroup) {
            final ViewGroup vg = (ViewGroup) v;
            for (int i = vg.getChildCount() - 1; i >= 0; i--) {
                //判断是否为Switch控件
                if(vg.getChildAt(i) instanceof Switch){
                    setEnabledStateOnViews(vg.getChildAt(i), !enabled);
                }else {
                    setEnabledStateOnViews(vg.getChildAt(i), enabled);
                }

            }
        }
    }
}
       在PreferenceScreen中调用自定义的BeamSwitchPreference即可



    
        
    


         在代码中设置相关属性:

        SwitchPreference sp = (SwitchPreference) findPreference("switch_preference");
        sp.setChecked(true);
        sp.setEnabled(false);

       最后看看自定义的BeamSwitchPreference的效果,已经达到了预期效果,并且因为整体的SwitchPreference已经是disable,所以这时候的Switch控件也是不能点击的:

自定义SwitchPreference实现其中Switch控件的enabled属性的解绑_第1张图片





















你可能感兴趣的:(Android)