android原生browser分析(二)--介面篇

來源:互聯網
上載者:User

標籤:android   browser   瀏覽器   ui   

我們先看一張瀏覽器的主介面,上面標示瀏覽器介面各部分對應的類,這裡是以平板上的介面為例。給張圖是為了給大家一個直觀的感覺。

 

  

BrowserActivity是整個應用的主介面,在onCreate中建立了Controller對象,Controller對象是整個應用最重要的管理類,這個後面再說。

@Override    public void onCreate(Bundle icicle) {       mController = createController();}

Controller的建立中建立了UI類,UI類是最主要的視圖類,它雖然不是View類的子類,只是一個包含很多抽象方法的介面,但是它的實作類別包含了重要的View視圖成員。後面將通過UI的實作類別BaseUi將這些視圖成員和BrowserActivity中布局檔案中視圖ID一一對應起來,關於這點後面描述。

 private Controller createController() {        Controller controller = new Controller(this);        boolean xlarge = isTablet(this);        UI ui = null;        if (xlarge) {            ui = new XLargeUi(this, controller);        } else {            ui = new PhoneUi(this, controller);        }        controller.setUi(ui);        return controller;} 

由上,我們看到根據isTablet() 方法擷取的值,將會建立不同的UI類。

看一下isTablet()方法:

public static boolean isTablet(Context context) {        return context.getResources().getBoolean(R.bool.isTablet);   }

可以看出,這裡是通過一個資源檔的值來確定的,實際上這裡是用來區分這個是手機應用還是平板應用的。取值為true的時候擷取的是XLargeUi對象,取值為false的時候,擷取的是PhoneUi對象。由於我的項目是平板的,就以XLargeUi 為例進行分析。

 

在此,我們把這幾個類的繼承關係理一理:

public interface UI {//....} public abstract class BaseUi implements UI {//...} public class XLargeUi extends BaseUi {//...} public class PhoneUi extends BaseUi {//...} 

我們現在來看看XLargeUi 的定義:

public class XLargeUi extends BaseUi {     private ActionBar mActionBar;    private TabBar mTabBar;     private NavigationBarTablet mNavBar;     /**     * @param browser     * @param controller     */    public XLargeUi(Activity browser, UiController controller) {        super(browser, controller);        //other code        mNavBar = (NavigationBarTablet) mTitleBar.getNavigationBar();        mTabBar = new TabBar(mActivity, mUiController, this);        mActionBar = mActivity.getActionBar();        setupActionBar();    }     private void setupActionBar() {         mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);        mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);        mActionBar.setCustomView(mTabBar);} //other code}

構造方法中傳入了兩個參數,第一個是應用的主介面BrowserActivity,第二個是UiController 對象,該對象主要做Ui進行控制,如對選項卡的操作,載入URL等。

 

建構函式中主要做了下面的事情:

1、通過TitleBar類型成員變數mTitleBar擷取NavigationBarTablet類型的對象mNavBar ,這個對象即是導航工具列。就是瀏覽器介面的如下的工具列

 

該對象主要用於更新導覽列的狀態,即對前進後退鍵、URL輸入框、URL表徵圖進行操作。

成員變數mTitleBar是從BaseUi繼承而來的。 

2、新建立一個TabBar類型的對象,這個TabBar對象是只有平板才有的。建立時傳入主介面BrowserActivity、UiController 對象、XLargeUi自身。建立的對象即選項卡欄


該對象將用來進行選項卡的相關操作,增加、刪除、更新選項卡,改變收藏夾表徵圖favicon,修改URL標題等。

3、通過主介面BrowserActivity擷取ActionBar對象。

4、設定ActionBar的樣式,並將選項卡欄TabBar對象設定為ActionBar的自訂視圖。

 

關於BaseUi

 

BaseUi是平板介面XLargeUi和手機介面PhoneUi共有的父類。

public abstract class BaseUi implements UI {     Activity mActivity;    UiController mUiController;    TabControl mTabControl;     private UrlBarAutoShowManager mUrlBarAutoShowManager;     protected TitleBar mTitleBar;    private NavigationBarBase mNavigationBar;    protected PieControl mPieControl;     public BaseUi(Activity browser, UiController controller) {        mActivity = browser;        mUiController = controller;        mTabControl = controller.getTabControl();           FrameLayout frameLayout = (FrameLayout) mActivity.getWindow()                .getDecorView().findViewById(android.R.id.content);        LayoutInflater.from(mActivity).inflate(R.layout.custom_screen, frameLayout);        //...        setFullscreen(BrowserSettings.getInstance().useFullscreen());        mTitleBar = new TitleBar(mActivity, mUiController, this,                mContentView);        mTitleBar.setProgress(100);        mNavigationBar = mTitleBar.getNavigationBar();        mUrlBarAutoShowManager = new UrlBarAutoShowManager(this);}}

先從構造方法來看:

構造方法傳入了兩個參數:第一個是應用的主介面BrowserActivity,第二個是UiController 對象,也就是建立XLargeUi時傳入的兩個參數。

 

構造方法中主要完成了如下的事情:

1、通過UiController 對象擷取TabControl類型的對象mTabControl 。

2、為BrowserActivity設定視圖。查看BrowserActivity的代碼,通篇沒有找到setContentView的影子,那麼它是怎麼為activity設定視圖的呢?原來是在這裡。

FrameLayout frameLayout = (FrameLayout) mActivity.getWindow()                .getDecorView().findViewById(android.R.id.content);    LayoutInflater.from(mActivity).inflate(R.layout.custom_screen, frameLayout);

這裡是將資源檔對應的視圖加入到android.R.id.content定義的FrameLayout中。這是怎麼回事呢?

原來activity中的setContentView如下:

public void setContentView(int layoutResID) {        getWindow().setContentView(layoutResID);        //...    }

Activity中:

public Window getWindow() {        return mWindow;}mWindow = PolicyManager.makeNewWindow(this);

PolicyManager中:

public final class PolicyManager {private static final String POLICY_IMPL_CLASS_NAME =        "com.android.internal.policy.impl.Policy";     private static final IPolicy sPolicy;     static {        try {            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);            sPolicy = (IPolicy)policyClass.newInstance();        } catch (InstantiationException ex) {            throw new RuntimeException( "exception", ex);        }     }public static Window makeNewWindow(Context context) {        return sPolicy.makeNewWindow(context);    }}

IPolicy 中:

public interface IPolicy {    public Window makeNewWindow(Context context);}

Policy中

public class Policy implements IPolicy//...public Window makeNewWindow(Context context) {        return new PhoneWindow(context);    }}

所以Activity的getWindow()擷取的是PhoneWindow對象。

而PhoneWindow繼承了Window,並覆寫了setContentView,PhoneWindow中setContentView(int layoutResID)方法如下:

@Override    public void setContentView(int layoutResID) {        if (mContentParent == null) {            installDecor();        } else {            mContentParent.removeAllViews();        }        mLayoutInflater.inflate(layoutResID, mContentParent);        final Callback cb = getCallback();        if (cb != null && !isDestroyed()) {            cb.onContentChanged();        }    }

就是將該布局資源檔填入mContentParent,那麼mContentParent是什麼呢?看下面

private void installDecor() {if (mContentParent == null) {            mContentParent = generateLayout(mDecor);//....}}protected ViewGroup generateLayout(DecorView decor) {//...ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);//...return contentParent;}

由上可知,是由ID為ID_ANDROID_CONTENT的資源檔定義的。

該值由Window類繼承而來,看看定義

public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

mActivity.getWindow()獲得一個Window對象,該對象調用getDecorView()找到的android.R.id.content,正是此處的com.android.internal.R.id.content,所以activity的setContentView實際就是將view加入到android.R.id.content定義的ViewGroup中,上面的第二步操作就等價於在BrowserActivity中setContentView。

 

3、根據BrowserSettings中的配置值設定是否全屏。

4、建立一個TitleBar對象。需要傳入的參數是BrowserActivity,UiController,BaseUi,FrameLayout,前兩個參數是作為BaseUi構造方法的參數傳進來的,第三個是BaseUi本身,第四個參數是布局中的一個FrameLayout。TitleBar對象是手機和平板共有的,而TabBar是平板特有的,故有這樣的設計。

5、設定TitleBar中的ProgressBar的最大值為100。這個ProgressBar也就是顯示載入網頁的進度的。載入時顯現,載入完畢時消失。

6、獲得NavigationBarBase對象,在平板中獲得的是NavigationBarTablet,在手機中獲得的是NavigationBarPhone.即導覽列。

7、建立一個UrlBarAutoShowManager對象,該對象用來控制網頁滾動過程中顯示和隱藏標題列TitleBar.

 

回過頭來看一下XLargeUi ,我們提到了NavigationBarTablet類型的對象mNavBar和TabBar類型的對象,為什麼這兩個不在BaseUi裡面定義呢?

這是因為這兩個是平板介面中特有的,手機介面中不存在。mNavBar在手機介面中是轉為NavigationBarPhone類型的,而TabBar是選項卡欄,手機螢幕小,所有沒有選項卡欄。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.