Android Browser学习五 多窗口: Tab 整体结构

前面说了这么多却发现我们的Tab还没有介绍, Tab到底是个什么东西呢?

其实是一个含有两个WebView 成员一个WebViewController成员的类: 其中PageState用来真正存储这个tab网页的一些信息,包括url 标题 图标等

?
1
2
3
4
5
6
7
8
// Main WebView wrapper tab的容器
    private View mContainer;
    // Main WebView 显示网页的webview
    private WebView mMainView;
    // Subwindow container
    private View mSubViewContainer;
    // Subwindow WebView在一个tab可能会弹出 另一个WebView的dialog  使用subwebview实现 (True if the new        window should be a dialog, rather than a full-size window.)
    private WebView mSubView;



其中mContainer就是tab的主Ui 了 他一般是一个形如"


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
     android:orientation = "vertical"
     android:fitsSystemWindows = "true"
     android:layout_width = "match_parent"
     android:layout_height = "match_parent" >
 
     <!-- Wrapper layout for the WebView, which must be in a FrameLayout. -->
     < FrameLayout android:id = "@+id/webview_wrapper"
         android:layout_width = "match_parent"
         android:layout_height = "0dip"
         android:layout_weight = "1" />
 
     <!-- Geolocation permissions prompt -->
     < ViewStub android:id = "@+id/geolocation_permissions_prompt"
         android:layout = "@layout/geolocation_permissions_prompt"
         android:layout_width = "match_parent"
         android:layout_height = "wrap_content" />
 
</ LinearLayout >



这样的布局, 通过 BaseUI的onSetWebView设置:



?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
   public void onSetWebView(Tab tab, WebView webView) {
       View container = tab.getViewContainer();
       if (container == null ) {
           // The tab consists of a container view, which contains the main
           // WebView, as well as any other UI elements associated with the tab.
           container = mActivity.getLayoutInflat().inflate(R.layout.tab,
                   mContentView, false ); //把tab的ContainerView  Attach到Activity
           tab.setViewContainer(container);
       }
       if (tab.getWebView() != webView) { //如果tab当前的 mMainWebview 和 以前的webview不一样就把以前的那个webview 从 Container 移除掉
           // Just remove the old one.
           FrameLayout wrapper =
                   (FrameLayout) container.findViewById(R.id.webview_wrapper);
           wrapper.removeView(tab.getWebView());
       }
   }




这个函数是谁调用的呢? 终归肯定是Controller进行的, 但是这里设计就有点乱了:

顺序是这样:  Controller::setActiveTab -> TabControl::setCurrentTab -> Tab::setWebView -> Controler ::onSetWebView  -> BaseUI::onSetWebView 



 Controller调用 BaseUI 的setActiveTab函数 (其实最后是attachTabToContentView)把Tab的mWebView和container 关联起来:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
protected void attachTabToContentView(Tab tab) {
        if ((tab == null ) || (tab.getWebView() == null )) {
            return ;
        }
        View container = tab.getViewContainer(); //对应tab的layout
        WebView mainView  = tab.getWebView();
        // Attach the WebView to the container and then attach the
        // container to the content view.
        //把Tab的container添加到mContentView
        FrameLayout wrapper =
                (FrameLayout) container.findViewById(R.id.webview_wrapper);
        ViewGroup parent = (ViewGroup) mainView.getParent();
        if (parent != wrapper) {
            if (parent != null ) {
                Log.w(LOGTAG, "mMainView already has a parent in"
                        + " attachTabToContentView!" );
                parent.removeView(mainView);
            }
            wrapper.addView(mainView);
        } else {
            Log.w(LOGTAG, "mMainView is already attached to wrapper in"
                    + " attachTabToContentView!" );
        }
        parent = (ViewGroup) container.getParent();
        if (parent != mContentView) {
            if (parent != null ) {
                Log.w(LOGTAG, "mContainer already has a parent in"
                        + " attachTabToContentView!" );
                parent.removeView(container);
            }
            mContentView.addView(container, COVER_SCREEN_PARAMS);
        } else {
            Log.w(LOGTAG, "mContainer is already attached to content in"
                    + " attachTabToContentView!" );
        }
        mUiController.attachSubWindow(tab);
    }

这样我们就明白了, Activity只是一个容器, 当哪个Tab放到前台, BaseUI就拿到对应Tab的Container和Webview , 把这两个空间attach到Activity的ContentView中去

之所以这样做, 可能是因为作者想让  BaseUI来进行把View attach到Activity上的操作 , Tab只做控制Webview load网页的操作; 他们之间的交互由Controller来控制.但是感觉这个设计可能有些乱了.


Tab获取当前快照的函数:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
protected void capture() {
         if (mMainView == null || mCapture == null ) return ;
         if (mMainView.getContentWidth() <= 0 || mMainView.getContentHeight() <= 0 ) {
             return ;
         }
         Canvas c = new Canvas(mCapture);
         final int left = mMainView.getScrollX(); //快照抓取的是tab的顶部
         final int top = mMainView.getScrollY() + mMainView.getVisibleTitleHeight();
         int state = c.save();
         c.translate(-left, -top);
         float scale = mCaptureWidth / ( float ) mMainView.getWidth();
         c.scale(scale, scale, left, top);
         if (mMainView instanceof BrowserWebView) {
             ((BrowserWebView)mMainView).drawContent(c);
         } else {
             mMainView.draw(c);
         }
         c.restoreToCount(state);
         // manually anti-alias the edges for the tilt
         c.drawRect( 0 , 0 , 1 , mCapture.getHeight(), sAlphaPaint);
         c.drawRect(mCapture.getWidth() - 1 , 0 , mCapture.getWidth(),
                 mCapture.getHeight(), sAlphaPaint);
         c.drawRect( 0 , 0 , mCapture.getWidth(), 1 , sAlphaPaint);
         c.drawRect( 0 , mCapture.getHeight() - 1 , mCapture.getWidth(),
                 mCapture.getHeight(), sAlphaPaint);
         c.setBitmap( null ); //释放canvas绘制的bitmap
         mHandler.removeMessages(MSG_CAPTURE);
         persistThumbnail();
         TabControl tc = mWebViewController.getTabControl();
         if (tc != null ) {
             OnThumbnailUpdatedListener updateListener
                     = tc.getOnThumbnailUpdatedListener();
             if (updateListener != null ) { //通知更新了缩略图
                 updateListener.onThumbnailUpdated( this );
             }
         }
     }



Tab 保存 当前网页的函数


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
  * 保存离线阅读的一些数据
  * @return
  */
public ContentValues createSnapshotValues() {
     if (mMainView == null ) return null ;
     SnapshotByteArrayOutputStream bos = new SnapshotByteArrayOutputStream();
     try {
         GZIPOutputStream stream = new GZIPOutputStream(bos);
         if (!mMainView.saveViewState(stream)) {
             return null ;
         }
         stream.flush();
         stream.close();
     } catch (Exception e) {
         Log.w(LOGTAG, "Failed to save view state" , e);
         return null ;
     }
     byte [] data = bos.toByteArray();
     ContentValues values = new ContentValues();
     values.put(Snapshots.TITLE, mCurrentState.mTitle); //标题
     values.put(Snapshots.URL, mCurrentState.mUrl); //url
     values.put(Snapshots.VIEWSTATE, data);
     values.put(Snapshots.BACKGROUND, mMainView.getPageBackgroundColor()); //背景
     values.put(Snapshots.DATE_CREATED, System.currentTimeMillis()); //时间
     values.put(Snapshots.FAVICON, compressBitmap(getFavicon())); //网址图标
     Bitmap screenshot = Controller.createScreenshot(mMainView,
             Controller.getDesiredThumbnailWidth(mContext),
             Controller.getDesiredThumbnailHeight(mContext));
     values.put(Snapshots.THUMBNAIL, compressBitmap(screenshot));
     return values;
}
 
public byte [] compressBitmap(Bitmap bitmap) {
     if (bitmap == null ) {
         return null ;
     }
     ByteArrayOutputStream stream = new ByteArrayOutputStream();
     bitmap.compress(CompressFormat.PNG, 100 , stream);
     return stream.toByteArray();
}



处理SSLError的函数


?
1
2
3
4
5
6
7
8
9
10
11
private void handleProceededAfterSslError(SslError error) {
        if (error.getUrl().equals(mCurrentState.mUrl)) {
            // The security state should currently be SECURITY_STATE_SECURE.
            setSecurityState(SecurityState.SECURITY_STATE_BAD_CERTIFICATE);
            mCurrentState.mSslCertificateError = error;
        } else if (getSecurityState() == SecurityState.SECURITY_STATE_SECURE) {
            // The page's main resource is secure and this error is for a
            // sub-resource.
            setSecurityState(SecurityState.SECURITY_STATE_MIXED);
        }
    }



?
1
2
3
4
5
6
7
8
9
10
/**
         * Called when an SSL error occurred while loading a resource, but the
         * WebView but chose to proceed anyway based on a decision retained
         * from a previous response to onReceivedSslError(). We update our
         * security state to reflect this.
         */
        @Override
        public void onProceededAfterSslError(WebView view, SslError error) {
            handleProceededAfterSslError(error);
        }


原文地址:http://my.oschina.net/sfshine/blog/198022

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值