公司在弄一个类似浏览器的框架,主要页面功能都是用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);
上面的示例代码仅用于演示,您需要根据您的实际需求进行修改和调整。