Android如何自定义Preference呢?

来源:互联网 发布:linux 解压war 编辑:程序博客网 时间:2024/05/21 08:55

Android如何自定义Preference呢?
前面我们一篇文章介绍了PreferenceFragment怎么使用,今天的话,我们介绍一下怎么自定义Preference。

Android开发中怎么使用PreferenceFragment

这篇文章基于前一篇文章,请阅读完前一篇文章,再阅读这篇文章吧!接下来我们呢就要学习自定义自己的Preference

【先理解源码】

首先,我们要看看默认的布局是怎么样的!在Preference.java这个类中,就有一个onCreateView这个方法,这个方法是View创建调用的:

protected View onCreateView(ViewGroup parent) {        final LayoutInflater layoutInflater =            (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);        final View layout = layoutInflater.inflate(mLayoutResId, parent, false);         final ViewGroup widgetFrame = (ViewGroup) layout                .findViewById(com.android.internal.R.id.widget_frame);        if (widgetFrame != null) {            if (mWidgetLayoutResId != 0) {                layoutInflater.inflate(mWidgetLayoutResId, widgetFrame);            } else {                widgetFrame.setVisibility(View.GONE);            }        }        return layout;    }

这里面很简单,就是用 Inflater去加载mLayoutResId这个id的xml,这个mLayoutResId是什么呢?
private int mLayoutResId = com.android.internal.R.layout.preference;
所以说,这个id是定的:这个xml的布局代码如下:

<?xml version="1.0" encoding="utf-8"?>  <!-- Copyright (C) 2011 The Android Open Source Project       Licensed under the Apache License, Version 2.0 (the "License");       you may not use this file except in compliance with the License.       You may obtain a copy of the License at            http://www.apache.org/licenses/LICENSE-2.0       Unless required by applicable law or agreed to in writing, software       distributed under the License is distributed on an "AS IS" BASIS,       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.       See the License for the specific language governing permissions and       limitations under the License.  -->  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:minHeight="?android:attr/listPreferredItemHeightSmall"      android:gravity="center_vertical"      android:paddingStart="?android:attr/listPreferredItemPaddingStart"      android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"      android:background="?android:attr/selectableItemBackground">      <RelativeLayout          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_weight="1"          android:paddingTop="16dip"          android:paddingBottom="16dip">          <TextView              android:id="@+android:id/title"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:singleLine="true"              android:textAppearance="@android:style/TextAppearance.Material.Subhead"              android:textColor="?android:attr/textColorPrimary"              android:ellipsize="marquee"              android:fadingEdge="horizontal" />          <TextView              android:id="@android:id/summary"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:layout_below="@android:id/title"              android:layout_alignStart="@android:id/title"              android:visibility="gone"              android:textAlignment="viewStart"              android:textAppearance="@android:style/TextAppearance.Material.Body1"              android:textColor="?android:attr/textColorSecondary"              android:maxLines="10" />      </RelativeLayout>      <LinearLayout          android:id="@android:id/widget_frame"          android:layout_width="wrap_content"          android:layout_height="match_parent"          android:minWidth="58dip"          android:gravity="end|center_vertical"          android:orientation="vertical" />  </LinearLayout>

我们可以看到,这个布局很简单:有一个title和一个sumarry

剩下就是一个widget_frame

而前面的java代码里,也就是onCreateView那里,还有一部分代码,就是把mWidgetLayoutResId这个xml布局加载到widget_frame里头。
那mWidgetLayoutResId是怎么来的呢?

只有两个地方,一个地方是设置它,通过一个方法:
public void setWidgetLayoutResource(int widgetLayoutResId)

另娃一个则是从属性中获取,也就是我们的布局属性中可以直接设置。

而它对应的控件使用,就会在onBindView里头找到对应的控件,成员变量。

到这里,我们基本明白了每一个Preference是怎么实现默认布局的吧!

【谈到了自定义Preference】

有了上面的基础,我们就知道了怎么去自定义一个Preference了。

首先,我们继承自Preference,然后覆写onCreateView方法,反回我们自己的编写的布局,接着复写onBindView去找到相应的控件。然后呢就是暴露一些方法吧!

先不说理论了,直接就上吧!
第一步:我们编写一个类,去继承自己Preference

没有第二步了,刚才写代码的时候没忍住,小手一抖,把整个例子写完了!先看代码吧,后面再进行解释:

  /**    * Create by TrillGates 2017/8/11    */    public class VolumeSettingPreference extends Preference implements View.OnClickListener {        private TextView mTitle;        private String mTitleText;        private int mDefaultVolume;        private String mSummaryText;        private String mKey;        private TextView mSummary;        private Dialog mShowDialog;        private SeekBar mSeekBar;        public VolumeSettingPreference(Context context) {            this(context, null);        }        public VolumeSettingPreference(Context context, AttributeSet attrs) {            this(context, attrs, 0);        }        public VolumeSettingPreference(Context context, AttributeSet attrs, int defStyleAttr) {            super(context, attrs, defStyleAttr);            //这里可以定一些自定义的属性,这跟自定义View的套路是一样的,比如说获取到title之类的,默认的音量是多少            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.voice_style);            mTitleText = typedArray.getString(R.styleable.voice_style_title);            mDefaultVolume = typedArray.getIndex(R.styleable.voice_style_default_voice);            mSummaryText = typedArray.getString(R.styleable.voice_style_summary);            mKey = typedArray.getString(R.styleable.voice_style_key);            //重要,把key给老爸            super.setKey(mKey);            typedArray.recycle();        }        @Override        protected View onCreateView(ViewGroup parent) {            //拿到Invalter            View content = LayoutInflater.from(getContext()).inflate(R.layout.voice_setting_layout, null);            return content;        }        @Override        protected void onBindView(View view) {            int saveValue = getSharedPreferences().getInt(mKey, 0);            mTitle = (TextView) view.findViewById(R.id.title);            mSummary = (TextView) view.findViewById(R.id.summary);            mTitle.setText(mTitleText);            if (saveValue != 0) {                mSummary.setText("当前音量:" + saveValue);            } else {                mSummary.setText(mSummaryText);            }            //设置这个view的点击事件,这里的话,我们会弹出一个dialog,去设置音量值            mShowDialog = new Dialog(getContext());            View dialogView = LayoutInflater.from(getContext()).inflate(R.layout.dialog_volume_set_layout, null);            mShowDialog.setContentView(dialogView);            mShowDialog.setTitle("音量设置");            view.setOnClickListener(this);            mSeekBar = (SeekBar) dialogView.findViewById(R.id.dialog_volume_value);            TextView cancel = (TextView) dialogView.findViewById(R.id.dialog_cancel);            TextView ok = (TextView) dialogView.findViewById(R.id.dialog_ok);            mSeekBar.setProgress(saveValue);            mSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener);            cancel.setOnClickListener(onCancelListener);            ok.setOnClickListener(onOkClickListener);            //这里是设置seekBar的总梯度            mSeekBar.setMax(10);        }        @Override        public void onClick(View v) {            //条目被点击了            mShowDialog.show();        }        private View.OnClickListener onCancelListener = new View.OnClickListener() {            @Override            public void onClick(View v) {                mShowDialog.dismiss();            }        };        private View.OnClickListener onOkClickListener = new View.OnClickListener() {            @Override            public void onClick(View v) {                //点击确定的时候,把数据获取到,显示出来,并且保存起来                persistInt(mSeekBar.getProgress());                //设置UI                mSummary.setText("当前音量是:" + mSeekBar.getProgress());                mShowDialog.dismiss();            }        };        private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {            @Override            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {            }            @Override            public void onStartTrackingTouch(SeekBar seekBar) {            }            @Override            public void onStopTrackingTouch(SeekBar seekBar) {                showText("当前音量为:" + seekBar.getProgress());            }        };        private Toast mToast = null;        private void showText(String summaryText) {            if (mToast == null) {                mToast = Toast.makeText(getContext(), summaryText, Toast.LENGTH_SHORT);            } else {                mToast.setText(summaryText);            }            mToast.show();        }    }

附加的文件呢?嘻嘻!如下:
自定义Preference的xml布局文件

   <?xml version="1.0" encoding="utf-8"?>    <RelativeLayout      xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="wrap_content">      <TextView          android:id="@+id/title"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_centerVertical="true"          android:padding="16dp"          android:text="我是标题"          android:textSize="20sp"/>      <TextView          android:id="@+id/summary"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_alignParentRight="true"          android:layout_centerVertical="true"          android:padding="16dp"          android:text="summary"          android:textSize="18sp"/>  </RelativeLayout>

自定义属性文件:

  <?xml version="1.0" encoding="utf-8"?>    <resources>        <declare-styleable name="voice_style">            <attr name="default_voice" format="integer"/>            <attr name="title" format="string"/>            <attr name="summary" format="string"/>            <attr name="key" format="string"/>        </declare-styleable>    </resources>

弹出的对话框布局文件:

<?xml version="1.0" encoding="utf-8"?>    <RelativeLayout        xmlns:android="http://schemas.android.com/apk/res/android"        android:layout_width="300dp"        android:layout_height="150dp"        android:background="#424242">        <RelativeLayout            android:layout_width="match_parent"            android:layout_height="150dp">            <TextView                android:id="@+id/dialog_title"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:padding="20dp"                android:text="音量设置"                android:textSize="16sp"/>            <SeekBar                android:id="@+id/dialog_volume_value"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:layout_centerInParent="true"                android:layout_marginLeft="10dp"                android:layout_marginRight="10dp"/>            <TextView                android:id="@+id/dialog_cancel"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_alignParentBottom="true"                android:padding="20dp"                android:text="CANCEL"                android:textColor="@color/colorAccent"/>            <TextView                android:id="@+id/dialog_ok"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_alignParentBottom="true"                android:layout_alignParentRight="true"                android:padding="20dp"                android:text="OK"                android:textColor="@color/colorAccent"/>        </RelativeLayout>    </RelativeLayout>

应该就这么多了吧!
接下来就是简单解释一下吧:

首先我们按着前面的分析,设置布局UI,然后处理事件,保存内容!

每一个Preference都会创建对应的SharePreference,它用于保存数据

注意的是要把key设置给老爸哦!

保存数据的方式是父类的方法persist类型,比如说保存Int类型的就用persistInt这个方法保存即可!

使用的话是这样子使用,跟上一篇文章的EditTextPreference是一样的!

  <?xml version="1.0" encoding="utf-8"?>    <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"                      xmlns:sob="http://schemas.android.com/apk/res-auto">        <PreferenceCategory            android:title="无线和网络">            <CheckBoxPreference                android:defaultValue="true"                android:key="is_auto_connect"                android:summary="选中则自动连接!"                android:title="是否自动连接wifi"/>            <SwitchPreference                android:defaultValue="false"                android:key="is_wifi_open"                android:summary="滑动打开wifi"                android:title="Wifi"/>            <EditTextPreference                android:dialogTitle="请输入wifi密码"                android:key="wifi_password"                android:summary="点击输入密码"                android:title="Wifi密码"/>        </PreferenceCategory>        <PreferenceCategory            android:title="区域和爱好">            <ListPreference                android:entries="@array/countries"                android:entryValues="@array/countries"                android:key="country"                android:summary="点击选择国家"                android:title="国家"/>            <MultiSelectListPreference                android:entries="@array/balls"                android:entryValues="@array/balls"                android:key="hobbies"                android:summary="点击选择你喜欢的球类"                android:title="爱好"/>        </PreferenceCategory>        <PreferenceCategory            android:title="其他">            <PreferenceScreen                android:summary="点击跳转到另外一个屏幕去看关于"                android:title="开发关模式">                <SwitchPreference                    android:defaultValue="false"                    android:key="is_development_mod"                    android:title="打开开发者模式"/>            </PreferenceScreen>            <com.sunofbeaches.preferencedemo.view.VolumeSettingPreference                sob:key="volume_value"                sob:summary="点击设置音量"                sob:title="音量设置"/>        </PreferenceCategory>    </PreferenceScreen>

最后面这个就是我们自己编写的啦!

<com.sunofbeaches.preferencedemo.view.VolumeSettingPreference                sob:key="volume_value"                sob:summary="点击设置音量"                sob:title="音量设置"/>

最后使用效果请看上面的git动图吧!

今天周五,祝大家周末愉快!我回去啦,明天休息,去找女朋友!有空接下来会录制wifi的开发视频!

有空来阳光沙滩(bbs.sunofbeaches.com)做客哦!一个人写博客挺闷的!

原创粉丝点击