zoukankan      html  css  js  c++  java
  • 自定义 Preference Header 布局

    1. Preference Header 概述
    对于什么是 Preference Header,以及何时使用 Preference Header,请参考我的另一篇博文: 何时使用 Preference Headers

    2. 自定义 Preference Header 布局的必要性:
    Preference Header 的设计初衷是作为复杂设置选项的一个简单抽象或者概括,所以它本身应该一目了然,让用户一看便知道下一级设置中大概都有哪些设置选项,在布局设计上也应简单,所以谷歌给 header 统一只设置了 icon、title 和 summary 三个布局项。

    基于以上原则,谷歌并没有给 Preference Header 提供方便的自定义接口,或许考虑到这本身不需要做什么自定义。但是有时候我们确实需要做一些简单的自定义。比如,你的 APP 需要统一 UI 风格,需要自定义的字体、颜色、selector样式等,这时当你需要用到 Preference Header 的时候就需要考虑对其布局进行 微自定义。

    3. 如何自定义?
    在本文中,我们将实现对 Preference Header 布局的有限的自定义,实现如下图所示的效果,上图为没有自定义的效果,下图为自定义之后的效果:










    3.1 寻找 Preference Headers 的布局方式:
    Headers 是在 PreferenceActivity 中进行布局的,PreferenceActivity 其实是继承了一个 ListActivity,所以呈现在我们面前的 Headers 列表其实就是一个 ListView,那么我们很自然地想到每个 Header ,即每个 list item 的布局应该在一个 list adapter 中被 inflated ,查看 PreferenceActivity 的 源代码发现里面定义了一个 ArrayAdapter<Header> 的子类 HeaderAdapter,请注意 getView 中是如何 inflate header item 布局的:

    @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                HeaderViewHolder holder;
                View view;
    
                if (convertView == null) {
                    view = mInflater.inflate(com.android.internal.R.layout.preference_header_item,
                            parent, false);
                    holder = new HeaderViewHolder();
                    holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
                    holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);
                    holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary);
                    view.setTag(holder);
                } else {
                    view = convertView;
                    holder = (HeaderViewHolder) view.getTag();
                }
            
             ......
                return view;
            }

    3.2 分析 header item 布局文件 preference_header_item.xml :
    从 getView 方法中我们确认了 header item 的布局在 preference_header_item.xml 这个文件中,那么要更改布局方式其实就是修改这个文件,我们从源码的资源文件中找到该文件的  源代码发现每一个 header item 都由 icon(ImageView)、title(TextView) 和 summary(TextView) 三个元素组成。接下来就可以考虑如何对其进行修改了。

    3.3 如何修改 preference_header_item.xml?
    这里我们不打算对 header 进行复杂的自定义(比如,增加额外的 header 元素,这个需要对 Header 本身也进行定制,考虑到 Header 的简洁要求,个人觉得没有必要这么做)。

    在本文中,我们实现一些比较有用的自定义,具体来说包括如下修改: icon 和 title、summary 位置的互换,title 和 summary 字体颜色、大小的更改,list item 高度的修改,list item 背景的修改(修改 selector),正如上图给出的效果所示。

    3.4 定义一个本地布局文件 custom_preference_header_item.xml:
    我们将原生的 preference_header_item.xml 文件拷贝到本地工程 layout 文件夹中,修改文件名称为 custom_preference_header_item.xml,并对布局进行 3.3 中所述的修改。

    3.5 定义一个 PreferenceActivity 的子类 CustomPreferenceActivity:
    在 CustomPreferenceActivity 中重新定义一个 HeaderAdapter,主要将其中的

    view = mInflater.inflate(com.android.internal.R.layout.preference_header_item,
                            parent, false);

    修改为:

    view = mInflater.inflate(R.layout.custom_preference_header_item,
                            parent, false);

    由于 PreferenceActivity 中的 List<Header> 成员 mHeaders 是私有的,而我们要将 mHeaders 作为数据源参数传递给新定义的 HeaderAdapter 中,为了解决这个问题,我们在 CustomPreferenceActivity 中再定义一个 List<Header> 成员 mCopyHeaders,作为 mHeaders 的一个拷贝,并通过重写 loadHeadersFromResource 方法将 mHeaders 赋值给 mCopyHeaders:

         @Override
         public void loadHeadersFromResource(int resid, List<Header> target) {
              super.loadHeadersFromResource(resid, target);
              mCopyHeaders = target;
         }

    注意: loadHeadersFromResource  中的 target 参数即为 mHeaders,详细请参考 PreferenceActivity 源码

    在 PreferenceActivity 源码  中,setListAdapter() 是在 onCreate() 方法中调用的,为此,我们还要重写 onCreate() 方法,将 CustomPreferenceActivity 中的 adapter 设置为自定义的 HeaderAdapter 对象:

         @Override
         protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
             
              if (mCopyHeaders != null && mCopyHeaders.size() > 0) {
                   setListAdapter(new HeaderAdapter(this, mCopyHeaders));
              }
         }
    

    至此,Preference Header 的自定义布局就完成了,接下来就只需要定义一个 CutomPreferenceActivity 的子类,并编写相应的 preference-headers 文件,重新 onBuildHeaders() 方法就可以了:

         @Override
         public void onBuildHeaders(List<Header> target) {
              this.loadHeadersFromResource(R.xml.preference_headers, target);
         }

    完整的工程请下载:CustomPreferenceHeader



  • 相关阅读:
    js 高阶函数之柯里化
    JavaScript 相关的工具代码
    JS 数组、对象的深拷贝
    页面性能优化
    axios(封装使用、拦截特定请求、判断所有请求加载完毕)
    java 实现登录验证码 (kaptcha 验证码组件)
    告别 hash 路由,迎接 history 路由
    解决 Vue 动态生成 el-checkbox 点击无法赋值问题
    分享基于 websocket 网页端聊天室
    vue + element 动态渲染、移除表单并添加验证
  • 原文地址:https://www.cnblogs.com/aukle/p/3220132.html
Copyright © 2011-2022 走看看