1. 程式人生 > >Android 一個Activity中實現多視窗WebView

Android 一個Activity中實現多視窗WebView

這裡寫圖片描述

這裡寫圖片描述

公司在弄一個類似瀏覽器的框架,主要頁面功能都是用h5,但是領導說要弄成多視窗的,而且還是隻在當前Activity中;
主體功能大概如此:頭部標題欄實現 標題、選單列表、多視窗顯示等
頭部以下就是一個WebView頁面,js互動實現頁面顯示。
聽到這個需求我挺頭疼,因為在一個Activity中實現多視窗還要實時的儲存每個頁面的狀態
查找了很多資料,跟我這個需求差不多的很少,所以只能自己來了。
最後勉勉強強實現了,做法很low,但是好歹也算是實現了,以此記錄一下:
廢話不多。

我的思路大概是這樣:

多視窗一般也不是無限制的,所以我定義了一個WebView[] 沒錯,定義一個WebView陣列,定義多視窗的上限為6
然後定義一個主WebView,將它存進WebView陣列中,而後面新建的也都存進WebView陣列中,顯示的時候將WebView[]陣列中的該項直接賦給主WebView,
是的,可以直接WebView = WebView[0];這樣賦值,同時定義一個總集合儲存每一個WebView的標題、連結等資料 
每次切換同時把資料切換就可以了

下面上主程式碼:MainActivity.java —主頁面

    public class MainActivity extends AppCompatActivity implements View.OnClickListener, View.OnLongClickListener {
public final static int FILECHOOSER_RESULTCODE = 41;
public final static int FILECHOOSER_RESULTCODE_FOR_ANDROID_5 = 42;
private static final String LOGTAG = "FrmMain";

ImageView imgBack, imgMore;
TextView lblTitle;
LinearLayout boxTitle;


private WebView mWebView; //瀏覽器
private boolean islogin = false;
private ValueCallback<Uri> mUploadMessage;
private ProgressBar progress;
private boolean is_ERROR = false;//是否錯誤了
private ValueCallback<Uri[]> mUploadMessageForAndroid5;

private FrameLayout mainframe;
private View view;      //彈出框子佈局
private CommBottomPopWindow mTitlePopWindow;  //標題欄選單項
private CommBottomPopWindow mpopWindow; //
public ArrayList<MainTitleMenu> mRightMenu;  //右側選單集合
private ArrayList<MainTitleMenu> mTitleWinMenu;  //標題選單視窗集合
public ArrayList<MainTitleMenu> mTitleMenu;  //標題選單集合
private ArrayList<ArrayList<MainTitleMenu>> allTitleList;  //標題選單總集合
private List<MainTitleMenu> titlePage;  //多頁面集合
private WebView newsWebView[] = new WebView[6];  //webView陣列,限制上限為6
private String currentUrl = null;
private int classWebView = 0;
private boolean webViewState = false;  //判斷是否新建webView
private String mUrl = "http://www.baidu.com";

/**
 * 是否直接退出
 */
private boolean is_exit = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mRightMenu = new ArrayList<MainTitleMenu>();
    mTitleMenu = new ArrayList<MainTitleMenu>();
    allTitleList = new ArrayList<ArrayList<MainTitleMenu>>();
    for (int i = 0; i < 6; i++) {
        allTitleList.add(new ArrayList<MainTitleMenu>());
    }
    titlePage = new ArrayList<MainTitleMenu>();
    mTitleWinMenu = new ArrayList<MainTitleMenu>();
    initData();
    InitView();
}

/**
 * 固定資料初始化
 */
private void initData() {
    mTitleMenu.clear();
    mRightMenu.clear();
    mTitleMenu.add(new MainTitleMenu("返回首頁", false, mUrl, 1, classWebView));  //設定初始化資料
    mTitleMenu.add(new MainTitleMenu("新建視窗", false, "", 1, classWebView));
    mRightMenu.add(new MainTitleMenu("設定", false, "", 1));
    mRightMenu.add(new MainTitleMenu("退出系統", true, "", 1));
}


@SuppressLint("JavascriptInterface")
private void InitView() {
    imgBack = (ImageView) this.findViewById(R.id.imgBack);
    imgMore = (ImageView) this.findViewById(R.id.imgMore);
    lblTitle = (TextView) this.findViewById(R.id.lblTitle);
    boxTitle = (LinearLayout) findViewById(R.id.boxTitle);
    mainframe = (FrameLayout) findViewById(R.id.mainframe);
    progress = (ProgressBar) this.findViewById(R.id.progress);
    imgBack.setOnClickListener(this);
    imgMore.setOnClickListener(this);
    lblTitle.setOnClickListener(this);
    lblTitle.setSelected(true);
    mWebView = (WebView) this.findViewById(R.id.viewView2);
//        mWebView.getSettings().setTextZoom(100);
        //jsAndroid 供web端js呼叫標識,修改請通知web開發者
//        mWebView.addJavascriptInterface(new JavaScriptProxy(this), "JSobj");
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setAllowFileAccess(true);
        mWebView.setWebViewClient(new MyWebViewClient());
        mWebView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if ((keyCode == KeyEvent.KEYCODE_BACK) && event.getAction() == KeyEvent.ACTION_UP) {
                    if (is_exit) {
                        Intent home = new Intent(Intent.ACTION_MAIN);
                        home.addCategory(Intent.CATEGORY_HOME);
                        startActivity(home);
                    } else {
                        if (mWebView.canGoBack()) mWebView.goBack();// 返回鍵退回
                        else finish();
                    }
                    return true;
                } else
                    return false;
            }
        });
        mWebView.setOnLongClickListener(this);
        AddWebView();
    }

@Override
public boolean onLongClick(View v) {
    //webview的長按事件,設定true後webview將不會觸發長按複製動作
    return true;
}

public int winClose = -1;  //控制關閉視窗
int mIndex = 0;   //當前頁面視窗位置下標
//標題選單回撥的點選事件
private CommBottomPopWindow.PopWindowListener mPopListener = new CommBottomPopWindow.PopWindowListener() {
    @Override
    public void onPopSelected(int which) {
        switch (which) {
            case 1:

            case 2:
                switch (mTitleMenu.get(which).getName()) {
                    case "關閉頁面":
                        //關閉當前視窗
                        int windowNum = 0;
                        for (int i = 0; i < allTitleList.size(); i++) {
                            if (allTitleList.get(i).size() > 0) {
                                windowNum++;
                            }
                        }
                        if (windowNum > 1) {
                            newsWebView[classWebView].setVisibility(View.GONE);
                            newsWebView[classWebView] = null;
                            for (int i = 0; i < allTitleList.size(); i++) {
                                if (allTitleList.get(i).size() > 0) {
                                    if (allTitleList.get(i).get(0).getOnlySign() == classWebView) {
                                        allTitleList.get(classWebView).clear();
                                    }
                                }
                            }
                            for (int i = 0; i < titlePage.size(); i++) {
                                if (titlePage.get(i).getOnlySign() == classWebView) {
                                    titlePage.remove(i);
                                }
                            }
                            for (int i = 0; i < newsWebView.length; i++) {
                                if (newsWebView[i] != null) {
                                    newsWebView[i].setVisibility(View.VISIBLE);
                                    mWebView = newsWebView[i];
                                    classWebView = i;
                                    for (int l = 0; l < allTitleList.size(); l++) {
                                        if (allTitleList.get(l).size() > 0) {
                                            if (allTitleList.get(l).get(0).getOnlySign() == classWebView) {
                                                upDataAggre(allTitleList.get(l), titlePage);
                                                mTitleMenu.clear();
                                                mTitleMenu.addAll(allTitleList.get(l));
                                                break;
                                            }
                                        }
                                    }
                                    for (int j = 0; j < titlePage.size(); j++) {
                                        if (titlePage.get(j).getOnlySign() == i) {
                                            lblTitle.setText(titlePage.get(j).getName());
                                            break;
                                        }
                                    }
                                    break;
                                }
                            }
                        } else {
                            Toast.makeText(MainActivity.this, "已經是頂層選單", Toast.LENGTH_SHORT).show();
                        }
                        mTitlePopWindow.dismiss();
                        initTitlePopWindow();
                        break;
                    case "新建視窗":
                        AddWebView();
                        mTitlePopWindow.dismiss();
                        break;
                    default:
                        bettWin(which);
                        break;
                }
                break;
            default:
                bettWin(which);
                break;
        }
    }
};

    /**
     * 切換視窗
     *
     * @param which
     */
    private void bettWin(int which) {
        switch (mTitleMenu.get(which).getLayerSign()) {
            case 3:
                //切換視窗
                mIndex = mTitleMenu.get(which).getOnlySign();
                classWebView = mIndex;
                newsWebView[mTitleMenu.get(which).getOnlySign()].setVisibility(View.VISIBLE);
                mWebView = newsWebView[mIndex];
                lblTitle.setText(mTitleMenu.get(which).getName());
                for (int i = 0; i < titlePage.size(); i++) {

                }
                for (int i = 0; i < allTitleList.size(); i++) {
                    if (allTitleList.get(i).size() > 0) {
                        if (allTitleList.get(i).get(0).getOnlySign() == classWebView) {
//                                        upDataAggre(allTitleList.get(i), titlePage);
                            mTitleMenu.clear();
                            mTitleMenu.addAll(allTitleList.get(i));
                            break;
                        }
                    }
                }
                for (int i = 0; i < newsWebView.length; i++) {
                    if (i != mIndex && newsWebView[i] != null) {
                        newsWebView[i].setVisibility(View.GONE);
                    }
                }
                mTitlePopWindow.dismiss();
                break;
            default:
                mWebView.loadUrl(mTitleMenu.get(which).getUrl());
                winClose = which;
                mTitlePopWindow.dismiss();
                break;
        }
    }

/**
 * 右側選單回撥的點選事件
 */
private CommBottomPopWindow.PopWindowListener mPopListener1 = new CommBottomPopWindow.PopWindowListener() {
    @Override
    public void onPopSelected(int which) {
        switch (which) {
            case 0:
                //設定介面
                Toast.makeText(MainActivity.this, "點選了設定", Toast.LENGTH_SHORT).show();
                mpopWindow.dismiss();
                break;
            case 1:
                Toast.makeText(MainActivity.this, "退出系統", Toast.LENGTH_SHORT).show();
                //退出系統
                finish();
                break;
            default:
                mWebView.loadUrl(mRightMenu.get(which).getUrl());
                mpopWindow.dismiss();
                break;
        }
    }
};

/**
 * 設定標題欄點選選單
 */
private void initTitlePopWindow() {
    view = this.getLayoutInflater().inflate(R.layout.comm_popwindow_item, null);
    mTitlePopWindow = new CommBottomPopWindow(this);
    upDataAggre(mTitleMenu, titlePage);
    for (int i = 0; i < allTitleList.size(); i++) {
        if (allTitleList.get(i).size() > 0) {
            if (allTitleList.get(i).get(0).getOnlySign() == classWebView) {
                allTitleList.get(classWebView).clear();
                allTitleList.get(classWebView).addAll(mTitleMenu);
            }
        }
    }
    for (int j = 0; j < mTitleMenu.size() - 1; j++) {
        if (mTitleMenu.get(j).getLayerSign() != mTitleMenu.get(j + 1).getLayerSign()) {
            mTitleMenu.get(j).setLine(true);
        } else {
            mTitleMenu.get(j).setLine(false);
        }
    }
    if (mTitleMenu.get(mTitleMenu.size() - 1).isLine()) {
        mTitleMenu.get(mTitleMenu.size() - 1).setLine(false);
    }
    mTitlePopWindow.initPopItem(mTitleMenu);
    mTitlePopWindow.setPopListener(mPopListener);
}

/**
 * 重新新增標題類
 *
 * @param list1
 * @param list2
 */
private void upDataAggre(List<MainTitleMenu> list1, List<MainTitleMenu> list2) {
    List<MainTitleMenu> tempList = new ArrayList<MainTitleMenu>();
    for (int i = 0; i < list1.size(); i++) {
        if (list1.get(i).getLayerSign() == 3) {
            tempList.add(list1.get(i));
        }
    }
    list1.removeAll(tempList);
    list1.addAll(list2);
}

/**
 * 設定右側彈出框
 */
private void initPopWindow() {
    view = this.getLayoutInflater().inflate(R.layout.comm_popwindow_item, null);
    mpopWindow = new CommBottomPopWindow(this, true);
    mRightMenu.get(1).setLine(true);
    if (mRightMenu.get(mRightMenu.size() - 1).isLine()) {
        mRightMenu.get(mRightMenu.size() - 1).setLine(false);
    }
    mpopWindow.initPopItem(mRightMenu);
    mpopWindow.setPopListener(mPopListener1);
}

private boolean newsWebView() {
    for (int i = 0; i < 6; i++) {
        if (newsWebView[i] != null) {
            webViewState = false;
        } else {
            webViewState = true;
            classWebView = i;
            break;
        }
    }
    if (webViewState) {
        initData();         //每次新建重新初始化資料
        titlePage.add(new MainTitleMenu("歡迎頁", false, currentUrl, 3, classWebView));
        newsWebView[classWebView] = new WebView(this);
        mainframe.addView(newsWebView[classWebView]);
        newsWebView[classWebView].getSettings().setTextZoom(100);

            //jsAndroid 供web端js呼叫標識,修改請通知web開發者
//            newsWebView[classWebView].addJavascriptInterface(new JavaScriptProxy(this), "JSobj");
            newsWebView[classWebView].getSettings().setJavaScriptEnabled(true);
            newsWebView[classWebView].getSettings().setAllowFileAccess(true);
            newsWebView[classWebView].setWebViewClient(new MyWebViewClient());

        newsWebView[classWebView].setWebChromeClient(new WebChromeClient() {

            // For Android  > 4.1.1
            public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
                openFileChooserImpl(uploadMsg);
                mUploadMessage = uploadMsg;
            }

            // For Android  > 3.0
            public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
                if (mUploadMessage != null) return;
                mUploadMessage = uploadMsg;
            }

            // For Android  > 5.0
            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
                openFileChooserImplForAndroid5(filePathCallback);
                return true;
            }

            @Override
            public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
                callback.invoke(origin, true, false);
                super.onGeolocationPermissionsShowPrompt(origin, callback);
            }

            @Override
            public void onPermissionRequest(PermissionRequest request) {
                super.onPermissionRequest(request);
            }

            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                    progress.setProgress(newProgress, true);
                else progress.setProgress(newProgress);
                super.onProgressChanged(view, newProgress);
            }

            @Override
            public void onReceivedTitle(WebView view, String title) {
                super.onReceivedTitle(view, title);
            }

            @Override
            public void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed) {
                super.onReceivedTouchIconUrl(view, url, precomposed);
            }
        });
        newsWebView[classWebView].setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if ((keyCode == KeyEvent.KEYCODE_BACK) && event.getAction() == KeyEvent.ACTION_UP) {
                    if (is_exit) {
                        Intent home = new Intent(Intent.ACTION_MAIN);
                        home.addCategory(Intent.CATEGORY_HOME);
                        startActivity(home);
                    } else {
                        if (newsWebView[classWebView].canGoBack())
                            newsWebView[classWebView].goBack();// 返回鍵退回
                        else finish();
                    }
                    return true;
                } else
                    return false;
            }
        });

    } else {
        Toast.makeText(this, "已達到新視窗上限", Toast.LENGTH_SHORT).show();
    }
    return webViewState;
}

/**
 * 新建視窗
 */
private void AddWebView() {
    if (newsWebView()) {
        //將資料存進總集合
        for (int i = 0; i < allTitleList.size(); i++) {
            if (allTitleList.get(i).size() == 0) {
                allTitleList.get(i).clear();
                allTitleList.get(i).addAll(mTitleMenu);
                break;
            }
        }
        mWebView = newsWebView[classWebView];
        mWebView.loadUrl(mUrl);
    }
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.imgBack:
            mWebView.goBack();
            break;
        case R.id.imgMore:
            initPopWindow();
            mpopWindow.showAsDropDown(boxTitle);
            mpopWindow.show(lblTitle);
            break;
        case R.id.lblTitle:
            //標題選單
            if (titlePage.size() > 1) {
                if (mTitleMenu.get(1).getName().equals("關閉頁面")) {
                } else {
                    mTitleMenu.add(1, new MainTitleMenu("關閉頁面", false, "", 1, classWebView));
                }
            } else {
                for (int i = 0; i < mTitleMenu.size(); i++) {
                    if (mTitleMenu.get(i).getName().equals("關閉頁面")) {
                        mTitleMenu.remove(i);
                        break;
                    }
                }
            }
            initTitlePopWindow();
            mTitlePopWindow.showAsDropDown(boxTitle);
            mTitlePopWindow.show(view);
            break;
        default:
            break;
    }
}


    /*
   *android 4.1以上webview呼叫的圖片方法
   * @param uploadMsg 回撥方法
    */
private void openFileChooserImpl(ValueCallback<Uri> uploadMsg) {
    mUploadMessage = uploadMsg;
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("image/*");
    startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}

/*
android 5.0以上webview呼叫的圖片方法
@param uploadMsg 回撥方法
 */
private void openFileChooserImplForAndroid5(ValueCallback<Uri[]> uploadMsg) {
    mUploadMessageForAndroid5 = uploadMsg;
    Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
    contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
    contentSelectionIntent.setType("image/*");
    Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
    chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
    chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
    startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE_FOR_ANDROID_5);
}

public void setTitleVisibility(boolean visibility) {
    boxTitle.setVisibility(visibility ? View.VISIBLE : View.GONE);
}

public void loadUrl(String url) {
    mWebView.loadUrl(url);
}

private List<MainTitleMenu> list;

/**
 * 頁面發生改變時清空js上層資料
 */
public void clearData() {
    list = new ArrayList<MainTitleMenu>();
    for (int i = 0; i < allTitleList.get(classWebView).size(); i++) {
        if (2 == allTitleList.get(classWebView).get(i).getLayerSign()) {
            list.add(allTitleList.get(classWebView).get(i));
        }
    }
    allTitleList.get(classWebView).remove(list);
    for (int d = 0; d < mTitleMenu.size(); d++) {
        if (2 == mTitleMenu.get(d).getLayerSign()) {
            list.add(mTitleMenu.get(d));
        }
    }
    mTitleMenu.removeAll(list);
    list.clear();
    for (int i = 0; i < mRightMenu.size(); i++) {
        if (2 == mRightMenu.get(i).getLayerSign()) {
            list.add(mRightMenu.get(i));
        }
    }
    mRightMenu.removeAll(list);
    list.clear();
    initTitlePopWindow();
    initPopWindow();
}

private class MyWebViewClient extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
        if (!(url.startsWith("http") || url.startsWith("https"))) {
            return true;
        }
        view.loadUrl(url);
        return true;
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        currentUrl = url;
        Log.d("print", "url___: " + url);
        Toast.makeText(MainActivity.this, "開始載入", Toast.LENGTH_SHORT).show();
        //每次開始載入頁面呼叫
        clearData();
        is_ERROR = false;
        /*
        if (WebConfig.getInstance() == null) return;
        is_exit = false;
        isGoHome = false;
        for (int i = 0; i < WebConfig.getInstance().getHomePagers().size(); i++) {
            if (url.contains(WebConfig.getInstance().getHomePagers().get(i).getHomeurl())) {
                isGoHome = true;
                is_exit = WebConfig.getInstance().getHomePagers().get(i).is_home();
            }
        }
        */
        progress.setVisibility(View.VISIBLE);
        super.onPageStarted(view, url, favicon);
    }

    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        is_ERROR = true;
        super.onReceivedError(view, request, error);
    }

    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        is_ERROR = true;
        super.onReceivedError(view, errorCode, description, failingUrl);
    }

    //頁面載入完成呼叫
    @Override
    public void onPageFinished(WebView view, String url) {
        if (is_ERROR) {
            lblTitle.setText("出錯了");
            for (int i = 0; i < titlePage.size(); i++) {
                if (titlePage.get(i).getOnlySign() == classWebView) {
                    titlePage.get(i).setName("出錯了");
                }
            }
        } else {
            lblTitle.setText(mWebView.getTitle());
            for (int i = 0; i < titlePage.size(); i++) {
                if (titlePage.get(i).getOnlySign() == classWebView) {
                    titlePage.get(i).setName(mWebView.getTitle());
                }
            }
        }
        /*
        if (isGoHome) {
            mWebView.clearHistory();
            mWebView.clearCache(true);
            imgBack.setVisibility(View.INVISIBLE);
        } else {
            imgBack.setVisibility(View.VISIBLE);
        }
        */
        progress.setVisibility(View.GONE);
        super.onPageFinished(view, url);
    }
}
}   

資料物件:MainTitleMenu.java

public class MainTitleMenu {
    private String name;
    private boolean isLine;   //這個暫時不用考慮
    private String url;
    private int layerSign;  //層次標識   //因為我這裡是有兩層不同的資料,一個是固定資料返回首頁關閉視窗等另一個是每個視窗的資料,存在一個集合裡面,所以需要定義一個標識來區分
    private int onlySign;     //唯一標識  這個唯一標識是區分每個WebView頁面的

public int getOnlySign() {
    return onlySign;
}

public void setOnlySign(int onlySign) {
    this.onlySign = onlySign;
}

public MainTitleMenu(String name, boolean isLine, String url, int layerSign) {
    this.name = name;
    this.isLine = isLine;
    this.url = url;
    this.layerSign = layerSign;
}

public MainTitleMenu(String name, boolean isLine, String url, int layerSign, int onlySign) {
    this.name = name;
    this.isLine = isLine;
    this.url = url;
    this.layerSign = layerSign;
    this.onlySign = onlySign;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public boolean isLine() {
    return isLine;
}

public void setLine(boolean line) {
    isLine = line;
}

public String getUrl() {
    return url;
}

public void setUrl(String url) {
    this.url = url;
}

public int getLayerSign() {
    return layerSign;
}

public void setLayerSign(int layerSign) {
    this.layerSign = layerSign;
}
}

自定義popupWindow CommBottomPopWindow.java

public class CommBottomPopWindow extends PopupWindow implements View.OnClickListener {

private Button cancleBtn;

private PopWindowListener listener;

private LinearLayout mLayout;

private Context mContext;

private boolean isHasSubTitle = false;

private LayoutInflater inflater;

public View popRootView;

/**
 * 功能描述: 設定點選事件<br>
 * 〈功能詳細描述〉
 * 點選的自定義回撥介面
 */
public void setPopListener(PopWindowListener listener) {
    this.listener = listener;
}

public CommBottomPopWindow(final Activity context) {
    mContext = context;
    LayoutInflater inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    popRootView = inflater.inflate(R.layout.comme_title_popup, null);
    // 設定SelectPicPopupWindow的View
    this.setContentView(popRootView);
    // 設定SelectPicPopupWindow彈出窗體的寬
    this.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
    // 設定SelectPicPopupWindow彈出窗體的高
    this.setHeight(LinearLayout.LayoutParams.MATCH_PARENT);
    // 設定SelectPicPopupWindow彈出窗體可點選
    this.setFocusable(true);
    this.setOutsideTouchable(true);
    // 重新整理狀態
    this.update();
    // 例項化一個ColorDrawable顏色為半透明
    ColorDrawable dw = new ColorDrawable(0x50000000);
    // 點back鍵和其他地方使其消失,設定了這個才能觸發OnDismisslistener ,設定其他控制元件變化等操作
    this.setBackgroundDrawable(new PaintDrawable());
    this.setBackgroundDrawable(dw);
    initViews();
    initEvents();
}

public CommBottomPopWindow(Activity context, boolean ispop) {
    mContext = context;
    LayoutInflater inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    popRootView = inflater.inflate(R.layout.comm_setup_popwindow, null);
    // 設定SelectPicPopupWindow的View
    this.setContentView(popRootView);
    // 設定SelectPicPopupWindow彈出窗體的寬
    this.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
    // 設定SelectPicPopupWindow彈出窗體的高
    this.setHeight(LinearLayout.LayoutParams.MATCH_PARENT);
    // 設定SelectPicPopupWindow彈出窗體可點選
    this.setFocusable(true);
    this.setOutsideTouchable(true);
    // 重新整理狀態
    this.update();
    // 例項化一個ColorDrawable顏色為半透明
    ColorDrawable dw = new ColorDrawable(0x50000000);
    // 點back鍵和其他地方使其消失,設定了這個才能觸發OnDismisslistener ,設定其他控制元件變化等操作
    this.setBackgroundDrawable(new PaintDrawable());
    this.setBackgroundDrawable(dw);
    initViews();
    initEvents();
}

/**
 * 功能描述:初始化小標題 <br>
 * 頂部是否需要提示的小標題
 */
public void initPopSubTitle(String notiTxt) {
    mLayout.addView(createItem(notiTxt, true));
}

/**
 * 功能描述: 初始化item<br>
 * 〈功能詳細描述〉
 * 動態新增的條目
 */
public void initPopItem(List<MainTitleMenu> list) {
    if (list == null || list.size() == 0) {
        return;
    }

    for (int i = 0; i < list.size(); i++) {
        String title = list.get(i).getName();
        mLayout.addView(createItem(title, i, list.size(), list.get(i).isLine()));
    }
}

private View createItem(String itemTxt, boolean isSubTitle) {
    return createItem(itemTxt, -1, -1, isSubTitle);
}

private View createItem(String itemTxt, final int index, int total) {
    return createItem(itemTxt, index, total, false);
}

/**
 * 功能描述: 建立item<br>
 * 〈功能詳細描述〉
 * <p>
 * 建立具體的條目
 */
private View createItem(String itemTxt, final int index, int total,
                        boolean isSubTitle) {
    inflater = (LayoutInflater) mContext
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.comm_popwindow_item, null);
    LinearLayout layout = (LinearLayout) view
            .findViewById(R.id.comm_popwindow_item_layout);
    View view1 = view.findViewById(R.id.view_title);
    final TextView textView = (TextView) view
            .findViewById(R.id.comm_popwindow_item_txt);
    if (isSubTitle) {
        view1.setVisibility(View.VISIBLE);
    }
    textView.setText(itemTxt);
    textView.setSelected(true);
    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (index == -1) {
                return;
            }
            if (listener != null) {
                listener.onPopSelected(index);
            }
        }
    });
    return view;
}

public void initViews() {
    mLayout = (LinearLayout) popRootView.findViewById(R.id.comm_bottom_popwindow_layout);
    cancleBtn = (Button) popRootView.findViewById(R.id.camp_pop_cancle);
    isHasSubTitle = false;
}

public void initEvents() {
    cancleBtn.setOnClickListener(this);
    popRootView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            dismiss();
        }
    });
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.camp_pop_cancle:
            this.dismiss();
            break;
        default:
            break;
    }
}

/**
 * 功能描述: 顯示pop window<br>
 * 〈功能詳細描述〉
 */
public void show(View view) {
    showAtLocation(view, Gravity.BOTTOM, 0, 0);
}

//回撥介面定義
public interface PopWindowListener {
    public void onPopSelected(int which);
}
}

activity_mian.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.hg.numswebview.MainActivity">

    <LinearLayout
        android:id="@+id/boxTitle"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:background="@color/colorPrimary"
        android:gravity="center_vertical">

        <ImageView
            android:id="@+id/imgBack"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:src="@drawable/ic_chevron_left_white_24dp" />


        <TextView
            android:id="@+id/lblTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginLeft="15dp"
            android:layout_weight="1"
            android:ellipsize="marquee"
            android:focusable="true"
            android:gravity="center"
            android:marqueeRepeatLimit="marquee_forever"
            android:singleLine="true"
            android:text="娃娃瀏覽器"
            android:textColor="@android:color/white"
            android:textSize="18dp" />


        <RelativeLayout
            android:layout_width="45dp"
            android:layout_height="45dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="15dp">

            <ImageView
                android:id="@+id/imgMore"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:src="@drawable/ic_more_vert_white_24dp" />
        </RelativeLayout>
    </LinearLayout>
    <FrameLayout
        android:id="@+id/mainframe"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    <WebView
        android:id="@+id/viewView2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"></WebView>

        <ProgressBar
            android:id="@+id/progress"
            style="@android:style/Widget.Holo.ProgressBar.Horizontal"
            android:layout_width="match_parent"
            android:layout_height="3dp"
            android:max="100"
            android:visibility="invisible" />
        </RelativeLayout>
    </FrameLayout>

</LinearLayout>

還有一些小布局我就不一一貼上來了。
程式碼不難,實現的方式也很low,如果你們有更好的建議不妨互相討論討論