今天介紹一下瀏覽器PieMenu的實現, Piemenu是瀏覽器的一個實驗室功能, 可是其效果仍是挺炫的以下所示: java
估計不少app都的扇形菜單都參考過這個東西.並且這個東西一直起來也不難, 解耦作的仍是比較好的~ android
今天這個文章先介紹一下Piemenu的大體架構, 其UML圖以下:(使用了astah 可能有些類型是錯的, ;懶得一個個改了 請諒解, 咱們須要的是大致架構~)_ web
能夠看到, Piemenu實際上是一個FrameLayout, 遮罩在tab的上層, 這樣用戶點擊這個Layout 若是是在屏幕的邊緣, 就能夠顯示這個 瀏覽器
PieMenu了. 架構
這個PieMenu是徹底的draw的, 給定一個點mCenter而後app就以這個點爲中心, 把每一個PieItem也就是扇葉繪製出來. 對於扇葉的組裝, piemenu的顯示等, 都是PieControl來控制的, 時序圖: mvc
按照時序圖來分析一下: app
添加Piemenu的最開始是在PhoneUI的構造函數中: ide
public PhoneUi(Activity browser, UiController controller) { super(browser, controller); setUseQuickControls(BrowserSettings.getInstance().useQuickControls()); //設置快速控制菜單,就是那個piemenu mNavigationBar = (NavigationBarPhone) mTitleBar.getNavigationBar(); TypedValue heightValue = new TypedValue(); browser.getTheme().resolveAttribute( com.android.internal.R.attr.actionBarSize, heightValue, true); mActionBarHeight = TypedValue.complexToDimensionPixelSize(heightValue.data, browser.getResources().getDisplayMetrics()); }
而後就是添加PieMenu到PhoneUI的頂層了: 函數
if (useQuickControls) { mPieControl = new PieControlPhone(mActivity, mUiController, this); mPieControl.attachToContainer(mContentView);//把piemenu添加到contentview之上 WebView web = getWebView(); if (web != null) { web.setEmbeddedTitleBar(null); } } else {//若是設置的是關閉 可能須要把以前的移除掉 if (mPieControl != null) { mPieControl.removeFromContainer(mContentView); } WebView web = getWebView(); if (web != null) { // make sure we can re-parent titlebar if ((mTitleBar != null) && (mTitleBar.getParent() != null)) { ((ViewGroup) mTitleBar.getParent()).removeView(mTitleBar); } web.setEmbeddedTitleBar(mTitleBar); } setTitleGravity(Gravity.NO_GRAVITY); }
attachToContainer是真正的添加到PhoneUI的邏輯, 果真是添加到整個瀏覽器的頂層: 學習
protected void attachToContainer(FrameLayout container) {
if (mPie == null) {
mPie = new PieMenu(mActivity);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
mPie.setLayoutParams(lp);
populateMenu();//添加pieitem
mPie.setController(this);
}
container.addView(mPie);//添加到整個瀏覽器的頂層: }
public PieMenu(Context context) { super(context); init(context); } private void init(Context ctx) { mItems = new ArrayList<PieItem>();//初始化pie中的item mLevels = 0;//peimenu能夠有幾層. 用這個標誌位來標誌是一級菜單仍是二級菜單 mCounts = new int[MAX_LEVELS]; Resources res = ctx.getResources(); mRadius = (int) res.getDimension(R.dimen.qc_radius_start); //內徑 mRadiusInc = (int) res.getDimension(R.dimen.qc_radius_increment);//外徑 mSlop = (int) res.getDimension(R.dimen.qc_slop); //應該是光暈, 周圍有一部分光暈 mTouchOffset = (int) res.getDimension(R.dimen.qc_touch_offset); //其實這個點擊的中心並非圓形的正中 mOpen = false; setWillNotDraw(false);//自定義了viewgroup的 ondraw 要設置這個爲false這樣才能調用ondraw setDrawingCacheEnabled(false); //當調用setDrawingCacheEnabled方法設置爲false, 系統會自動把原來的cache銷燬。減少資源佔用 mCenter = new Point(0,0); mBackground = res.getDrawable(R.drawable.qc_background_normal);//背景 mNormalPaint = new Paint(); mNormalPaint.setColor(res.getColor(R.color.qc_normal));//默認是藍色 mNormalPaint.setAntiAlias(true); mSelectedPaint = new Paint(); mSelectedPaint.setColor(res.getColor(R.color.qc_selected));//選中是黃色 mSelectedPaint.setAntiAlias(true); }
這個操做在不一樣的設備上展現是不一樣的, 咱們只看在Phone上的展示也就是PieControlPhone:
protected void populateMenu() { mUrl = makeItem(R.drawable.ic_web_holo_dark, 1); View tabs = makeTabsView(); mShowTabs = new PieItem(tabs, 1); mTabAdapter = new TabAdapter(mActivity, mUiController);//這是展現那個tab的小listview PieStackView stack = new PieStackView(mActivity); //這個東西其實是 piemenu 選擇tab的時候顯示的那個tab listview 後面講解. stack.setLayoutListener(new OnLayoutListener() { @Override public void onLayout(int ax, int ay, boolean left) { buildTabs(); } }); stack.setOnCurrentListener(mTabAdapter); stack.setAdapter(mTabAdapter); mShowTabs.setPieView(stack);//設置tab多窗口的列表 mOptions = makeItem(com.android.internal.R.drawable.ic_menu_moreoverflow_normal_holo_dark, 1); // level 1 mNewTab = makeItem(R.drawable.ic_new_window_holo_dark, 1); mBookmarks = makeItem(R.drawable.ic_bookmarks_holo_dark, 1); mPie.addItem(mNewTab); mPie.addItem(mShowTabs); mPie.addItem(mUrl); mPie.addItem(mBookmarks); mPie.addItem(mOptions); setClickListener(this, mUrl, mShowTabs, mOptions, mNewTab, mBookmarks); mPopup = new PopupMenu(mActivity, mUi.getTitleBar()); Menu menu = mPopup.getMenu();//顯示menu菜單 mPopup.getMenuInflater().inflate(R.menu.browser, menu); mPopup.setOnMenuItemClickListener(this); }
//生成各類piemenuitem的圖標 protected PieItem makeItem(int image, int l) { ImageView view = new ImageView(mActivity); view.setImageResource(image); view.setMinimumWidth(mItemSize); view.setMinimumHeight(mItemSize); view.setScaleType(ScaleType.CENTER); LayoutParams lp = new LayoutParams(mItemSize, mItemSize); view.setLayoutParams(lp); return new PieItem(view, l); }
這就是大體的PieMenu的架構了,能夠看到仍是谷歌經常使用的mvc架構, 感受這個架構設計的挺好的, 思路很清晰以及:
統一的setting模塊.
業務和展現分開,
使用繼承來實現手機和平板的適配,
每一個扇形都是一個PieItem類, 方便未來繪製邏輯以及事件分發邏輯的處理等,
在這個app的頂部遮罩framelayout, 從而實現點擊任何屏幕編譯均可以顯示piemenu
這些都是值得咱們學習的.
這裏還有個移植的小案例:http://blog.csdn.net/libre923045/article/details/7800227