当前位置:  编程技术>移动开发
本页文章导读:
    ▪activity,view,window,windowmanager代码阅览总结及相互关系        activity,view,window,windowmanager代码阅读总结及相互关系 ActivityThread类:performLaunchActivity函数: activity.attach(appContext, this, getInstrumentation(), r.token,                        r.ident, app, r.intent.........
    ▪ 移动互联-早下8、9点钟的太阳 <论We7.Mobi手机网站&gt        移动互联--早上8、9点钟的太阳 <论We7.Mobi手机网站> 此文章由于有表格和图片,请直接查看附件! ......
    ▪ PreferenceActivity UI 优化批改       PreferenceActivity UI 优化修改  虽然PreferenceActivity的UI比较搓,但是由于其良好的封装性和实用性,所以在一些场景还是有一定的使用价值。所以如何能优化它的UI让它和你程序相配就十分必要了.........

[1]activity,view,window,windowmanager代码阅览总结及相互关系
    来源: 互联网  发布时间: 2014-02-18
activity,view,window,windowmanager代码阅读总结及相互关系
ActivityThread类:performLaunchActivity函数:
activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstance,
                        r.lastNonConfigurationChildInstances, config);
Activity类中的attach方法:
//创建新的window,与Activity相关联,在android2.2以下以及2.2版本返回的是MidWindow,但是sdk类库中包含PhoneWindow,2.2版本以上删除了MidWindow类,使用的是PhoneWindow。这两个类都是继承自Window,因此可以认为两个类是相同的。
mWindow = PolicyManager.makeNewWindow(this);
***省略操作
//创建一个与window相关的WindowManager,由于Activity类中使用的setManager方法传递的WindowManager参数为null,因此在Window类中使用WindowManager变量是同一个对象。
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
//从Window类的setWindowManager方法可以知道Activity的WindowManager是一个//LocalWindowManager
mWindowManager = mWindow.getWindowManager();
Window类的setWindowManager方法:
public void setWindowManager(WindowManager wm, IBinder appToken,
String appName) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
//使用WindowManager的变量来创建LocalWindowManager
mWindowManager = new LocalWindowManager(wm);
}

private class LocalWindowManager implements WindowManager {
LocalWindowManager(WindowManager wm) {
mWindowManager = wm;
mDefaultDisplay = mContext.getResources().getDefaultDisplay(
mWindowManager.getDefaultDisplay());
}
public final void addView(View view, ViewGroup.LayoutParams params) {
****
View decor = peekDecorView();
****
mWindowManager.addView(***);
}
*********
}
Window类的peekDecorView()方法,获取当前的Decor View
public abstract View peekDecorView();
获取顶层窗口decor view(包含了标准窗口)可以作为window添加到window manager。
public abstract View getDecorView();
这两个函数在PhoneWindow中被实现。
在WindowImpl类中:
public static WindowManagerImpl getDefault() {
return mWindowManager;
}
private static WindowManagerImpl mWindowManager = new WindowManagerImpl();
因此通过getDefault()方法返回的WindowManagerImpl是同一个对象。

addView方法,将View保存到数组中,并设置View的root信息:
private void addView(View view, ViewGroup.LayoutParams params, boolean nest) {
****
ViewRoot root;
View panelParentView = null;
****
root = new ViewRoot(view.getContext());
****
mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
****
root.setView(view, wparams, panelParentView);
}

PhoneWindow继承了Window,实现了Window中的所有虚函数。
    // This is the top-level view of the window, containing the window decor.
    // 窗口的顶层View
    private DecorView mDecor;

    // This is the view in which the window contents are placed. It is either
    // mDecor itself, or a child of mDecor where the contents go.
    // 放置窗口内容的View,或者是mDecor或者mDecor的子View用来放置内容,对应于ID为com.android.internal.R.id.content的FramLayout。
    private ViewGroup mContentParent;
    //设置view
    @Override
    public void setContentView(int layoutResID) {
//判断contentParent是否为null,如果为null则需要installDecor,否则需要清空原来已经填充的view
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
//inflate xml并设置父view为mContentParent,初次设置view
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null) {
            cb.onContentChanged();
        }
    }

    @Override
    public void setContentView(View view) {
        setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
//判断contentParent是否为null,如果为null则需要installDecor,否则需要清空原来已经填充的view
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
//给mContentParent增加view
        mContentParent.addView(view, params);
        final Callback cb = getCallback();
        if (cb != null) {
            cb.onContentChanged();
        }
    }
private void installDecor() {
//生成mDecor
        if (mDecor == null) {
            mDecor = generateDecor();
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
        }
        if (mContentParent == null) {
    //生成mContentParent
            mContentParent = generateLayout(mDecor);

            mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
            ****设置标题栏信息
        }
}

   //使用DecorView作为参数创建mContentParent,并设置mDecor将mContentParent添加为子view
   //mContentParent对应于id为content的framlayout可以参考代码中提供的window布局文件,以及使用的findViewById函数的参数。
   protected ViewGroup generateLayout(DecorView decor) {
设置flags
        WindowManager.LayoutParams params = getAttributes();
设置params
        // Inflate the window decor.
        int layoutResource;
        int features = getLocalFeatures();
        获取整个屏幕对应的layout资源id
        mDecor.startChanging();
//根据使用的资源不同,显示出来的布局也不同,可以参考sdk下的platforms/android-*/data/res/layout/screen*.xml或dialog*.xml
        View in = mLayoutInflater.inflate(layoutResource, null);
//将整个屏幕对应的view作为decor子view,并设置布局参数为铺满整个屏幕(match_parent)
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        //找到id为content的framlayout,由于使用的资源不同,所以content不一定为mDecor的直接子View。使用的findViewById是mDecor的方法,
//由于已经将屏幕View加为mDecor的子View,因此mContentParent也是mDecor的子View
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
设置mDecor的背景和标题
        mDecor.finishChanging();
        return contentParent;
   }
   //从本质上来讲Decor为一个FramLayout
   private final class DecorView extends FrameLayout {
  ***省略各种操作
   }

Activity在onCreate之前调用attach方法,在attach方法中会创建window对象。window对象创建时并没有创建 Decor对象对象。用户在Activity中调用setContentView,然后调用window的setContentView,这时会检查 DecorView是否存在,如果不存在则创建DecorView对象,然后把用户自己的View 添加到DecorView中。
在ActivityThread函数中:

ActivityThread.java中调用wm.addView(decor, l);把它加入到window manager proxy的mViews中,同时为这个decor view创建一个ViewRoot,ViewRoot负责协调decor view与window manager直接绘图、事件处理。
ViewRoot中有IWindowSession和IWindow用来和window manger打交道和接收window manager传过来的消息,消息传过来后ViewRoot分发给decor view,再由decor view进行分发

windowManager创建和使用流程:
创建:
1、Activity的attach方法中:
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
2、Window的setWindowManager方法,会返回一个LocalWindowManager对象:
if (wm == null) {
//调用WindowManagerImpl的getDefault方法
wm = WindowManagerImpl.getDefault();
}
//使用WindowManager的变量来创建LocalWindowManager
mWindowManager = new LocalWindowManager(wm);
3、WindowManagerImpl的getDefault方法:
public static WindowManagerImpl getDefault() {
return mWindowManager;
}
mWindowManager生成方法,在WIndowManageImpl类中:
private static WindowManagerImpl mWindowManager = new WindowManagerImpl();
使用:
1、 在Activity中生成
2、 ActivityThread类的handleResumeActivity方法中:
ActivityRecord r = performResumeActivity(token, clearHide);
if (r != null) {
  final Activity a = r.activity;
  if (r.window == null && !a.mFinished && willBeVisible) {
    r.window = r.activity.getWindow();
    View decor = r.window.getDecorView();
    decor.setVisibility(View.INVISIBLE);
  //只有在此时才创建一个新的WindowManager
    ViewManager wm = a.getWindowManager();
    WindowManager.LayoutParams l = r.window.getAttributes();
    a.mDecor = decor;
    if (a.mVisibleFromClient) {
         a.mWindowAdded = true;
//将decor添加到WindowManager中,具体的wm为WindowManagerImpl //在wm的addView方法中将ViewRoot和WindowManager关联起来
wm.addView(decor, l);
           }
         }
       }
3、 WindowManagerImpl类的addView方法,windowManager通过数组来建立View,ViewRoot之间的关联:
ViewRoot root;
//使用view来创建ViewRoot
root = new ViewRoot(view.getContext());
root.mAddNesting = 1;
//使用索引将view和ViewRoot关联起来
mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
//设置root的view,并设置view的parent为root
root.setView(view, wparams, panelParentView);

总结Activity,View,window,DecorView的关系如下:
android中真正展示给用户的是window和view,activity在android中所的作用主要是处理一些逻辑问题,比如生命周期的管理、建立窗口等。在android中,窗口的管理还是比较重要的一块,因为他直接负责把内容展示给用户,并和用户进行交互。响应用户的输入等。
View是真正显示的矩形区域,DecorView是顶层View,也就是主View。
相互之间的关系可以理解为一个Activity包含了一个Window,这个Window其实是一个PhoneWindow,在PhoneWindow中包含了DecorView,变量名称为mDecor,mDecor有一个子View,这个子View的布局方式根据设定的主题来确定,在这个子View的xml布局中包含了一个FrameLayout元素,这个FrameLayout元素的id为content,这个content对应于PhoneWindow中的mContentParent变量,用户自定义的布局作为mContentParent的子View存在,一般情况下mContentParnet只有一个子View,如果在Activity调用addView方式实际上是给PhoneWindow中的mContentParent添加子View,由于mContentParent是一个FrameLayout,因此新的子view会覆盖通过setContentView添加的子view。

仅通过setContentView添加子View类View层次与下图类似:


通过addView方式给Activity添加子view层次图如下所示,右下角两个LinearLayout为用户自定义的布局。


ViewRoot作用:是View和WindowManager之间的桥梁,用于两者之间的协议通讯。
Android 的窗口管理是基于 C/S 模式的,客户端就是应用程序,服务端 就是 Window Manager服务。如下图:
public static IWindowSession getWindowSession(Looper mainLooper) {
      InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
//获取回话Session,ViewRoot和Window manager通信,
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"))
       .openSession(imm.getClient(), imm.getInputContext());
            return sWindowSession;
        }
}
Activity和Window manager之间的通讯:
     
  
    Activity 建立一个主窗口之后,在将主窗口添加到 Window Manager 时,首先要建立 Window Manager的代理对象,并打开一个Session(session:会话;该session由上面函数中的第二行代码实现,实现 IWindowSession AIDL 接口),并维持该会话(Activity 将通过该会话与 Window Manager 建立联系,这个Session 是C/S 体系的基础)。Client 通过这个Session 将 window 加入到 Window Manager 中。
    一个完整的窗口概念包含了 View,ViewRoot,Window Manager Service,Window,Decor View,IWindow,ISession,WindowState。他们之间的关系如下:
  
    Client 端的 Activity 通过 IWindowSession 会话与Window Manager Service 建立对话,而 Window Manager Service 通过 IWindow 接口访问 Client,将消息传递到Client 端,在通过消息分发渠道,将消息传递到具体的消息处理函数。(用户输入等操作最先是到 窗口管理服务,由窗口管理服务发给活动窗口,再一步步传递到焦点)。
public ViewRoot(Context context) {
        super();
//获取IWindowSession,
        getWindowSession(context.getMainLooper());
mWindow = new W(this, context);
}
W类,用于window manager向Activity传递各种消息。
static class W extends IWindow.Stub {
private final WeakReference<ViewRoot> mViewRoot;
        private final Looper mMainLooper;

        public W(ViewRoot viewRoot, Context context) {
            mViewRoot = new WeakReference<ViewRoot>(viewRoot);
            mMainLooper = context.getMainLooper();
        }
******从Window mananger来的消息通过W出递给ViewRoot,由ViewRoot分发
public void dispatchKey(KeyEvent event) {
            final ViewRoot viewRoot = mViewRoot.get();
            if (viewRoot != null) {
                viewRoot.dispatchKey(event);
            } else {              
                new EventCompletion(mMainLooper, this, event, false, null);
            }
        }
}

通过IWindowSession机制就可以保证Activity和Window manager保持联系,通过IWindow可以将window manager收集到的消息分发出去。

部分内容及第三张和第四张图片参考网址:
http://blog.csdn.net/xieqibao/article/details/6567814
http://blog.csdn.net/windskier/article/details/6957901
http://vssupermadman.iteye.com/blog/1196323
http://blog.csdn.net/maxleng/article/list/2
http://hi.baidu.com/xiaofanqing/item/8ad71c3fd40e810eceb9feb5[/size][size=xx-large]

    
[2] 移动互联-早下8、9点钟的太阳 <论We7.Mobi手机网站&gt
    来源: 互联网  发布时间: 2014-02-18
移动互联--早上8、9点钟的太阳 <论We7.Mobi手机网站>
此文章由于有表格和图片,请直接查看附件!



















    
[3] PreferenceActivity UI 优化批改
    来源: 互联网  发布时间: 2014-02-18
PreferenceActivity UI 优化修改

 虽然PreferenceActivity的UI比较搓,但是由于其良好的封装性和实用性,所以在一些场景还是有一定的使用价值。所以如何能优化它的UI让它和你程序相配就十分必要了。毕竟对于程序员来说能懒点就懒点,哈哈。

 首先,

 

public abstract class PreferenceActivity extends ListActivity implements
        PreferenceManager.OnPreferenceTreeClickListener,
        PreferenceFragment.OnPreferenceStartFragmentCallback

  这就表明可以替换背景,可以替换Divider,Selector。

  它的adapter是PreferenceGroupAdapter,见于PreferenceScreen:

 

    public void bind(ListView listView) {
        listView.setOnItemClickListener(this);
        listView.setAdapter(getRootAdapter());
        
        onAttachedToActivity();
    }

   这个方法在PreferenceActivity里被掉,用于加载adapter。

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(); 
    
    private 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 know
        mPreferenceGroup.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());
        flattenPreferenceGroup(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();
        for (int i = 0; i < groupSize; i++) {
            final Preference preference = group.getPreference(i);
            
            preferences.add(preference);
            
            if (!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 index
            insertPos = 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;
        }

        return preference.getView(convertView, parent);
    }

    @Override
    public boolean isEnabled(int position) {
        if (position < 0 || position >= getCount()) return true;
        return this.getItem(position).isSelectable();
    }

    @Override
    public boolean areAllItemsEnabled() {
        // There should always be a preference group, and these groups are always
        // disabled
        return false;
    }

    public void onPreferenceChange(Preference preference) {
        notifyDataSetChanged();
    }

    public void onPreferenceHierarchyChange(Preference preference) {
        mHandler.removeCallbacks(mSyncRunnable);
        mHandler.post(mSyncRunnable);
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public 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;
        }
    }

    @Override
    public int getViewTypeCount() {
        if (!mHasReturnedViewTypeCount) {
            mHasReturnedViewTypeCount = true;
        }
        
        return Math.max(1, mPreferenceLayouts.size());
    }

}

  它的getView里掉的是Preference的getView。Preference类似于View,是所有相关UI类的基类。以下是和UI相关的重要代码。

    public View getView(View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = onCreateView(parent);
        }
        onBindView(convertView);
        return convertView;
    }

    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;
    }

 所以基本上每个Preference UI控件最多和mLayoutResId和mWidgetLayoutResId相关。

 首先查找它们的布局,比如PreferenceCategory,attr为com.android.internal.R.attr.preferenceCategoryStyle,

对应主题中的style为<item name="preferenceCategoryStyle">@android:style/Preference.Category</item>。

<style name="Preference.Category">
<item name="android:layout">@android:layout/preference_category</item>
<!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
<item name="android:shouldDisableView">false</item>
<item name="android:selectable">false</item>
</style>

 

 

 如下列出所有的attr:

<declare-styleable name="Theme">
......
<attr name="preferenceScreenStyle" format="reference"/>
<!-- Default style for PreferenceCategory. -->
<attr name="preferenceCategoryStyle" format="reference"/>
<!-- Default style for Preference. -->
<attr name="preferenceStyle" format="reference"/>
<!-- Default style for informational Preference. -->
<attr name="preferenceInformationStyle" format="reference"/>
<!-- Default style for CheckBoxPreference. -->
<attr name="checkBoxPreferenceStyle" format="reference"/>
<!-- Default style for YesNoPreference. -->
<attr name="yesNoPreferenceStyle" format="reference"/>
<!-- Default style for DialogPreference. -->
<attr name="dialogPreferenceStyle" format="reference"/>
<!-- Default style for EditTextPreference. -->
<attr name="editTextPreferenceStyle" format="reference"/>
<!-- Default style for RingtonePreference. -->
<attr name="ringtonePreferenceStyle" format="reference"/>
<!-- The preference layout that has the child/tabbed effect. -->
<attr name="preferenceLayoutChild" format="reference"/>
</declare-styleable>

对应的style为:

<style name="Theme">
......
 <!-- Preference styles -->
<item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
<item name="preferenceCategoryStyle">@android:style/Preference.Category</item>
<item name="preferenceStyle">@android:style/Preference</item>
<item name="preferenceInformationStyle">@android:style/Preference.Information</item>
<item name="checkBoxPreferenceStyle">@android:style/Preference.CheckBoxPreference</item>
<item name="yesNoPreferenceStyle">@android:style/Preference.DialogPreference.YesNoPreference</item>
<item name="dialogPreferenceStyle">@android:style/Preference.DialogPreference</item>
<item name="editTextPreferenceStyle">@android:style/Preference.DialogPreference.EditTextPreference</item>
<item name="ringtonePreferenceStyle">@android:style/Preference.RingtonePreference</item>
<item name="preferenceLayoutChild">@android:layout/preference_child</item>
</style>

   我没搞清楚的是这个style是在什么地方设进去的。所以如果要修改PreferenceCategory的UI,只需从系统源码中拷贝出这个布局XML,修改它的title的id:@+android:id/title为@android:id/title,同时  

<PreferenceCategory
        android:layout="@layout/preference_category"

        android:title="你好1" >

由于PreferenceCategory是直接加载preference_category的,所以替换了默认的preference.xml,所以就算你配上android:widgetLayout也没用。

  修改CheckBoxPreference的UI需要:layout->preference.xml widgetLayout->preference_widget_checkbox.xml,同时修改id。

  拿到布局文件后,字体,字体大小,颜色等布局元素你想怎么弄就怎么弄了。

需要注意的是,如果你想要保存那写选中的数据,必须要对preference UI 控件设置key。因为保存XML时候必须要有key。



    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

▪Android提高之自定义Menu(TabMenu)实现方法 iis7站长之家