需求描述:

由于手机功能越来越完善,相应的偏好设置也就越来越多;从用户体验的角度考虑,为了让用户能够在短时间内对常用的偏好设置进行操作,如WIFI,蜂窝数据等。单独将一些常用的设置功能单独展示出来,已达到减少用户操作的可能性。因此采用将系统设置页面进行分页展示并可以滑动进行切换。

效果图:

          

对于了解Settings源码的同学应该知道,Settings的设计相对来说并不是很简单,大刀阔斧的对Settings可能会引起更多的bug。因此若实现该需求则在保持原有Settings功能完整的情况下进行低耦合高内聚的修改。

由于Settings是一个Activity,因此,我这里采用ViewPager结合Activity的方法实现该功能。也就是说把Settings作为一个子View嵌入到ViewPager中,同时克隆一个新的Settings为OffenUsedSettings作为另一个字View,该OffenUsedSettings采用与Settings相同的设计思路进行,或者可以完全的复制,只是在载入布局的时候加以改变。具体架构设计如下图:

这里贴出SettingsActivity.java全部代码和OffenUsedActivity.java关键部分代码,其他部分与原有Settings相同。

SettingsActivity.java代码:

package com.android.settings;





import java.util.ArrayList;





import android.app.Activity;

import android.app.LocalActivityManager;

import android.content.Context;

import android.content.Intent;

import android.os.Bundle;

import android.support.v4.view.ViewPager;

import android.support.v4.view.ViewPager.OnPageChangeListener;

import android.view.View;

import android.view.Window;

import android.widget.CompoundButton;

import android.widget.RadioGroup;

import android.widget.CompoundButton.OnCheckedChangeListener;

import android.widget.RadioButton;





public class SettingsActivity extends Activity implements OnCheckedChangeListener, OnPageChangeListener {

    private RadioGroup mRadioGroup;

    private RadioButton mOffenUsed, mAll;

    private ViewPager mViewPager;

    private Context mContext;

    private LocalActivityManager mManager;

    private SettingsAdapter mAdapter;





    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE);

        setContentView(R.layout.activity_settings);

        mContext = SettingsActivity.this;

        mManager = new LocalActivityManager(this, false);

        mManager.dispatchCreate(savedInstanceState);

        initView();

    }





    @Override

    protected void onResume() {

        super.onResume();

        mManager.dispatchResume();

        if (mViewPager != null) {

            switch (mViewPager.getCurrentItem()) {

            case 0:

                Activity offenUsedActivity = mManager.getActivity("OFFENUSED");

                if (offenUsedActivity != null && offenUsedActivity instanceof OffenUsedSettings) {

                    ((OffenUsedSettings) offenUsedActivity).invisibleOnScreen();

                }

                break;

            case 1:

                Activity allActivity = mManager.getActivity("ALL");

                if (allActivity != null && allActivity instanceof Settings) {

                    ((Settings) allActivity).invisibleOnScreen();

                }

                break;

            }

        }

    }



    private void initView() {

        mRadioGroup = (RadioGroup) findViewById(R.id.rg_settings);

        mOffenUsed = (RadioButton) findViewById(R.id.rb_offen_used);

        mOffenUsed.setOnCheckedChangeListener(this);

        mAll = (RadioButton) findViewById(R.id.rb_all);

        mAll.setOnCheckedChangeListener(this);

        mViewPager = (ViewPager) findViewById(R.id.vp_settings);

        mViewPager.setOnPageChangeListener(this);





        final ArrayList<View> list = new ArrayList<View>();

        Intent intentCommon = new Intent(mContext, OffenUsedSettings.class);

        list.add(getView("OFFENUSED", intentCommon));

        Intent intentMain = new Intent(mContext, Settings.class);

        list.add(getView("ALL", intentMain));





        mAdapter = new SettingsAdapter(mContext, list);

        mViewPager.setAdapter(mAdapter);





        if (mOffenUsed.isChecked()) {

            mViewPager.setCurrentItem(0);

            mRadioGroup.setBackgroundResource(R.drawable.settings_common);

        } else if (mAll.isChecked()) {

            mViewPager.setCurrentItem(1);

            mRadioGroup.setBackgroundResource(R.drawable.settings_main);

        }

    }





    private View getView(String id, Intent intent) {

        return mManager.startActivity(id, intent).getDecorView();

    }





    @Override

    public void onCheckedChanged(CompoundButton arg0, boolean arg1) {

        if (arg1) {

            switch (arg0.getId()) {

            case R.id.rb_offen_used:

                mViewPager.setCurrentItem(0);

                Activity offenUsedActivity = mManager.getActivity("OFFENUSED");

                if (offenUsedActivity != null && offenUsedActivity instanceof OffenUsedSettings) {

                    ((OffenUsedSettings) offenUsedActivity).invisibleOnScreen();

                }

                break;





            case R.id.rb_all:

                mViewPager.setCurrentItem(1);

                Activity allActivity = mManager.getActivity("ALL");

                if (allActivity != null && allActivity instanceof Settings) {

                    ((Settings) allActivity).invisibleOnScreen();

                }

                break;

            }

        }

    }





    @Override

    public void onPageScrollStateChanged(int arg0) {

    }





    @Override

    public void onPageScrolled(int arg0, float arg1, int arg2) {

    }





    @Override

    public void onPageSelected(int arg0) {

        switch (arg0) {

        case 0:

            if (!mOffenUsed.isChecked())

                mOffenUsed.setChecked(true);

            mRadioGroup.setBackgroundResource(R.drawable.settings_common);

            break;

        case 1:

            if (!mAll.isChecked())

                mAll.setChecked(true);

            mRadioGroup.setBackgroundResource(R.drawable.settings_main);

            break;

        }

    }

}

这里主要对上面代码中蓝色和红色部分进行简单描述,其他都是很基础的部分我相信这里不需要我在赘述。

红色代码部分主要将当前Activity作为一个容器以便于可以将其他的Activity作为子View嵌入其中。需要注意的是第二个参数,源码中给出的解释是@param singleMode Ture if the LocalActivityManager should keep a maximum of one activity resume.我这里理解的大概的意思再创建子Activity的时候是否执行所有子Activity的onResume的方法,如果为true,则只执行ViewPager中最后一个创建的Activity的onResume()方法。(这种结论也得到了证实,如果这里为true,则ViewPager中只有最后一个子Activity中的onResume()方法被调用)因此这里我们给出的实参是false。

蓝色部分代码的原因是,ViewPager+Activity的方式会导致子Activity中生命周期函数的紊乱,当然在第一次创建子Activity的时候onResume()方法会正常执行,但是当我们创建成功后,按home键将应用程序切换到后台的时候,在切换回活动状态的时候子Activity的onResume()方法并不会正确调用,但是最外层中的Activity,也就是这里的SettingsActivity方法中的onRuesme()方法会正常被调用,因此这部分代码可以解决这个问题。

OffenUsedSettings.java

/**

     * Populate the activity with the top-level headers.

     */

    @Override

    public void onBuildHeaders(List<Header> headers) {

        if (!onIsHidingHeaders()) {

            PDebug.Start("loadHeadersFromResource");

 

loadHeadersFromResource(R.xml.offen_used_settings_headers, headers);



            PDebug.End("loadHeadersFromResource");

            updateHeaderList(headers);

        }

    }

以上紫色代码中主要是在载入不同的布局文件。其他与原有的Settings无异。

因此代码解释到这里已经节本完成了,那么值得再叨叨的是,既然OffenusedSettings.java中只是修改以实现载入不同的布局文件来达到前文叙述的需求,为什么不同时使用两个Settings作为子Activity呢?

答案是可定的。我们完全可以把两个Settings同时作为子Activity,只是载入的布局文件不同来达到需求。我已经验证过,这里为了让大家容易理解,便采用了复制Settings的方式来实现。有兴趣的朋友可以自己动手实现。

实现Android4.4系统设置分页滑动浏览功能的更多相关文章

  1. Android 使用ViewPager结合PhotoView开源组件实现网络图片在线浏览功能

    在实际的开发中,我们市场会遇到这样的情况:点击某图片,浏览某列表(某列表详情)中的所有图片数据,当然,这些图片是可以放大和缩小的,比如我们看下百度贴吧的浏览大图的效果:  链接 这种功能,在一些app ...

  2. ViewPager取消左右滑动切换功能

    ViewPager取消左右滑动切换功能 最近做项目要求某种情况下ViewPager不能滑动,那么我们只需要重写这个方法就可以禁止ViewPager滑动 IndexViewPager.java: imp ...

  3. Nginx 和 Apache 开启目录浏览功能

    1.Nginx 在相应项目的 Server 段中的 location 段中,添加 autoindex on.例如: server { listen ; server_name www.dee.prac ...

  4. Swipe to back not working滑动后退功能消失?

    如果你发现滑动后退功能突然失效了,很可能是因为你隐藏了NavigationBar 或者定制了 leftBarButtonItem(s) 这会导致 NavigationController 的 inte ...

  5. nginx和apache配置目录浏览功能

    今天工作需要,要给客户提供一个patch的下载地址,于是想用nginx的目录浏览功能来做,需要让客户看到指定一个目录下的文件列表,然后让他自己来选择该下载那个文件: 我们都知道在apache下可以配置 ...

  6. ViewPager撤消左右滑动切换功能

    ViewPager取消左右滑动切换功能 最近做项目要求某种情况下ViewPager不能滑动,那么我们只需要重写这个方法就可以禁止ViewPager滑动 IndexViewPager.java: imp ...

  7. iOS之手势滑动返回功能-b

    iOS中如果不自定义UINavigationBar,通过手势向右滑是可以实现返回的,这时左边的标题文字提示的是上一个ViewController的标题,如果需要把文字改为简约风格,例如弄过箭头返回啥的 ...

  8. 禁用ios7 手势滑动返回功能

    禁用ios7 手势滑动返回功能 版权声明:本文为博主原创文章,未经博主允许不得转载. 在有的时候,我们不需要手势返回功能,那么可以在页面中添加以下代码: - (void)viewDidAppear:( ...

  9. 自定义listView添加滑动删除功能

    今天研究了一下android里面的手势,结合昨天学习的自定义View,做了一个自定义的listview,继承自listView,添加了条目的滑动手势操作,滑动后出现一个删除按钮,点击删除按钮,触发一个 ...

随机推荐

  1. Java堆和栈详解

    Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...

  2. 【转】【C/C++】实现memcpy函数

    本文转自:http://my.oschina.net/renhc/blog/36345 面试中如问到memcpy的实现,那就要小心了,这里有陷阱. 先看下标准memcpy()的解释: ? 1 2 vo ...

  3. web.xml配置详情 - 简要介绍

    <!--web.xml 元素简介--> <?xml version="1.0" encoding="UTF-8"?><web-ap ...

  4. jquery.validate使用 - 自定义验证方法

    自定义jquery-validate的验证行为 1: 自定义表单提交 设置submitHandler来自定义表单提交动作 $(".selector").validate({    ...

  5. shell awk入门

    本文参考自 http://www.cnblogs.com/zhuyp1015/archive/2012/07/11/2586985.html awk:好用的数据处理工具 awk 也是一个非常棒的数据处 ...

  6. js获取url参数 兼容某些带#url

    网上有大把现成的代码,不过有点小小的瑕疵 例如目前最流行的 正则法: function getArgument(_arg) { var reg = new RegExp("(^|&) ...

  7. 根据多年经验整理的《互联网MySQL开发规范》

    一.基础规范 使用 INNODB 存储引擎 表字符集使用 UTF8  所有表都需要添加注释 单表数据量建议控制在 5000W 以内 不在数据库中存储图⽚.文件等大数据 禁止在线上做数据库压力测试 禁⽌ ...

  8. CodeForces 166B (凸包)

    求一个多边形是否完全在另一个凸多边形内. 乍一看,好像要判点在多边形内,但复杂度不允许,仔细一想,可以把两个多边形的点混起来求一个共同的凸包,如果共同的凸包依旧是原来凸包上的点,说明是. #inclu ...

  9. html,css,js加载顺序

    1.js放在head中会立即执行,阻塞后续的资源下载与执行.因为js有可能会修改dom,如果不阻塞后续的资源下载,dom的操作顺序不可控. 正常的网页加载流程是这样的. 浏览器一边下载HTML网页,一 ...

  10. Centos 7环境下编译mysql 5.7

    首先在编译之前,我们要了解相关mysql 5.7的编译选项,官网编译选项地址:http://dev.mysql.com/doc/refman/5.7/en/source-configuration-o ...