Android4.0设置界面修改总结

为什么80%的码农都做不了架构师?>>>   hot3.png

笔者前段时间完成设置的圆角item风格的修改,但最近,客户新增需求,想把设置做成Tab风格的,没办法,顾客就是上帝,咱得改啊。今天算是初步改完了,趁着测试紧张测试的空隙,赶紧写写博客,梳理一下,一来是给自己记个笔记,二来希望给有需要的朋友一点帮助。

修改主要是两个点:

①.圆角item的实现。

②.Tab风格的实现。


先来看看下面粗糙的效果图:


我们都知道,Android从3.0开始加入了Fragment,这大大的减少了Activity的使用,在4.0的设置中尤其发挥的淋漓尽致,几乎整个设置应用的一级、二级设置菜单就属于一个Activity即Settings.java。我们能看到不同的设置项,其实就是更换不同的Fragment,表面上是显得很简洁明了,但是修改起来还是有点蛋疼了,一点小改动就有可能牵扯一大部分功能,引起一堆bug。

  • 圆角item的实现:

其实这种圆角的item有两种类型,一种是一直都有的Preference,另外一种是从3.0开始添加的Header。比如设置的第一个主界面使用的就是Header(第一、二张图片所示),其二级、三级菜单就是Preference(第三张图片所示)了,不管是哪种类型,他们都是基于ListView实现的,理解了这个原理,修改起来就简单了,只用在ListView的Adapter的getView函数中,修改对应item项的背景图片即可。观察圆角item的背景图片我们可以发现,先要准备四种背景图片:顶部(上圆下方)、中间(上下都方)、底部(上方下圆)和单独(上下都圆)。

由于Header和Preference还是有一点区别的,Header使用频率没有Preference高,因此,我这里就没有在framework层修改Header,只是在需要用到的地方再修改。所以重点说一下Preference。

在源码中找到:frameworks/base/core/java/android/preference/PreferenceGroupAdapter.java,这个就是Preference的Adapter,首先声明4种类型的背景,然后通过计算得知那一项需要替换成对应的背景图片,最后在getView函数中,把对应的item的背景替换成我们需要的,下面是源码,加上liweiping标签的就是我的修改:

/** Copyright (C) 2007 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.*/package android.preference;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;import android.os.Handler;
import android.preference.Preference.OnPreferenceChangeInternalListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.BaseAdapter;
import android.widget.ListView;/*** An adapter that returns the {@link Preference} contained in this group.* In most cases, this adapter should be the base class for any custom* adapters from {@link Preference#getAdapter()}.* <p>* This adapter obeys the* {@link Preference}'s adapter rule (the* {@link Adapter#getView(int, View, ViewGroup)} should be used instead of* {@link Preference#getView(ViewGroup)} if a {@link Preference} has an* adapter via {@link Preference#getAdapter()}).* <p>* This adapter also propagates data change/invalidated notifications upward.* <p>* This adapter does not include this {@link PreferenceGroup} in the returned* adapter, use {@link PreferenceCategoryAdapter} instead.* * @see PreferenceCategoryAdapter*/
class PreferenceGroupAdapter extends BaseAdapter implements OnPreferenceChangeInternalListener {private static final String TAG = "PreferenceGroupAdapter";/*** The group that we are providing data from.*/private PreferenceGroup mPreferenceGroup;/*** Maps a position into this adapter -> {@link Preference}. These* {@link Preference}s don't have to be direct children of this* {@link PreferenceGroup}, they can be grand children or younger)*/private List<Preference> mPreferenceList;/*** List of unique Preference and its subclasses' names. This is used to find* out how many types of views this adapter can return. Once the count is* returned, this cannot be modified (since the ListView only checks the* count once--when the adapter is being set). We will not recycle views for* Preference subclasses seen after the count has been returned.*/private ArrayList<PreferenceLayout> mPreferenceLayouts;private PreferenceLayout mTempPreferenceLayout = new PreferenceLayout();/*** Blocks the mPreferenceClassNames from being changed anymore.*/private boolean mHasReturnedViewTypeCount = false;private volatile boolean mIsSyncing = false;private Handler mHandler = new Handler(); //start by liweiping 20130826private ArrayList<Integer> mPreferenceListBackgroundIndex;private final int SINGLE_LINE_ROUND_CORNER_BACKGROUND = 1;private final int TOP_ROUND_CORNER_BACKGROUND = 2;private final int BOTTOM_ROUND_CORNER_BACKGROUND = 3;private final int CENTER_RECTANGLE_BACKGROUND = 4;private final int NO_BACKGOUND = 5;//end by liweiping 20130826private Runnable mSyncRunnable = new Runnable() {public void run() {syncMyPreferences();}};private static class PreferenceLayout implements Comparable<PreferenceLayout> {private int resId;private int widgetResId;private String name;public int compareTo(PreferenceLayout other) {int compareNames = name.compareTo(other.name);if (compareNames == 0) {if (resId == other.resId) {if (widgetResId == other.widgetResId) {return 0;} else {return widgetResId - other.widgetResId;}} else {return resId - other.resId;}} else {return compareNames;}}}public PreferenceGroupAdapter(PreferenceGroup preferenceGroup) {mPreferenceGroup = preferenceGroup;// If this group gets or loses any children, let us knowmPreferenceGroup.setOnPreferenceChangeInternalListener(this);mPreferenceList = new ArrayList<Preference>();mPreferenceLayouts = new ArrayList<PreferenceLayout>();syncMyPreferences();}private void syncMyPreferences() {synchronized(this) {if (mIsSyncing) {return;}mIsSyncing = true;}List<Preference> newPreferenceList = new ArrayList<Preference>(mPreferenceList.size());mPreferenceListBackgroundIndex = new ArrayList<Integer>(mPreferenceList.size());//add by liweiping 20130826flattenPreferenceGroup(newPreferenceList, mPreferenceGroup);mPreferenceList = newPreferenceList;notifyDataSetChanged();synchronized(this) {mIsSyncing = false;notifyAll();}}private void flattenPreferenceGroup(List<Preference> preferences, PreferenceGroup group) {// TODO: shouldn't always?group.sortPreferences();final int groupSize = group.getPreferenceCount();final int[] tempIndexOfPrefrence  = calcItemsBetweenCategory(group);//add by liweiping 20130826for (int i = 0; i < groupSize; i++) {final Preference preference = group.getPreference(i);preferences.add(preference);//start by liweiping 20130826 if(tempIndexOfPrefrence[i] == 0){mPreferenceListBackgroundIndex.add(NO_BACKGOUND);} else if (tempIndexOfPrefrence[i] == 1&& (i == 0 ? true : tempIndexOfPrefrence[i - 1] <= 1)){if(i == (groupSize - 1) ? true	: tempIndexOfPrefrence[i + 1] <= 1){mPreferenceListBackgroundIndex.add(SINGLE_LINE_ROUND_CORNER_BACKGROUND);}else {mPreferenceListBackgroundIndex.add(TOP_ROUND_CORNER_BACKGROUND);}}else if(tempIndexOfPrefrence[i] > 1){if(i == (groupSize - 1) ? true	: tempIndexOfPrefrence[i + 1] <= 1){mPreferenceListBackgroundIndex.add(BOTTOM_ROUND_CORNER_BACKGROUND);}else {mPreferenceListBackgroundIndex.add(CENTER_RECTANGLE_BACKGROUND);}}//end by liweiping 20130826if (!mHasReturnedViewTypeCount && !preference.hasSpecifiedLayout()) {addPreferenceClassName(preference);}if (preference instanceof PreferenceGroup) {final PreferenceGroup preferenceAsGroup = (PreferenceGroup) preference;if (preferenceAsGroup.isOnSameScreenAsChildren()) {flattenPreferenceGroup(preferences, preferenceAsGroup);}}preference.setOnPreferenceChangeInternalListener(this);}}/*** Creates a string that includes the preference name, layout id and widget layout id.* If a particular preference type uses 2 different resources, they will be treated as* different view types.*/private PreferenceLayout createPreferenceLayout(Preference preference, PreferenceLayout in) {PreferenceLayout pl = in != null? in : new PreferenceLayout();pl.name = preference.getClass().getName();pl.resId = preference.getLayoutResource();pl.widgetResId = preference.getWidgetLayoutResource();return pl;}private void addPreferenceClassName(Preference preference) {final PreferenceLayout pl = createPreferenceLayout(preference, null);int insertPos = Collections.binarySearch(mPreferenceLayouts, pl);// Only insert if it doesn't exist (when it is negative).if (insertPos < 0) {// Convert to insert indexinsertPos = insertPos * -1 - 1;mPreferenceLayouts.add(insertPos, pl);}}public int getCount() {return mPreferenceList.size();}public Preference getItem(int position) {if (position < 0 || position >= getCount()) return null;return mPreferenceList.get(position);}public long getItemId(int position) {if (position < 0 || position >= getCount()) return ListView.INVALID_ROW_ID;return this.getItem(position).getId();}public View getView(int position, View convertView, ViewGroup parent) {final Preference preference = this.getItem(position);// 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) {convertView = null;}// start by liweiping 20130826            //return preference.getView(convertView, parent);View mView = preference.getView(convertView, parent);mView.setBackgroundResource(com.android.internal.R.color.transparent);if(mPreferenceListBackgroundIndex.get(position) == SINGLE_LINE_ROUND_CORNER_BACKGROUND){mView.setBackgroundResource(com.android.internal.R.drawable.easy_pref_item_single);}else if(mPreferenceListBackgroundIndex.get(position) == TOP_ROUND_CORNER_BACKGROUND){mView.setBackgroundResource(com.android.internal.R.drawable.easy_pref_item_top);}else if(mPreferenceListBackgroundIndex.get(position) == CENTER_RECTANGLE_BACKGROUND){mView.setBackgroundResource(com.android.internal.R.drawable.easy_pref_item_center);}else if(mPreferenceListBackgroundIndex.get(position) == BOTTOM_ROUND_CORNER_BACKGROUND){mView.setBackgroundResource(com.android.internal.R.drawable.easy_pref_item_bottom);}return mView;//end by liweiping 20130826}@Overridepublic boolean isEnabled(int position) {if (position < 0 || position >= getCount()) return true;return this.getItem(position).isSelectable();}@Overridepublic boolean areAllItemsEnabled() {// There should always be a preference group, and these groups are always// disabledreturn false;}public void onPreferenceChange(Preference preference) {notifyDataSetChanged();}public void onPreferenceHierarchyChange(Preference preference) {mHandler.removeCallbacks(mSyncRunnable);mHandler.post(mSyncRunnable);}@Overridepublic boolean hasStableIds() {return true;}@Overridepublic int getItemViewType(int position) {if (!mHasReturnedViewTypeCount) {mHasReturnedViewTypeCount = true;}final Preference preference = this.getItem(position);if (preference.hasSpecifiedLayout()) {return IGNORE_ITEM_VIEW_TYPE;}mTempPreferenceLayout = createPreferenceLayout(preference, mTempPreferenceLayout);int viewType = Collections.binarySearch(mPreferenceLayouts, mTempPreferenceLayout);if (viewType < 0) {// This is a class that was seen after we returned the count, so// don't recycle it.return IGNORE_ITEM_VIEW_TYPE;} else {return viewType;}}@Overridepublic int getViewTypeCount() {if (!mHasReturnedViewTypeCount) {mHasReturnedViewTypeCount = true;}return Math.max(1, mPreferenceLayouts.size());}//start by liweiping 20130826private int[] calcItemsBetweenCategory(PreferenceGroup group){final int groupSize = group.getPreferenceCount();int[] indexOfPreference = new int[groupSize];for (int i = 0; i < groupSize; i++) {final Preference preference = group.getPreference(i);if (preference instanceof PreferenceCategory) {indexOfPreference[i]  = 0 ;}else if(i == 0){indexOfPreference[i]  = 1 ;}else {indexOfPreference[i] = indexOfPreference[i - 1] + 1;}}return indexOfPreference;}//end by liweiping 20130826
}


  • tab风格的实现

tab风格的实现有两种方法,一种是传统的TabHost,另外一种就是从3.0开始的ActionBar中的tab,我最开始使用的就是TabHost,也大概实现了,但是最后的Bug让我头疼死了,因此果断放弃,选择了ActionBar的tab,其实一开始就应该选择这个的,由于笔者过度自信对TabHost的使用熟练度,因此结果就是不得不返工,浪费时间精力。其实用ActionBar的tab对代码的改动应该是最小的。下面来看看我修改过后的Settings.java的源码(我的修改也是打过liweiping标签的):

/** Copyright (C) 2008 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.*/package com.android.settings;import com.android.settings.accounts.AccountSyncSettings;
import com.android.settings.bluetooth.BluetoothEnabler;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.wifi.WifiEnabler;
//import static com.sprd.android.config.OptConfig.LC_RAM_SUPPORT;import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.ActionBar.TabListener;
import android.app.FragmentTransaction;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.SystemProperties;
import android.os.TopwiseProp;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.MenuItem;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Switch;
import android.widget.TextView;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;/*** Top-level settings activity to handle single pane and double pane UI layout.*/
public class Settings extends PreferenceActivity implements ButtonBarHandler {private static final String LOG_TAG = "Settings";private static final String META_DATA_KEY_HEADER_ID ="com.android.settings.TOP_LEVEL_HEADER_ID";private static final String META_DATA_KEY_FRAGMENT_CLASS ="com.android.settings.FRAGMENT_CLASS";private static final String META_DATA_KEY_PARENT_TITLE ="com.android.settings.PARENT_FRAGMENT_TITLE";private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS ="com.android.settings.PARENT_FRAGMENT_CLASS";private static final String EXTRA_CLEAR_UI_OPTIONS = "settings:remove_ui_options";private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";public static boolean UNIVERSEUI_SUPPORT = SystemProperties.getBoolean("universe_ui_support",false);private String mFragmentClass;private int mTopLevelHeaderId;private Header mFirstHeader;private Header mCurrentHeader;private Header mParentHeader;private boolean mInLocalHeaderSwitch;// TODO: Update Call Settings based on airplane mode state.protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();private List<Header> mHeaders;//start by liweiping 20140103private int mTabFlag;private static final int FLAG_TAB_WIRELESS_NETWORKS = 0;private static final int FLAG_TAB_DEVICE = 1;private static final int FLAG_TAB_PERSONAL = 2;private static final int FLAG_TAB_SYSTEM = 3;private final TabListener mTabListener = new TabListener() {@Overridepublic void onTabUnselected(Tab tab, FragmentTransaction ft) {// TODO Auto-generated method stub}@Overridepublic void onTabSelected(Tab tab, FragmentTransaction ft) {//Log.i("lwp-log", "tab.getContentDescription().toString() = "+tab.getContentDescription().toString());if (tab.getContentDescription().toString().equals(getResources().getString(R.string.header_category_wireless_networks))){mTabFlag = FLAG_TAB_WIRELESS_NETWORKS;}else if(tab.getContentDescription().toString().equals(getResources().getString(R.string.header_category_personal))) {mTabFlag = FLAG_TAB_PERSONAL;} else if (tab.getContentDescription().toString().equals(getResources().getString(R.string.header_category_system))) {mTabFlag = FLAG_TAB_SYSTEM;} else if (tab.getContentDescription().toString().equals(getResources().getString(R.string.header_category_device))) {mTabFlag = FLAG_TAB_DEVICE;}Log.i("lwp-log", "onTabSelected mTabFlag = " + mTabFlag); invalidateHeaders();}@Overridepublic void onTabReselected(Tab tab, FragmentTransaction ft) {}};private void setupWirelessNetworks(ActionBar bar) {final Tab tab = bar.newTab();View view = mInflater.inflate(R.layout.tab_widget_view, null);ImageView dialView =  (ImageView)view.findViewById(R.id.main_activity_tab_image);if(dialView != null){dialView.setImageResource(R.drawable.ic_tab_wireless);}TextView dialText = (TextView) view.findViewById(R.id.main_activity_tab_text);if(dialText!=null){dialText.setText(R.string.header_category_wireless_networks);}tab.setCustomView(view);tab.setTabListener(mTabListener);tab.setContentDescription(R.string.header_category_wireless_networks);bar.addTab(tab);}private void setupDevice(ActionBar bar) {final Tab tab = bar.newTab();View view = mInflater.inflate(R.layout.tab_widget_view, null);ImageView dialView =  (ImageView)view.findViewById(R.id.main_activity_tab_image);if(dialView != null){dialView.setImageResource(R.drawable.ic_tab_device);}TextView dialText = (TextView) view.findViewById(R.id.main_activity_tab_text);if(dialText!=null){dialText.setText(R.string.header_category_device);}tab.setCustomView(view);tab.setTabListener(mTabListener);tab.setContentDescription(R.string.header_category_device);bar.addTab(tab);}private void setupPersonal(ActionBar bar) {final Tab tab = bar.newTab();View view = mInflater.inflate(R.layout.tab_widget_view, null);ImageView dialView =  (ImageView)view.findViewById(R.id.main_activity_tab_image);if(dialView != null){dialView.setImageResource(R.drawable.ic_tab_personal);}TextView dialText = (TextView) view.findViewById(R.id.main_activity_tab_text);if(dialText!=null){dialText.setText(R.string.header_category_personal);}tab.setCustomView(view);tab.setTabListener(mTabListener);tab.setContentDescription(R.string.header_category_personal);bar.addTab(tab);}private void setupSystem(ActionBar bar) {final Tab tab = bar.newTab();View view = mInflater.inflate(R.layout.tab_widget_view, null);ImageView dialView =  (ImageView)view.findViewById(R.id.main_activity_tab_image);if(dialView != null){dialView.setImageResource(R.drawable.ic_tab_system);}TextView dialText = (TextView) view.findViewById(R.id.main_activity_tab_text);if(dialText!=null){dialText.setText(R.string.header_category_system);}tab.setCustomView(view);tab.setTabListener(mTabListener);tab.setContentDescription(R.string.header_category_system);bar.addTab(tab);}private LayoutInflater mInflater;//end by liweiping 20140103@Overrideprotected void onCreate(Bundle savedInstanceState) {if(UNIVERSEUI_SUPPORT){this.setTheme(R.style.Theme_Holo_new_ui);}if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) {getWindow().setUiOptions(0);}//start by liweiping 20140103setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);mInflater = getLayoutInflater();mTabFlag = FLAG_TAB_WIRELESS_NETWORKS;//end by liweiping 20140103getMetaData();mInLocalHeaderSwitch = true;super.onCreate(savedInstanceState);mInLocalHeaderSwitch = false;//For LowCost case, define the list selector by itself//  if (LC_RAM_SUPPORT) {//ListView list = getListView();//list.setSelector(R.drawable.list_selector_holo_dark);// list.setOverScrollMode(View.OVER_SCROLL_NEVER);//  }if (!onIsHidingHeaders() && onIsMultiPane()) {highlightHeader();// Force the title so that it doesn't get overridden by a direct launch of// a specific settings screen.setTitle(R.string.settings_label);}// Retrieve any saved stateif (savedInstanceState != null) {mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);}// If the current header was saved, switch to itif (savedInstanceState != null && mCurrentHeader != null) {//switchToHeaderLocal(mCurrentHeader);showBreadCrumbs(mCurrentHeader.title, null);}if (mParentHeader != null) {setParentTitle(mParentHeader.title, null, new OnClickListener() {public void onClick(View v) {switchToParent(mParentHeader.fragment);}});}}/* Set ActionBar with popup function */protected void setActionBarStyle() {ActionBar actionBar = getActionBar();if (actionBar == null){return;}//start by liweiping 20140106Log.i("lwp-log", "this.toString() = " + this.toString());//if ( this.toString().contains("SubSettings") ) {if ( this.toString().contains("SubSettings") || this.toString().contains("$")) {//end by liweiping 20140106actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);actionBar.setDisplayHomeAsUpEnabled(true);}else {actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP^ ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);actionBar.setDisplayHomeAsUpEnabled(false);//start by liweiping 20140103actionBar.setAlternativeTabStyle(true);actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);if(actionBar.getTabCount() == 0){setupWirelessNetworks(actionBar);setupDevice(actionBar);setupPersonal(actionBar);setupSystem(actionBar);}final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);mTabFlag = settings.getInt("tab", FLAG_TAB_WIRELESS_NETWORKS);Log.i("lwp-log", "setActionBarStyle mTabFlag = " + mTabFlag);actionBar.selectTab(actionBar.getTabAt(mTabFlag));//end by liweiping 20140103}}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// TODO Add support for android.R.id.home in all Setting's onOptionsItemSelected// getActionBar().setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP,// ActionBar.DISPLAY_HOME_AS_UP);// Now it's done.if (item.getItemId() == android.R.id.home) {finish();return true;}return super.onOptionsItemSelected(item);}@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);// Save the current fragment, if it is the same as originally launchedif (mCurrentHeader != null) {outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);}if (mParentHeader != null) {outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);}}@Overridepublic void onResume() {ListAdapter listAdapter = getListAdapter();if (listAdapter instanceof HeaderAdapter) {((HeaderAdapter) listAdapter).resume();}setActionBarStyle();super.onResume();}@Overridepublic void onPause() {super.onPause();ListAdapter listAdapter = getListAdapter();if (listAdapter instanceof HeaderAdapter) {((HeaderAdapter) listAdapter).pause();}//start by liweiping 20140106final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);settings.edit().putInt("tab", settings.getInt("tab", FLAG_TAB_WIRELESS_NETWORKS)).commit();//end by liweiping 20140106 }//start by liweiping 20140106@Overrideprotected void onDestroy() {super.onDestroy();//final SharedPreferences settings = PreferenceManager//      .getDefaultSharedPreferences(this);//settings.edit().putInt("tab", FLAG_TAB_WIRELESS_NETWORKS).commit();}//end by liweiping 20140106 @Overridepublic void onBackPressed() {if (!moveTaskToBack(false)) {super.onBackPressed();}}private void switchToHeaderLocal(Header header) {mInLocalHeaderSwitch = true;switchToHeader(header);mInLocalHeaderSwitch = false;}@Overridepublic void switchToHeader(Header header) {if (!mInLocalHeaderSwitch) {mCurrentHeader = null;mParentHeader = null;}super.switchToHeader(header);}/*** Switch to parent fragment and store the grand parent's info* @param className name of the activity wrapper for the parent fragment.*/private void switchToParent(String className) {final ComponentName cn = new ComponentName(this, className);try {final PackageManager pm = getPackageManager();final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);if (parentInfo != null && parentInfo.metaData != null) {String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);CharSequence fragmentTitle = parentInfo.loadLabel(pm);Header parentHeader = new Header();parentHeader.fragment = fragmentClass;parentHeader.title = fragmentTitle;mCurrentHeader = parentHeader;switchToHeaderLocal(parentHeader);highlightHeader();mParentHeader = new Header();mParentHeader.fragment= parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);}} catch (NameNotFoundException nnfe) {Log.w(LOG_TAG, "Could not find parent activity : " + className);}}@Overridepublic void onNewIntent(Intent intent) {super.onNewIntent(intent);// If it is not launched from history, then reset to top-levelif ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0&& mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {switchToHeaderLocal(mFirstHeader);}}private void highlightHeader() {if (mTopLevelHeaderId != 0) {Integer index = mHeaderIndexMap.get(mTopLevelHeaderId);if (index != null) {getListView().setItemChecked(index, true);getListView().smoothScrollToPosition(index);}}}@Overridepublic Intent getIntent() {Intent superIntent = super.getIntent();String startingFragment = getStartingFragmentClass(superIntent);// This is called from super.onCreate, isMultiPane() is not yet reliable// Do not use onIsHidingHeaders either, which relies itself on this methodif (startingFragment != null && !onIsMultiPane()) {Intent modIntent = new Intent(superIntent);modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);Bundle args = superIntent.getExtras();if (args != null) {args = new Bundle(args);} else {args = new Bundle();}args.putParcelable("intent", superIntent);modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());return modIntent;}return superIntent;}/*** Checks if the component name in the intent is different from the Settings class and* returns the class name to load as a fragment.*/protected String getStartingFragmentClass(Intent intent) {if (mFragmentClass != null) return mFragmentClass;String intentClass = intent.getComponent().getClassName();if (intentClass.equals(getClass().getName())) return null;if ("com.android.settings.ManageApplications".equals(intentClass)|| "com.android.settings.RunningServices".equals(intentClass)|| "com.android.settings.applications.StorageUse".equals(intentClass)) {// Old names of manage apps.intentClass = com.android.settings.applications.ManageApplications.class.getName();}return intentClass;}/*** Override initial header when an activity-alias is causing Settings to be launched* for a specific fragment encoded in the android:name parameter.*/@Overridepublic Header onGetInitialHeader() {String fragmentClass = getStartingFragmentClass(super.getIntent());if (fragmentClass != null) {Header header = new Header();header.fragment = fragmentClass;header.title = getTitle();header.fragmentArguments = getIntent().getExtras();mCurrentHeader = header;return header;}return mFirstHeader;}@Overridepublic Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,int titleRes, int shortTitleRes) {Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,titleRes, shortTitleRes);// some fragments want to avoid split actionbarif (DataUsageSummary.class.getName().equals(fragmentName) ||PowerUsageSummary.class.getName().equals(fragmentName) ||AccountSyncSettings.class.getName().equals(fragmentName) ||UserDictionarySettings.class.getName().equals(fragmentName)) {intent.putExtra(EXTRA_CLEAR_UI_OPTIONS, true);}intent.setClass(this, SubSettings.class);return intent;}/*** Populate the activity with the top-level headers.*/@Overridepublic void onBuildHeaders(List<Header> headers) {//start by liweiping 20130103//if(UNIVERSEUI_SUPPORT){//    loadHeadersFromResource(R.xml.settings_headers_uui, headers);//}else{//    loadHeadersFromResource(R.xml.settings_headers, headers);//}Log.i("lwp", "mTabFlag = "+mTabFlag + ", headers.size() = "+ headers.size() );if (mTabFlag == FLAG_TAB_WIRELESS_NETWORKS){loadHeadersFromResource(R.xml.settings_headers_wireless_networks, headers);}else if(mTabFlag == FLAG_TAB_DEVICE){loadHeadersFromResource(R.xml.settings_headers_device, headers);}else if(mTabFlag == FLAG_TAB_PERSONAL){loadHeadersFromResource(R.xml.settings_headers_personal, headers);}else{loadHeadersFromResource(R.xml.settings_headers_system, headers);}//end by liweiping 20130103updateHeaderList(headers);//start by liweiping 20130107 for bug 1146//mHeaders = headers;if(mHeaders != null){mHeaders.clear();mHeaders.addAll(headers);}//end by liweiping 20130107}private void updateHeaderList(List<Header> target) {int i = 0;while (i < target.size()) {Header header = target.get(i);// Ids are integers, so downcastingint id = (int) header.id;if (id == R.id.dock_settings) {if (!needsDockSettings())target.remove(header);} else if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);} else if (id == R.id.wifi_settings) {// Remove WiFi Settings if WiFi service is not available.// modified by zhangguixin// if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {if (!SystemProperties.getBoolean("ro.device.support.wifi", true)) {// if ("0".equals(SystemProperties.getBoolean("ro.device.support.wifi", "1"))) {target.remove(header);}} else if (id == R.id.bluetooth_settings) {// Remove Bluetooth Settings if Bluetooth service is not available.// modified by zhangguixin// if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {if (!SystemProperties.getBoolean("ro.device.support.bt", true)) {// if ("0".equals(SystemProperties.getBoolean("ro.device.support.bt", "1"))) {target.remove(header);}} else if (id == R.id.dual_sim_settings) {if (!TelephonyManager.isMultiSim()) {target.remove(header);}} else if (id == R.id.data_usage_settings &&"sc8825".equalsIgnoreCase(SystemProperties.get("ro.board.platform", "sc8825"))) {//fix bug182500target.remove(header);}//add by huangweiwei, topwise, 2013-10-12else if (id == R.id.development_settings) {if (android.os.TopwiseProp.getDefaultSettingBoolean("settings_remove_development", false)) {target.remove(header);}}//add end by huangweiwei, topwise, 2013-10-12// Increment if the current one wasn't removed by the Utils code.if (target.get(i) == header) {// Hold on to the first header, when we need to reset to the top-levelif (mFirstHeader == null &&HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {mFirstHeader = header;}mHeaderIndexMap.put(id, i);i++;}}}private boolean needsDockSettings() {return getResources().getBoolean(R.bool.has_dock_settings);}private void getMetaData() {try {ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),PackageManager.GET_META_DATA);if (ai == null || ai.metaData == null) return;mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);// Check if it has a parent specified and create a Header objectfinal int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);if (parentFragmentClass != null) {mParentHeader = new Header();mParentHeader.fragment = parentFragmentClass;if (parentHeaderTitleRes != 0) {mParentHeader.title = getResources().getString(parentHeaderTitleRes);}}} catch (NameNotFoundException nnfe) {// No recovery}}@Overridepublic boolean hasNextButton() {return super.hasNextButton();}@Overridepublic Button getNextButton() {return super.getNextButton();}private static class HeaderAdapter extends ArrayAdapter<Header> {static final int HEADER_TYPE_CATEGORY = 0;static final int HEADER_TYPE_NORMAL = 1;static final int HEADER_TYPE_SWITCH = 2;private static final int HEADER_TYPE_COUNT = HEADER_TYPE_SWITCH + 1;private final WifiEnabler mWifiEnabler;private final BluetoothEnabler mBluetoothEnabler;private SparseArray<View> mViewCache;private static class HeaderViewHolder {ImageView icon;TextView title;TextView summary;Switch switch_;}private LayoutInflater mInflater;static int getHeaderType(Header header) {if (header.fragment == null && header.intent == null) {return HEADER_TYPE_CATEGORY;} else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {return HEADER_TYPE_SWITCH;} else {return HEADER_TYPE_NORMAL;}}@Overridepublic int getItemViewType(int position) {Header header = getItem(position);return getHeaderType(header);}//start by liweiping 20140106@Overridepublic void notifyDataSetChanged() {// TODO Auto-generated method stubsuper.notifyDataSetChanged();mViewCache = new SparseArray<View>(getCount());}//end by liweiping 20140106@Overridepublic boolean areAllItemsEnabled() {return false; // because of categories}@Overridepublic boolean isEnabled(int position) {return getItemViewType(position) != HEADER_TYPE_CATEGORY;}@Overridepublic int getViewTypeCount() {return HEADER_TYPE_COUNT;}@Overridepublic boolean hasStableIds() {return true;}public HeaderAdapter(Context context, List<Header> objects) {super(context, 0, objects);mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);// Temp Switches provided as placeholder until the adapter replaces these with actual// Switches inflated from their layouts. Must be done before adapter is set in supermWifiEnabler = new WifiEnabler(context, new Switch(context));mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));mViewCache = new SparseArray<View>(objects.size());}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {HeaderViewHolder holder;Header header = getItem(position);int headerType = getHeaderType(header);View view = null;convertView = mViewCache.get(position);if (convertView == null) {holder = new HeaderViewHolder();switch (headerType) {case HEADER_TYPE_CATEGORY:view = new TextView(getContext(), null,android.R.attr.listSeparatorTextViewStyle);holder.title = (TextView) view;break;case HEADER_TYPE_SWITCH:view = mInflater.inflate(R.layout.preference_header_switch_item, parent,false);holder.icon = (ImageView) view.findViewById(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);holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);break;case HEADER_TYPE_NORMAL:view = mInflater.inflate(com.android.internal.R.layout.preference_header_item, parent,false);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);break;}view.setBackgroundDrawable(null);view.setTag(holder);mViewCache.put(position, view);} else {view = convertView;holder = (HeaderViewHolder) view.getTag();return view;}// All view fields must be updated every time, because the view may be recycledswitch (headerType) {case HEADER_TYPE_CATEGORY:holder.title.setText(header.getTitle(getContext().getResources()));holder.title.setTextColor(android.R.color.transparent);//add by liweiping 20130826break;case HEADER_TYPE_SWITCH:// Would need a different treatment if the main menu had more switchesif (header.id == R.id.wifi_settings) {mWifiEnabler.setSwitch(holder.switch_);} else {mBluetoothEnabler.setSwitch(holder.switch_);}// No break, fall through on purpose to update common fields//$FALL-THROUGH$case HEADER_TYPE_NORMAL:holder.icon.setImageResource(header.iconRes);holder.title.setText(header.getTitle(getContext().getResources()));CharSequence summary = header.getSummary(getContext().getResources());if (!TextUtils.isEmpty(summary)) {holder.summary.setVisibility(View.VISIBLE);holder.summary.setText(summary);} else {holder.summary.setVisibility(View.GONE);}break;}//start by liweiping 20130826if (header.fragment == null && header.intent == null) {view.setBackgroundColor(android.R.color.transparent); }else if(header.id == R.id.dual_sim_settings || header.id == R.id.sound_settings || header.id == R.id.sync_settings || header.id == R.id.dock_settings || header.id == R.id.date_time_settings){view.setBackgroundResource(com.android.internal.R.drawable.easy_pref_item_top);}else if(header.id == R.id.wireless_settings || header.id == R.id.manufacturer_settings || header.id == R.id.privacy_settings || header.id == R.id.about_settings || header.id == R.id.application_settings){view.setBackgroundResource(com.android.internal.R.drawable.easy_pref_item_bottom);}else {view.setBackgroundResource(com.android.internal.R.drawable.easy_pref_item_center);}//end by liweiping 20130826return view;}public void resume() {mWifiEnabler.resume();mBluetoothEnabler.resume();}public void pause() {mWifiEnabler.pause();mBluetoothEnabler.pause();}}@Overridepublic boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {// Override the fragment title for Wallpaper settingsint titleRes = pref.getTitleRes();if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {titleRes = R.string.wallpaper_settings_fragment_title;}startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, null, null, 0);return true;}//start,added by topwise hehuadong in 2013.10.24@Overridepublic void onHeaderClick(Header header, int position) {// TODO Auto-generated method stub//start by liweiping 20140105final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);settings.edit().putInt("tab", mTabFlag).commit();Log.i("lwp-log", "onHeaderClick..." + settings.getInt("tab", -1));//end by liweiping 20140105if (TopwiseProp.getDefaultSettingString("default_customize_about_device")!=null){if (header != null && header.fragment !=null && header.fragment.equals("com.android.settings.DeviceInfoSettings")){header.fragment="com.android.settings.AboutDeviceSettings";}}super.onHeaderClick(header, position);}//end,added by topwise hehuadong in 2013.10.24@Overridepublic void setListAdapter(ListAdapter adapter) {if (mHeaders == null) {mHeaders = new ArrayList<Header>();// When the saved state provides the list of headers, onBuildHeaders is not called// Copy the list of Headers from the adapter, preserving their orderfor (int i = 0; i < adapter.getCount(); i++) {mHeaders.add((Header) adapter.getItem(i));}}// Ignore the adapter provided by PreferenceActivity and substitute ours insteadsuper.setListAdapter(new HeaderAdapter(this, mHeaders));}/** Settings subclasses for launching independently.*/public static class BluetoothSettingsActivity extends Settings { /* empty */ }public static class WirelessSettingsActivity extends Settings { /* empty */ }public static class TetherSettingsActivity extends Settings { /* empty */ }public static class VpnSettingsActivity extends Settings { /* empty */ }public static class DateTimeSettingsActivity extends Settings { /* empty */ }public static class StorageSettingsActivity extends Settings { /* empty */ }public static class WifiSettingsActivity extends Settings { /* empty */ }public static class WifiP2pSettingsActivity extends Settings { /* empty */ }public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }public static class LocalePickerActivity extends Settings { /* empty */ }public static class UserDictionarySettingsActivity extends Settings { /* empty */ }public static class SoundSettingsActivity extends Settings { /* empty */ }public static class DisplaySettingsActivity extends Settings { /* empty */ }public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }public static class ApplicationSettingsActivity extends Settings { /* empty */ }public static class ManageApplicationsActivity extends Settings { /* empty */ }public static class StorageUseActivity extends Settings { /* empty */ }public static class DevelopmentSettingsActivity extends Settings { /* empty */ }public static class AccessibilitySettingsActivity extends Settings { /* empty */ }public static class SecuritySettingsActivity extends Settings { /* empty */ }public static class LocationSettingsActivity extends Settings { /* empty */ }public static class PrivacySettingsActivity extends Settings { /* empty */ }public static class DockSettingsActivity extends Settings { /* empty */ }public static class RunningServicesActivity extends Settings { /* empty */ }public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }public static class PowerUsageSummaryActivity extends Settings { /* empty */ }public static class AccountSyncSettingsActivity extends Settings { /* empty */ }public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }public static class DataUsageSummaryActivity extends Settings { /* empty */ }public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
}

简单分析一下:

①.首先我们在onResume中找到setActionBarStyle这个函数,这就是设置每次恢复时的必经之路,在这里,我们改变ActionBar的样式,如果是一级界面,就加上tab风格,二级界面就去掉tab风格,显示返回键。

/* Set ActionBar with popup function */protected void setActionBarStyle() {ActionBar actionBar = getActionBar();if (actionBar == null){return;}//start by liweiping 20140106Log.i("lwp-log", "this.toString() = " + this.toString());//if ( this.toString().contains("SubSettings") ) {if ( this.toString().contains("SubSettings") || this.toString().contains("$")) {//end by liweiping 20140106actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);actionBar.setDisplayHomeAsUpEnabled(true);}else {actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP^ ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);actionBar.setDisplayHomeAsUpEnabled(false);//start by liweiping 20140103actionBar.setAlternativeTabStyle(true);actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);if(actionBar.getTabCount() == 0){setupWirelessNetworks(actionBar);setupDevice(actionBar);setupPersonal(actionBar);setupSystem(actionBar);}final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);mTabFlag = settings.getInt("tab", FLAG_TAB_WIRELESS_NETWORKS);Log.i("lwp-log", "setActionBarStyle mTabFlag = " + mTabFlag);actionBar.selectTab(actionBar.getTabAt(mTabFlag));//end by liweiping 20140103}}

②.监听tab的选择事件,点击每一个tab产生对应的事件,然后把选择项存为全局变量mTabFlag中,最后调用invalidateHeaders()函数刷新界面,替换成不同的Header list。

private final TabListener mTabListener = new TabListener() {@Overridepublic void onTabUnselected(Tab tab, FragmentTransaction ft) {// TODO Auto-generated method stub}@Overridepublic void onTabSelected(Tab tab, FragmentTransaction ft) {//Log.i("lwp-log", "tab.getContentDescription().toString() = "+tab.getContentDescription().toString());if (tab.getContentDescription().toString().equals(getResources().getString(R.string.header_category_wireless_networks))){mTabFlag = FLAG_TAB_WIRELESS_NETWORKS;}else if(tab.getContentDescription().toString().equals(getResources().getString(R.string.header_category_personal))) {mTabFlag = FLAG_TAB_PERSONAL;} else if (tab.getContentDescription().toString().equals(getResources().getString(R.string.header_category_system))) {mTabFlag = FLAG_TAB_SYSTEM;} else if (tab.getContentDescription().toString().equals(getResources().getString(R.string.header_category_device))) {mTabFlag = FLAG_TAB_DEVICE;}Log.i("lwp-log", "onTabSelected mTabFlag = " + mTabFlag);invalidateHeaders();}@Overridepublic void onTabReselected(Tab tab, FragmentTransaction ft) {}};

③.当调用invalidateHeaders()函数时,就进入了onBuildHeaders(List<Header> headers)函数,在这里,我们需要根据mTabFlag来loadHeadersFromResource对应的布局文件,最后一定要记住用新的headers将全局变量mHeaders替换掉。

/*** Populate the activity with the top-level headers.*/@Overridepublic void onBuildHeaders(List<Header> headers) {//start by liweiping 20130103//if(UNIVERSEUI_SUPPORT){//    loadHeadersFromResource(R.xml.settings_headers_uui, headers);//}else{//    loadHeadersFromResource(R.xml.settings_headers, headers);//}Log.i("lwp", "mTabFlag = "+mTabFlag + ", headers.size() = "+ headers.size() );if (mTabFlag == FLAG_TAB_WIRELESS_NETWORKS){loadHeadersFromResource(R.xml.settings_headers_wireless_networks, headers);}else if(mTabFlag == FLAG_TAB_DEVICE){loadHeadersFromResource(R.xml.settings_headers_device, headers);}else if(mTabFlag == FLAG_TAB_PERSONAL){loadHeadersFromResource(R.xml.settings_headers_personal, headers);}else{loadHeadersFromResource(R.xml.settings_headers_system, headers);}//end by liweiping 20130103updateHeaderList(headers);//start by liweiping 20130107 for bug 1146//mHeaders = headers;if(mHeaders != null){mHeaders.clear();mHeaders.addAll(headers);}//end by liweiping 20130107}

OK,今天就大概这样了。


转载于:https://my.oschina.net/cjkall/blog/195789

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/536390.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android之仿网易V3.5新特性

为什么80%的码农都做不了架构师&#xff1f;>>> 最近&#xff0c;网易新闻更新到V3.5了&#xff0c;给我印象最深的是第一次进应用时显示新特性的ViewPager变成垂直滑动了。于是&#xff0c;小小的模仿了一下&#xff0c;我们来看看效果&#xff1a; 本文源码下载地…

Android_内存泄露

2019独角兽企业重金招聘Python工程师标准>>> 1.资源对象没关闭造成的内存泄漏 描述&#xff1a; 资源性对象比如&#xff08;Cursor&#xff0c;File文件等&#xff09;往往都用了一些缓冲&#xff0c;我们在不使用的时候&#xff0c;应该及时关闭它们&#xff0c;以…

CYQ.Data 轻量数据层之路 使用篇三曲 MAction 取值赋值(十四)

2019独角兽企业重金招聘Python工程师标准>>> 上一篇&#xff1a;CYQ.Data 轻量数据层之路 使用篇二曲 MAction 数据查询(十三&#xff09; 内容概要 本篇继续上一篇内容&#xff0c;本节介绍所有取值与赋值的相关操作。1&#xff1a;原生&#xff1a;像操作Row一样…

CYQ.Data 数据框架 发放V1.5版本源码

2019独角兽企业重金招聘Python工程师标准>>> 本篇的内容很简单&#xff0c;就发放V1.5版本源码&#xff0c;同时补充了所有发布版本的API文档。 具体相关下载地址见&#xff1a; 秋色园下载中心&#xff1a;http://www.cyqdata.com/download/article-detail-426 如何…

爱说说技术原理:与TXT交互及MDataTable对Json的功能扩展(二)

2019独角兽企业重金招聘Python工程师标准>>> 关于爱说说在技术选型的文章见&#xff1a;"爱说说"技术原理方案的定选思考过程 本篇将讲述“爱说说”比较重大的技术问题点及解决手段&#xff1a; 爱说说&#xff1a;http://speak.cyqdata.com/ 杂说几句&am…

如何制作VSPackage的安装程序

2019独角兽企业重金招聘Python工程师标准>>> 第一步&#xff0c;生成一个REG文件&#xff1a; 收钱进入目录: C:\Program Files\Microsoft Visual Studio 2008 SDK\VisualStudioIntegration\Tools\Bin 这是SDK的目录&#xff0c;使用regpkg.exe 命令 命令格式为: …

MyBatis学习总结(1)——MyBatis快速入门

2019独角兽企业重金招聘Python工程师标准>>> 一、Mybatis介绍 MyBatis是一个支持普通SQL查询&#xff0c;存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和…

MyEclipse+Tomcat+MAVEN+SVN项目完整环境搭建

2019独角兽企业重金招聘Python工程师标准>>> 这次换了台电脑&#xff0c;所以需要重新配置一次项目开发环境&#xff0c;过程中的种种&#xff0c;记录下来&#xff0c;便于以后再次安装&#xff0c;同时给大家一个参考。 1.JDK的安装 首先下载JDK&#xff0c;这个从…

Java基础学习总结(10)——static关键字

2019独角兽企业重金招聘Python工程师标准>>> 一、static关键字 原来一个类里面的成员变量&#xff0c;每new一个对象&#xff0c;这个对象就有一份自己的成员变量&#xff0c;因为这些成员变量都不是静态成员变量。对于static成员变量来说&#xff0c;这个成员变量只…

ActiveMQ学习总结(3)——spring整合ActiveMQ

2019独角兽企业重金招聘Python工程师标准>>> 1.参考文献 Spring集成ActiveMQ配置Spring JMS异步发收消息 ActiveMQ2.环境 在前面的一篇 ActiveMQ入门实例中我们实现了消息的异步传送&#xff0c;这篇博文将如何在spring环境下集成ActiveMQ。如果要在spring下集成Act…

堆树

一、堆树的定义 堆树的定义如下&#xff1a; &#xff08;1&#xff09;堆树是一颗完全二叉树&#xff1b; &#xff08;2&#xff09;堆树中某个节点的值总是不大于或不小于其孩子节点的值&#xff1b; &#xff08;3&#xff09;堆树中每个节点的子树都是堆树。 当父节点的键…

问题 G: 区间权值

问题 G: 区间权值 时间限制: 1 Sec 内存限制: 128 MB 提交: 112 解决: 49 [提交] [状态] [讨论版] [命题人:admin] 题目描述 小Bo有n个正整数a1..an&#xff0c;以及一个权值序列w1…wn&#xff0c;现在他定义 现在他想知道的值&#xff0c;需要你来帮帮他 你只需要输出答案…

步步为营 SharePoint 开发学习笔记系列 七、SharePoint Timer Job 开发

概要 项目需求要求我们每天晚上同步员工的一些信息到sharepoint 的user List &#xff0c;我们决定定制开发sharepoint timer Job,Sharepoint timer Job是sharePoint的定时作业Job,需要安装、布曙到服务器上,而这里我只是介绍下Job开发的例子&#xff0c;以供大家学习用。 开发…

windows下jenkins常见问题填坑

没有什么高深的东西&#xff0c;1 2天的时间大多数人都能自己摸索出来&#xff0c;这里将自己遇到过的问题分享出来避免其他同学再一次挖坑. 目录 1. 主从节点 2. Nuget自动包还原 3. powershell部署 4. 内网机器实现基于变化的构建 5. Github私有项目pull时限 所谓主从&#x…

HTTP首部(1)

1、报文首部 HTTP协议的请求和响应必定包含HTTP首部&#xff0c;它包括了客户端和服务端分别处理请求和响应提供所需要的信息。报文主体字儿是所需要的用户和资源的信息都在这边。  HTTP请求报文组成 方法&#xff0c;URL&#xff0c;HTTP版本&#xff0c;HTTP首部字段 HTTP响…

XMLHttpRequest+WebForm模式(接口IHttpHandler)实现ajax

首先引入ajax.js文件 创建xmlhttpRequest对象 Code//创建XMLHttpRequest对象var xmlHttp;function newXMLHttpRequest() { if (window.XMLHttpRequest) { xmlHttp new XMLHttpRequest(); } else if (window.ActiveXObject) { try { xmlHttp …

IIS 5 与IIS 6 原理介绍

[ 转] ASP.NET Process Model之一&#xff1a;IIS 和 ASP.NET ISAPI 前几天有一个朋友在MSN上问我“ASP.NET 从最初的接收到Http request到最终生成Response的整个流程到底是怎样的&#xff1f;”我觉得这个问题涉及到IIS和ASP.NETASP.NET Runtime的处理模型的问题&#xff0c;…

SharePoint v3:忘掉模拟用户Impersonate,SPSecurity.RunWithElevatedPrivileges来了

回顾&#xff1a; 在SharePoint V2 大家应该都用过模拟用户Impersonate这个功能&#xff0c; 这个功能用来暂时提升某个用户的权限&#xff0c;比如某个普通用户的本来不能修改某个列表的值&#xff0c;但是我们功能需要在修改。 缺点&#xff1a; 我们使用这个模拟用户功能…

螺旋方阵问题【数组】

输入n&#xff0c;输出n阶螺旋方阵&#xff0c;下面为5阶螺旋方阵&#xff1a;1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9 下面为我的代码&#xff1a; #include <cstdio> #include <iostream> #include &…

马鞍点问题【数组】

如果在一矩阵中元素A[i][j]满足A[i][j]为第i行的最小值&#xff0c;第j行的最大值&#xff0c;则称这个元素为这个矩阵的马鞍点&#xff0c;求m*n矩阵所有的马鞍点。若需求一个矩阵的所有马鞍点&#xff0c;其实只需将矩阵的每行的最小值与每列的最大值分别求出存在相应的数组中…