Android(安卓)L Settings实现
概述
Android L的settings界面实现和Android4.4版本有很大的不同,在Android L中,setting是使用dashboard等控件进行了重新实现。具体流程如下。
初始化流程
Android L Settings模块首界面为Settings,继承自SettingsActivity,而SettingsActivity继承自Activity。
首先看一下Settings.java代码,可以发现它没有重写任何SettingsActiviy的方法,也没有增加任何自己的方法,唯独增加了许多静态内部类,如:
/* * Settings subclasses for launching independently. */ public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ } public static class WirelessSettingsActivity extends SettingsActivity { /* empty */ } public static class SimSettingsActivity extends SettingsActivity { /* empty */ } // ......
看注释可以知道,这些子类是为了启动特定独立的Settings选项而创建的,例如在某个应用里需要设置蓝牙那么只需要启动 BluetoothSettingsActivity 就可以了。
所以,Settings模块的启动流程直接看SettingsActivity就行了。
SettingsActivity
onCreate方法是Activity的生命周期第一步,带注释的onCreate()源码如下:
@Override protected void onCreate(Bundle savedState) { super.onCreate(savedState); // 用来获取Activity的额外数据mFragmentClass,直接启动Settings模块不会获得这个数据 getMetaData(); final Intent intent = getIntent(); if (intent.hasExtra(EXTRA_UI_OPTIONS)) { getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0)); } mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE, Context.MODE_PRIVATE); // Getting Intent properties can only be done after the super.onCreate(...) final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT); mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) || intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false); final ComponentName cn = intent.getComponent(); final String className = cn.getClassName(); mIsShowingDashboard = className.equals(Settings.class.getName()); // This is a "Sub Settings" when: // - this is a real SubSettings // - or :settings:show_fragment_as_subsetting is passed to the Intent final boolean isSubSettings = className.equals(SubSettings.class.getName()) || intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false); // If this is a sub settings, then apply the SubSettings Theme for the ActionBar content insets if (isSubSettings) { // Check also that we are not a Theme Dialog as we don't want to override them final int themeResId = getThemeResId(); if (themeResId != R.style.Theme_DialogWhenLarge && themeResId != R.style.Theme_SubSettingsDialogWhenLarge) { setTheme(R.style.Theme_SubSettings); } } // 设置contentview setContentView(mIsShowingDashboard ? R.layout.settings_main_dashboard : R.layout.settings_main_prefs); // 获取framelayout控件 mContent = (ViewGroup) findViewById(R.id.main_content); getFragmentManager().addOnBackStackChangedListener(this); if (mIsShowingDashboard) { Index.getInstance(getApplicationContext()).update(); } if (savedState != null) { // We are restarting from a previous saved state; used that to initialize, instead // of starting fresh. mSearchMenuItemExpanded = savedState.getBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED); mSearchQuery = savedState.getString(SAVE_KEY_SEARCH_QUERY); setTitleFromIntent(intent); ArrayList<DashboardCategory> categories = savedState.getParcelableArrayList(SAVE_KEY_CATEGORIES); if (categories != null) { mCategories.clear(); mCategories.addAll(categories); setTitleFromBackStack(); } mDisplayHomeAsUpEnabled = savedState.getBoolean(SAVE_KEY_SHOW_HOME_AS_UP); mDisplaySearch = savedState.getBoolean(SAVE_KEY_SHOW_SEARCH); mHomeActivitiesCount = savedState.getInt(SAVE_KEY_HOME_ACTIVITIES_COUNT, 1 /* one home activity by default */); } else { // 第一次启动 if (!mIsShowingDashboard) { // Search is shown we are launched thru a Settings "shortcut". UP will be shown // only if it is a sub settings if (mIsShortcut) { mDisplayHomeAsUpEnabled = isSubSettings; mDisplaySearch = false; } else if (isSubSettings) { mDisplayHomeAsUpEnabled = true; mDisplaySearch = true; } else { mDisplayHomeAsUpEnabled = false; mDisplaySearch = false; } setTitleFromIntent(intent); Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS); switchToFragment(initialFragmentName, initialArguments, true, false, mInitialTitleResId, mInitialTitle, false); } else { // No UP affordance if we are displaying the main Dashboard mDisplayHomeAsUpEnabled = false; // Show Search affordance mDisplaySearch = true; mInitialTitleResId = R.string.dashboard_title; // 跳转到DashboardSummary,这是构造UI真正的地方 switchToFragment(DashboardSummary.class.getName(), null, false, false, mInitialTitleResId, mInitialTitle, false); } } mActionBar = getActionBar(); if (mActionBar != null) { mActionBar.setDisplayHomeAsUpEnabled(mDisplayHomeAsUpEnabled); mActionBar.setHomeButtonEnabled(mDisplayHomeAsUpEnabled); } mSwitchBar = (SwitchBar) findViewById(R.id.switch_bar); // see if we should show Back/Next buttons if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) { View buttonBar = findViewById(R.id.button_bar); if (buttonBar != null) { buttonBar.setVisibility(View.VISIBLE); Button backButton = (Button)findViewById(R.id.back_button); backButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { setResult(RESULT_CANCELED, getResultIntentData()); finish(); } }); Button skipButton = (Button)findViewById(R.id.skip_button); skipButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { setResult(RESULT_OK, getResultIntentData()); finish(); } }); mNextButton = (Button)findViewById(R.id.next_button); mNextButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { setResult(RESULT_OK, getResultIntentData()); finish(); } }); // set our various button parameters if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) { String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT); if (TextUtils.isEmpty(buttonText)) { mNextButton.setVisibility(View.GONE); } else { mNextButton.setText(buttonText); } } if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) { String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT); if (TextUtils.isEmpty(buttonText)) { backButton.setVisibility(View.GONE); } else { backButton.setText(buttonText); } } if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) { skipButton.setVisibility(View.VISIBLE); } } } mHomeActivitiesCount = getHomeActivitiesCount(); }
DashboardSummary
dashboard中文意思是仪表盘,这里是指DashboardSummary就是用来显示Settings所有选项的。而DashboardSummary是个Fragment,所以先执行了onCreateView方法。
在onCreateView中,就是inflate了一个View返回,这个view的布局如下:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/dashboard" android:layout_width="match_parent" android:layout_height="match_parent" <!-- 设置滑动那个bar的样式 --> android:scrollbarStyle="outsideOverlay" android:clipToPadding="false"> <LinearLayout android:id="@+id/dashboard_container" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal" android:paddingStart="@dimen/dashboard_padding_start" android:paddingEnd="@dimen/dashboard_padding_end" android:paddingTop="@dimen/dashboard_padding_top" android:paddingBottom="@dimen/dashboard_padding_bottom" android:orientation="vertical" /></ScrollView>
DashboardSummary走完onCreateView方法后会走onResume,onResume会通过handler发送一个消息来构建UI界面的方法rebuildUI,然后一路下来又会调用到SettingsActivity的loadCategoriesFromResource(R.xml.dashboard_categories, categories);
这个dashboard_categories.xml其实是布局的内容的抽象,通过这个xml文件解析出来能够填充每一项的资源内容。
小结
总结内容如下:
- onCreate完成的任务是切换DashboardSummary这个Fragment,然后从dashboard_categories.xml中读取预先配置好的文件来初始化Settings节目。
- AndroidL中舍弃了Header类,取而代之的是DashboardCategory和DashboardTile类。
UI修改
可以看出,如果我们想要改变Settings的UI,那我们主要需要改动如下几个自定义View和布局文件,分别是:
自定义view:
- DashboardContainerView
- DashboardTileView
布局文件:
- dashboard.xml,全局的xml布局文件。
- dashboard_category.xml,乘放tile的布局文件。
- dashboard_tile.xml,每个tile的布局文件。
更多相关文章
- android 没有root下实现软件自动更新的一些思路和方法
- Android(安卓)studio 3.0.1 莫名其妙 R报错啦!(check logs for det
- Android(安卓)开发建立经验分享...
- Android用Intent启动Activity的方法
- ProGuard惯用法
- android kill process 杀死进程的方法
- Android(安卓)自定义类库打包jar! 谁说不可以打包res 文件?
- Android关闭SdcardFS
- [Android]Fragment进行show和hide时候刷新数据