原文网址:http://www.myexception.cn/android/1168124.html
Android 简单定制OptionMenu外观
《Android内核剖析》第8章笔记
1. 分析
1.1 主要类
1.2 主要流程
1.3 关键代码
private void openPanel(PanelFeatureState st, KeyEvent event) {
// System.out.println("Open panel: isOpen=" + st.isOpen);
// Already open, return
if (st.isOpen) {
return;
}
Callback cb = getCallback();
if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) {
// Callback doesn't want the menu to open, reset any state
closePanel(st, true);
return;
}
final WindowManager wm = getWindowManager();
if (wm == null) {
return;
}
// Prepare panel (should have been done before, but just in case)
if (!preparePanel(st, event)) {
return;
}
....
public final boolean preparePanel(PanelFeatureState st, KeyEvent event) {
// Already prepared (isPrepared will be reset to false later)
if (st.isPrepared)
return true;
if ((mPreparedPanel != null) && (mPreparedPanel != st)) {
// Another Panel is prepared and possibly open, so close it
closePanel(mPreparedPanel, false);
}
final Callback cb = getCallback();
if (cb != null) {
st.createdPanelView = cb.onCreatePanelView(st.featureId);
}
if (st.createdPanelView == null) {
// Init the panel state's menu--return false if init failed
if (st.menu == null) {
if (!initializePanelMenu(st) || (st.menu == null)) {
return false;
}
// Call callback, and return if it doesn't want to display menu
if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) {
// Ditch the menu created above
st.menu = null;
return false;
}
}
// Callback and return if the callback does not want to show the menu
if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) {
return false;
}
// Set the proper keymap
KeyCharacterMap kmap = KeyCharacterMap.load(event != null ? event.getDeviceId() : 0);
st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC;
st.menu.setQwertyMode(st.qwertyMode);
}
// Set other state
st.isPrepared = true;
st.isHandled = false;
mPreparedPanel = st;
return true;
}
根据Callback 也即Activity的onCreatePanelView()方法的返回结果, 导致preparePanel返回不同的布尔值, 最终影响openPanel()方法的执行路径 。若返回false, 表示使用完全自定义的OptionMenu视图,openPanel()直接退出;否则使用系统的OptionMenu视图。
所以, 可以重写Activity的onCreatePanelView()方法提供一个完全自定义的OptionMenu视图
2. 示例
1. Java代码。 重写Activity的onCreatePanelView()方法。
public class CustomOptionMenuActivity extends Activity {
@Override
public View onCreatePanelView(int featureId) {
// return super.onCreatePanelView(featureId);
View v = getLayoutInflater().inflate(
R.layout.activity_custom_option_menu, null);
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MyLog.i("");
Toast.makeText(CustomOptionMenuActivity.this, "text",
Toast.LENGTH_SHORT).show();
CustomOptionMenuActivity.this.finish();
}
});
return v;
}
}
2. 布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:text="TextView" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="10dip"></TextView> </LinearLayout>
3. 截图
如上图, 点击Menu键后, 出现一个自定义OptionMenu。