添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

公司在弄一个类似浏览器的框架,主要页面功能都是用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>
 * 〈功能详细描述〉
 * 创建具体的条目
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,如果你们有更好的建议不妨互相讨论讨论

这是demo http://download.csdn.net/download/quietwake/10103249

公司在弄一个类似浏览器的框架,主要页面功能都是用h5,但是领导说要弄成多窗口的,而且还是只在当前Activity中; 主体功能大概如此:头部标题栏实现 标题、菜单列表、多窗口显示等 头部以下就是一个WebView页面,js交互实现页面显示。 听到这个需求我挺头疼,因为在一个Activity中实现多窗口还要实时的保存每个页面的状态 查找了很多资料,跟我这个需求差 示例 这是运行的效果 1.列表使用的是RecyclerView,实现滑动3s之后再缓存网页HTML,每个Item对应于一个HTML。每个HTML获得源码、缓存之后就给Item一个标记 (1)判断滑动3s之后开始预加载: 1 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 2            CountDownTimer countDownTimer; 3 4            @Override 5            public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 6                switch (newState) { 7     
5+webview只需要集成一次时,按照Dcloud官方文档集成。 如果需要集成多次,在之后的activity只需要调用SDK.creatWebview方法,创建出webview,然后添加到布局文件即可 final FrameLayout rootView = (FrameLayout) findViewById(R.id.frameLayout); //使用自己的布局 rootVie
在H5调用window.open是无法打开新窗口的,需要在android添加如下代码才能实现: webSetting.setJavaScriptEnabled(true); webSetting.setSupportMultipleWindows(true); webSetting.setJavaScriptCanOpenWindowsAutomatically(true); 最近忙着app的适配,在这个过程问题,各种机型的奇葩问题都出来了,适配真尼玛痛苦!今天就oppo机型虚拟导航栏遮挡底部的输入框的问题作个记录。 2.解决方法 ① 在该Activity的根layout配置如下属性: android:fitsSystemWindows=true android:clipToPadding=false 第一个属性: 如果为true,将调整系统窗口布局以适应你自定义的布局。 第二个属性: 控件的绘制区域是否在padding里面,值为true时那么绘制的区域就不包括padding区域,默认滚动是在padding(区域)下进行的.然而如果你设置了
画支持 Android 8.0(API 级别 26)允许以画画模式启动 Activity。画画是一种特殊类型的多窗口模式,最常用于视频播放。使用该模式,用户可以通过固定到屏幕一角的小窗口观看视频,同时在应用之间进行导航或浏览主屏幕上的内容。 画画利用 Android 7.0 多窗口模式 API 来提供固定的视频叠加窗口。要将画画添加到您的应用,您需要注册支持画画的 Activity、根据需要将 Activity 切换为画画模式,并确保当 Activity 处于画画模式时,界面元素处于隐藏状态且视频能够继续播放。 画画窗口会显示在屏幕的最上层,位于系统选择的一角。您可以
现在android的每一个项目都会需要设置为全屏,现在介绍两种设置为全屏的方式。 一、在配置文件设置android:theme=”@android:style/Theme.Light.NoTitleBar.Fullscreen” 如: 二、在activity设置 这两种方式都可以设置全屏,任选其一即可。 您可能感兴趣的文章:Android调用默认浏览器打开指定Url的方法实例android webview 简单浏览器实现代码android 浏览器多窗口方案详解Android调用系统默认浏览器访问的方法Android自定义 WebView
Android WebView用于在 android 显示网页。可以从相同的应用程序或 URL 加载网页。它用于在 android 活动显示在线内容。 Android WebView 使用 webkit 引擎来显示网页。 android.webkit.WebView 是 AbsoluteLayout 类的子类。 Android WebView 类的loadUrl()和loadData()方法用于加载和显示网页。 Android WebView 示例 让我们看看使用 Web 视图显示 javat
根据网页的跳转链接在页面的显示方式 分为如下两种: 1、网页的跳转链接还在本Activity页面显示 2、网页的跳转链接在另一个Activity页面显示 就是在多窗口 又多了一个Activity 页面 例如腾讯视频 在Via浏览器 和 小米浏览器 对于跳转链接的处理方式就是不一样的 Via浏览器 : 属于第二种显示模式 直接将跳转页面显示在了 一个新的页面了。 小米浏览器
Android WebView实现消息推送的常见方法是使用JavaScript桥接技术。您可以通过以下步骤实现: 1. 在您的Android项目创建一个类,用于JavaScript桥接,这个类需要继承自`WebViewClient`和`WebChromeClient`。 2. 通过`WebView`的`addJavascriptInterface`方法将Java对象与JavaScript绑定。 3. 在JavaScript使用`window.<object name>.<method name>`来调用Java对象的方法。 4. 在Java对象实现处理JavaScript方法调用的代码。 5. 当需要推送消息时,在Java代码调用JavaScript方法,从而在WebView显示推送消息。 下面是一些简单的示例代码,以便您更好地理解: // 创建一个用于JavaScript桥接的Java类 public class WebViewBridge extends WebViewClient { private WebView mWebView; public WebViewBridge(WebView webView) { mWebView = webView; // 使用addJavascriptInterface方法将Java对象与JavaScript绑定 public void bindJavaScript() { mWebView.addJavascriptInterface(this, "Android"); // 实现处理JavaScript方法调用的代码 @JavascriptInterface public void showToast(String message) { Toast.makeText(mWebView.getContext(), message, Toast.LENGTH_SHORT).show(); // 在Java代码调用JavaScript方法,从而在WebView显示推送消息 public void pushMessage(String message) { mWebView.loadUrl("javascript:showMessage('" + message + "')"); // 在WebView加载一个网页,并将Java对象与JavaScript绑定 WebView webView = (WebView) findViewById(R.id.webview); webView.setWebViewClient(new WebViewBridge(webView)); webView.setWebChromeClient(new WebViewBridge(webView)); WebViewBridge bridge = new WebViewBridge(webView); bridge.bindJavaScript(); webView.loadUrl("http://example.com"); // JavaScript代码 function showMessage(message) { alert(message); 上面的示例代码仅用于演示,您需要根据您的实际需求进行修改和调整。
View view = inflater.inflate(R.layout.comm_popwindow_item, null); LinearLayout layout = (LinearLayout) view .findViewById(R.id.comm_popwindow_item_layout); 这里面的二段请发一下,谢谢