自定义Preference
来源:互联网 发布:永安 知乎 编辑:程序博客网 时间:2024/06/03 16:28
Preference、PreferenceActivity,PreferenceFragment
Preference的容器,如PreferenceGroup持有一个ListView对象成员,而adapter是PreferenceGroupAdapter(extends BaseAdapter)
PreferenceGroupAdapter
#getView()
public View getView(int position, View convertView, ViewGroup parent) { final Preference preference = this.getItem(position);//获取对应的Preference // Build a PreferenceLayout to compare with known ones that are cacheable. mTempPreferenceLayout = createPreferenceLayout(preference, mTempPreferenceLayout); // If it's not one of the cached ones, set the convertView to null so that // the layout gets re-created by the Preference. if (Collections.binarySearch(mPreferenceLayouts, mTempPreferenceLayout) < 0 || (getItemViewType(position) == getHighlightItemViewType())) { convertView = null; } View result = preference.getView(convertView, parent);//调用Preference的getView获取view if (position == mHighlightedPosition && mHighlightedDrawable != null) { ViewGroup wrapper = new FrameLayout(parent.getContext()); wrapper.setLayoutParams(sWrapperLayoutParams); wrapper.setBackgroundDrawable(mHighlightedDrawable); wrapper.addView(result); result = wrapper; } return result; }
Preference#getView()
/** * Gets the View that will be shown in the {@link PreferenceActivity}. * * @param convertView The old View to reuse, if possible. Note: You should * check that this View is non-null and of an appropriate type * before using. If it is not possible to convert this View to * display the correct data, this method can create a new View. * @param parent The parent that this View will eventually be attached to. * @return Returns the same Preference object, for chaining multiple calls * into a single statement. * @see #onCreateView(ViewGroup) * @see #onBindView(View) */ public View getView(View convertView, ViewGroup parent) { if (convertView == null) { convertView = onCreateView(parent);//调用onCreateView去inflate布局 } onBindView(convertView);//将Preference的xml文件的属性应用到View中 return convertView; }
Preference#onCreateView()
/** * Creates the View to be shown for this Preference in the * {@link PreferenceActivity}. The default behavior is to inflate the main * layout of this Preference (see {@link #setLayoutResource(int)}. If * changing this behavior, please specify a {@link ViewGroup} with ID * {@link android.R.id#widget_frame}. * <p> * Make sure to call through to the superclass's implementation. * * @param parent The parent that this View will eventually be attached to. * @return The View that displays this Preference. * @see #onBindView(View) */ @CallSuper protected View onCreateView(ViewGroup parent) { final LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); final View layout = layoutInflater.inflate(mLayoutResId, parent, false);//布局为mLayoutResId final ViewGroup widgetFrame = (ViewGroup) layout .findViewById(com.android.internal.R.id.widget_frame); if (widgetFrame != null) { if (mWidgetLayoutResId != 0) {//mWidgeLayoutResId可以在子类构造方法中传入一个style layoutInflater.inflate(mWidgetLayoutResId, widgetFrame); } else { widgetFrame.setVisibility(View.GONE); } } return layout; }该方法是inflate一个Preference的layout,而想要自定义layout,可以重写这个onCreate方法,也可以不重写,
而在子类构造方法中传入一个参数到Preference的第三个参数defStyleAttr。详细看下面SwichPreference的
解析。
Preference#onBindView()
/** * Binds the created View to the data for this Preference. * <p> * This is a good place to grab references to custom Views in the layout and * set properties on them. * <p> * Make sure to call through to the superclass's implementation. * * @param view The View that shows this Preference. * @see #onCreateView(ViewGroup) */ @CallSuper protected void onBindView(View view) { final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title); if (titleView != null) { final CharSequence title = getTitle();//获取title属性值 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();//获取summary属性值 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());//和Enable属性相关,下面在自定义SwitchPreference时会详细说 } }该方法在Preference属性改变时,会被调用,因为getView会被调用,因为属性改变后,View也会改变,如一些可见性等。
在自定义Preference时,一定要调用这个方法,因为里面有些被调用到的方法的访问权限是private的,如果不调用这个
父类方法,有些属性就无法生效。
还介绍一个public方法,performClick()
/** * Called when a click should be performed. * * @param preferenceScreen A {@link PreferenceScreen} whose hierarchy click * listener should be called in the proper order (between other * processing). May be null. * @hide */ public void performClick(PreferenceScreen preferenceScreen) { if (!isEnabled()) {//当enalble时,此方法无效。enalbe的确认其属性enable只是必要条件 return; } onClick();//自定义时,最好不要直接重写PerformClick,可以重写这个空方法 if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) { return;//对mOnClickListener的处理可能需要重写该方法 } PreferenceManager preferenceManager = getPreferenceManager(); if (preferenceManager != null) { PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager .getOnPreferenceTreeClickListener(); if (preferenceScreen != null && listener != null && listener.onPreferenceTreeClick(preferenceScreen, this)) { return; } } if (mIntent != null) { Context context = getContext(); context.startActivity(mIntent); } }该方法是点击该Preference的view时会回调的一个方法,如果必须重写该方法,最好调用一下这个父类方法
Perference的一个构造方法:
public SwitchPreference(Context context, AttributeSet attrs) { this(context, attrs, com.android.internal.R.attr.switchPreferenceStyle); }其中switchPreferenceStyle
<item name="switchPreferenceStyle">@style/Preference.SwitchPreference</item>
而perference.SwitchPreference
<style name="Preference.SwitchPreference"> <item name="widgetLayout">@layout/preference_widget_switch</item> <item name="switchTextOn">@string/capital_on</item> <item name="switchTextOff">@string/capital_off</item> </style>其中的widgetlayout就是Perference中的mWidgetLayoutResId。
下面说下SwitchPreference的实现,由此可知道自定义Preference的方法
SwitchPreference extends TwoStatePreference,
TwoStatePreference
没有定义一些跟view相关的东西,
只是增加了mChecked,mSummaryOff,mSummaryOn字段及其getter和setter。而在setter实现中,没有实现对View
的任何操作。其实在Perference的实现中,属性的setter中也没有对View操作,只是将设置进来的东西保存到成员
中,然后notifyChange()通知一个Listener,就是OnPerferenceChangeInternalListener,这是一个默认权限
的接口,而其setter也是,所以只有同一个包的才能设置这个接口,所以我们无法通过子类去设置或者重写这个Listener。
而PreferenceGroupAdapter是实现并为该Group的每个Preference设置了这个Listener。
其实现如下:
public void onPreferenceChange(Preference preference) { notifyDataSetChanged(); }
所以每次有什么属性变化,都会ListView的Adapter都会调用所有Preference#getView一遍。
所以在自定义时,需要在onBindView中处理自定义Preference中新增属性的变化,并把变化应用到
View中,也可以在onBindView中处理其他属性变化。
Preference的Enable属性
setEnable
/** * Sets whether this Preference is enabled. If disabled, it will * not handle clicks. * * @param enabled Set true to enable it. */ public void setEnabled(boolean enabled) { if (mEnabled != enabled) { mEnabled = enabled; // Enabled state can change dependent preferences' states, so notify notifyDependencyChange(shouldDisableDependents()); notifyChanged(); } }看上面的
Preference#onBindView()
方法,要将Enable属性和View关联起来,代码如下:if (mShouldDisableView) { setEnabledStateOnViews(view, isEnabled()); }就是还需要mShouldDisableView属性为true才行。而且setEnabledStateOnViews()方法是private,
不调用父类onBindView,根本没有实现Enable属性对View生效。而isEnable()方法,也不只是考虑Enable
属性,其代码如下:
boolean isEnable()
/** * Checks whether this Preference should be enabled in the list. * * @return True if this Preference is enabled, false otherwise. */ public boolean isEnabled() { return mEnabled && mDependencyMet && mParentDependencyMet; }还考虑了该Preference及父容器的dependency属性。
- 自定义 Preference
- 自定义Preference
- 自定义Preference
- Android preference 自定义控件
- Android 自定义 Preference
- android preference自定义
- 自定义 Preference Header 布局
- Preference实现自定义视图
- Android 自定义preference组件
- android 自定义Preference(APIDemons中自定义Preference解析)
- Android中preference 自定义样式
- android 自定义preference的属性
- Android如何自定义Preference呢?
- Android自定义控件——自定义Preference
- Preference
- Preference
- Preference
- Preference
- Linux用户进程高精度定时器去抖动
- hdu 4348 To the moon (主席树)
- Java知识(对象的序列化和反序列化)
- 网络流入门术语定理
- JDBC
- 自定义Preference
- 使用指南(自用)
- 算法题练习系列之(三十): 在霍格沃茨找零钱
- 几条短信验证码防刷机制
- 解决ToolBar中的menu无法同时显示图标和文字的问题
- 文章管理 linux命令嵌套实例(二)
- 编程之美:3.1 字符串移位包含的问题
- .ftl文件介绍
- css文本