首先,看一下项目完成后的,最终效果是这样的:
一.主界面
二,书签界面
三、主界面
四.操作对话框界面
这几个界面你是否看到了uc浏览器的影子了,其实我说你也可以了,在接下来篇幅中,我将手把手叫大家完成这个浏览器。
首先,我们从主界面开始吧,这是一个主线,项目的一些开始由他开始了。
从图一中,我们可以看出其布局文件主要的布局文件以线性布局为主,而同时了他嵌套了相对布局,有图有真相,下图就是我对主页布局文件一种说明:
从上图的布局文件,我们可以清晰的看出来了,中间viewflipper这个翻页控件有大作用的,里面的一些网页内容将展现如此。
android布局文件固然重要,但只有了代码控制,才能使一个app变得"有血有肉",我们来看看这个主页面的控制文件。
照例了,我们先介绍了一些常量的声明:这些在下面的代码中将会大量的使用,源代码如下:
//滑动像素的入口常量 private static final int FLIP_PIXEL_THRESHOLD = 200; //滑动时间的入口常量 private static final int FLIP_TIME_THRESHOLD = 400; // 添加标签的菜单常量 private static final int MENU_ADD_BOOKMARK = Menu.FIRST; //展示标签的菜单常量 private static final int MENU_SHOW_BOOKMARKS = Menu.FIRST + 1; //展示下载的菜单常量 private static final int MENU_SHOW_DOWNLOADS = Menu.FIRST + 2; //喜爱的菜单常量 private static final int MENU_PREFERENCES = Menu.FIRST + 3; //退出的菜单常量 private static final int MENU_EXIT = Menu.FIRST + 4; //打开的上下文菜单常量 private static final int CONTEXT_MENU_OPEN = Menu.FIRST + 10; //打开新的菜单常量 private static final int CONTEXT_MENU_OPEN_IN_NEW_TAB = Menu.FIRST + 11; //下载的上下文菜单常量 private static final int CONTEXT_MENU_DOWNLOAD = Menu.FIRST + 12; //拷贝的菜单常量 private static final int CONTEXT_MENU_COPY = Menu.FIRST + 13; //发送具体的上下文菜单常量 private static final int CONTEXT_MENU_SEND_MAIL = Menu.FIRST + 14; //分享上下文菜单常量 private static final int CONTEXT_MENU_SHARE = Menu.FIRST + 15; //打开标签历史记录的页面常量 private static final int OPEN_BOOKMARKS_HISTORY_ACTIVITY = 0; //打开下载的页面常量 private static final int OPEN_DOWNLOADS_ACTIVITY = 1; //打开文件选择的界面的常量 private static final int OPEN_FILE_CHOOSER_ACTIVITY = 2; //全频的常量 protected static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
观察上面各个变量,我们可以得出来这样的结论:
①程序将会利用一些菜单,上下文菜单进行添加书签,书签,退出的操作。
②主界面全屏形式将会大量利用。
接下来,是一些控件变量的声明,源代码如下:
// 填充器 protected LayoutInflater mInflater = null; //顶部的线性布局文件 private LinearLayout mTopBar; //底部 线性布局文件 private LinearLayout mBottomBar; private LinearLayout mFindBar; //前一步按钮 private ImageButton mFindPreviousButton; //下一步按钮 private ImageButton mFindNextButton; //关闭的按钮 private ImageButton mFindCloseButton; //文本框 private EditText mFindText; //前一步视图 private ImageView mPreviousTabView; //下一步的视图 private ImageView mNextTabView; //工具按钮 private ImageButton mToolsButton; //自动匹配文本框 private AutoCompleteTextView mUrlEditText; //前往的按钮 private ImageButton mGoButton; //进度条 private ProgressBar mProgressBar; //右边imageviw private ImageView mBubbleRightView; //左边的imageview private ImageView mBubbleLeftView; //当前的web视图 private CustomWebView mCurrentWebView; //所有的打开的web的视图 private List<CustomWebView> mWebViews; //前面按钮 private ImageButton mPreviousButton; //下一步的按钮 private ImageButton mNextButton; //开启一个tab按钮 private ImageButton mNewTabButton; //移去tab的按钮 private ImageButton mRemoveTabButton; //快速进入的按钮 private ImageButton mQuickButton; //当前的背景 private Drawable mCircularProgress; //url 是否显示 private boolean mUrlBarVisible; //工具grid 是否显示 private boolean mToolsActionGridVisible = false; //对话框是否显示 private boolean mFindDialogVisible = false; //url的监听者 private TextWatcher mUrlTextWatcher; //开启的多线程 private HideToolbarsRunnable mHideToolbarsRunnable; //翻页的控件 private ViewFlipper mViewFlipper; //手势的监听者 private GestureDetector mGestureDetector; //换tab的枚举 private SwitchTabsMethod mSwitchTabsMethod = SwitchTabsMethod.BOTH; //action的grid private QuickActionGrid mToolsActionGrid; //消息URL private ValueCallback<Uri> mUploadMessage; //改变的监听者 private OnSharedPreferenceChangeListener mPreferenceChangeListener; private View mCustomView; //当前的 private Bitmap mDefaultVideoPoster = null; private View mVideoProgressView = null; //桢不具 private FrameLayout mFullscreenContainer; //相应回调 private WebChromeClient.CustomViewCallback mCustomViewCallback; //改变tab的枚举 private enum SwitchTabsMethod { BUTTONS, FLING, BOTH }
通过上述一些变量的声明,我们应该明白这么几点了
①主要控件声明是一些上局布局文件中的控件的声明。
②取此之外,一些判断其是否显示隐藏的变量,一些保存当前webview的变量,一些保存当前webview视图也在此申明了,相应回调的接口。
③此外,还有一个tab页改变方式的申明。
接下来,重头戏——方法实现就来了。首先是一个oncreate方法,是进行数据的初始化。
/** * 数据的初始化 */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); INSTANCE = this; Constants.initializeConstantsFromResources(this); Controller.getInstance().setPreferences(PreferenceManager.getDefaultSharedPreferences(this)); if (Controller.getInstance().getPreferences().getBoolean(Constants.PREFERENCES_SHOW_FULL_SCREEN, false)) { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } if (Controller.getInstance().getPreferences().getBoolean(Constants.PREFERENCES_GENERAL_HIDE_TITLE_BARS, true)) { requestWindowFeature(Window.FEATURE_NO_TITLE); } setProgressBarVisibility(true); setContentView(R.layout.main); mCircularProgress = getResources().getDrawable(R.drawable.spinner); EventController.getInstance().addDownloadListener(this); mHideToolbarsRunnable = null; mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); buildComponents(); mViewFlipper.removeAllViews(); updateSwitchTabsMethod(); updateBookmarksDatabaseSource(); registerPreferenceChangeListener(); Intent i = getIntent(); if (i.getData() != null) { // App first launch from another app. addTab(false); navigateToUrl(i.getDataString()); } else { // Normal start. int currentVersionCode = ApplicationUtils.getApplicationVersionCode(this); int savedVersionCode = PreferenceManager.getDefaultSharedPreferences(this).getInt(Constants.PREFERENCES_LAST_VERSION_CODE, -1); // If currentVersionCode and savedVersionCode are different, the application has been updated. if (currentVersionCode != savedVersionCode) { // Save current version code. Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit(); editor.putInt(Constants.PREFERENCES_LAST_VERSION_CODE, currentVersionCode); editor.commit(); // Display changelog dialog. Intent changelogIntent = new Intent(this, ChangelogActivity.class); startActivity(changelogIntent); } boolean lastPageRestored = false; if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(Constants.PREFERENCES_BROWSER_RESTORE_LAST_PAGE, false)) { if (savedInstanceState != null) { String savedUrl = savedInstanceState.getString(Constants.EXTRA_SAVED_URL); if (savedUrl != null) { addTab(false); navigateToUrl(savedUrl); lastPageRestored = true; } } } if (!lastPageRestored) { addTab(true); } } initializeWebIconDatabase(); startToolbarsHideRunnable(); }
从上述的源代码,我们可以清楚看出啦:
①,相应的初始化的内容,是从sharedprefrence这个xml文件中读取相应是否全屏啊,是否有标题这些所谓变量,来决定他显示显示相应的内容。
②,在这里进行相应数据化的初始化。
③,找到相应的控件。
④,未控件赋予相应事件的监听。
⑤,导航到相应的界面
接下来的源代码了,主要是解决退出销毁数据,保存数据的方法,开启新意图的方法。
/** * 销毁界面 */ @Override protected void onDestroy() { WebIconDatabase.getInstance().close(); if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(Constants.PREFERENCES_PRIVACY_CLEAR_CACHE_ON_EXIT, false)) { mCurrentWebView.clearCache(true); } EventController.getInstance().removeDownloadListener(this); PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(mPreferenceChangeListener); super.onDestroy(); } /** * 保存相应的数据 */ @Override protected void onSaveInstanceState(Bundle outState) { outState.putString(Constants.EXTRA_SAVED_URL, mCurrentWebView.getUrl()); super.onSaveInstanceState(outState); } /** * Handle url request from external apps. * @param intent The intent. */ @Override protected void onNewIntent(Intent intent) { if (intent.getData() != null) { addTab(false); navigateToUrl(intent.getDataString()); } setIntent(intent); super.onNewIntent(intent); }
我们得出来这样的结论了,功能有三
①保存数据,将相应的URL数据保存起来。
②退出时候,判断这个是否需要清空相应的缓存,将相应的sharedpreference的监听者移除。
③开启新的一个意图的时候,导航到相应URL的页面,开始新的意图。
在上面oncreate的方法中,我们说到了他有初始化控件的方法,那长成了什么样子了,我们来瞧一瞧:
/** * Create main UI. */ private void buildComponents() { mToolsActionGrid = new QuickActionGrid(this); mToolsActionGrid.addQuickAction(new QuickAction(this, R.drawable.ic_btn_home, R.string.QuickAction_Home)); mToolsActionGrid.addQuickAction(new QuickAction(this, R.drawable.ic_btn_share, R.string.QuickAction_Share)); mToolsActionGrid.addQuickAction(new QuickAction(this, R.drawable.ic_btn_find, R.string.QuickAction_Find)); mToolsActionGrid.addQuickAction(new QuickAction(this, R.drawable.ic_btn_select, R.string.QuickAction_SelectText)); mToolsActionGrid.addQuickAction(new QuickAction(this, R.drawable.ic_btn_mobile_view, R.string.QuickAction_MobileView)); mToolsActionGrid.setOnQuickActionClickListener(new OnQuickActionClickListener() { @Override public void onQuickActionClicked(QuickActionWidget widget, int position) { switch (position) { case 0: navigateToHome(); break; case 1: ApplicationUtils.sharePage(MainActivity.this, mCurrentWebView.getTitle(), mCurrentWebView.getUrl()); break; case 2: // Somewhat dirty hack: when the find dialog was shown from a QuickAction, // the soft keyboard did not show... Hack is to wait a little before showing // the file dialog through a thread. startShowFindDialogRunnable(); break; case 3: swithToSelectAndCopyTextMode(); break; case 4: String currentUrl = mUrlEditText.getText().toString(); // Do not reload mobile view if already on it. if (!currentUrl.startsWith(Constants.URL_GOOGLE_MOBILE_VIEW_NO_FORMAT)) { String url = String.format(Constants.URL_GOOGLE_MOBILE_VIEW, mUrlEditText.getText().toString()); navigateToUrl(url); } break; } } }); mToolsActionGrid.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { mToolsActionGridVisible = false; startToolbarsHideRunnable(); } }); mGestureDetector = new GestureDetector(this, new GestureListener()); mUrlBarVisible = true; mWebViews = new ArrayList<CustomWebView>(); Controller.getInstance().setWebViewList(mWebViews); mBubbleRightView = (ImageView) findViewById(R.id.BubbleRightView); mBubbleRightView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setToolbarsVisibility(true); } }); mBubbleRightView.setVisibility(View.GONE); mBubbleLeftView = (ImageView) findViewById(R.id.BubbleLeftView); mBubbleLeftView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setToolbarsVisibility(true); } }); mBubbleLeftView.setVisibility(View.GONE); mViewFlipper = (ViewFlipper) findViewById(R.id.ViewFlipper); mTopBar = (LinearLayout) findViewById(R.id.BarLayout); mTopBar.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // Dummy event to steel it from the WebView, in case of clicking between the buttons. } }); mBottomBar = (LinearLayout) findViewById(R.id.BottomBarLayout); mBottomBar.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // Dummy event to steel it from the WebView, in case of clicking between the buttons. } }); mFindBar = (LinearLayout) findViewById(R.id.findControls); mFindBar.setVisibility(View.GONE); mPreviousTabView = (ImageView) findViewById(R.id.PreviousTabView); mPreviousTabView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showPreviousTab(true); } }); mPreviousTabView.setVisibility(View.GONE); mNextTabView = (ImageView) findViewById(R.id.NextTabView); mNextTabView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showNextTab(true); } }); mNextTabView.setVisibility(View.GONE); String[] from = new String[] {UrlSuggestionCursorAdapter.URL_SUGGESTION_TITLE, UrlSuggestionCursorAdapter.URL_SUGGESTION_URL}; int[] to = new int[] {R.id.AutocompleteTitle, R.id.AutocompleteUrl}; UrlSuggestionCursorAdapter adapter = new UrlSuggestionCursorAdapter(this, R.layout.url_autocomplete_line, null, from, to); adapter.setCursorToStringConverter(new CursorToStringConverter() { @Override public CharSequence convertToString(Cursor cursor) { String aColumnString = cursor.getString(cursor.getColumnIndex(UrlSuggestionCursorAdapter.URL_SUGGESTION_URL)); return aColumnString; } }); adapter.setFilterQueryProvider(new FilterQueryProvider() { @Override public Cursor runQuery(CharSequence constraint) { if ((constraint != null) && (constraint.length() > 0)) { return BookmarksProviderWrapper.getUrlSuggestions(getContentResolver(), constraint.toString(), PreferenceManager.getDefaultSharedPreferences(MainActivity.this).getBoolean(Constants.PREFERENCE_USE_WEAVE, false)); } else { return BookmarksProviderWrapper.getUrlSuggestions(getContentResolver(), null, PreferenceManager.getDefaultSharedPreferences(MainActivity.this).getBoolean(Constants.PREFERENCE_USE_WEAVE, false)); } } }); mUrlEditText = (AutoCompleteTextView) findViewById(R.id.UrlText); mUrlEditText.setThreshold(1); mUrlEditText.setAdapter(adapter); mUrlEditText.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER) { navigateToUrl(); return true; } return false; } }); mUrlTextWatcher = new TextWatcher() { @Override public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { } @Override public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { } @Override public void afterTextChanged(Editable arg0) { updateGoButton(); } }; mUrlEditText.addTextChangedListener(mUrlTextWatcher); mUrlEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { // Select all when focus gained. if (hasFocus) { mUrlEditText.setSelection(0, mUrlEditText.getText().length()); } } }); mUrlEditText.setCompoundDrawablePadding(5); mGoButton = (ImageButton) findViewById(R.id.GoBtn); mGoButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if (mCurrentWebView.isLoading()) { mCurrentWebView.stopLoading(); } else if (!mCurrentWebView.isSameUrl(mUrlEditText.getText().toString())) { navigateToUrl(); } else { mCurrentWebView.reload(); } } }); mToolsButton = (ImageButton) findViewById(R.id.ToolsBtn); mToolsButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mToolsActionGridVisible = true; mToolsActionGrid.show(v); } }); mProgressBar = (ProgressBar) findViewById(R.id.WebViewProgress); mProgressBar.setMax(100); mPreviousButton = (ImageButton) findViewById(R.id.PreviousBtn); mNextButton = (ImageButton) findViewById(R.id.NextBtn); mPreviousButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { navigatePrevious(); } }); mNextButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { navigateNext(); } }); mNewTabButton = (ImageButton) findViewById(R.id.NewTabBtn); mNewTabButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { addTab(true); } }); mRemoveTabButton = (ImageButton) findViewById(R.id.RemoveTabBtn); mRemoveTabButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if (mViewFlipper.getChildCount() == 1 && !mCurrentWebView.getUrl().equals(Constants.URL_ABOUT_START)) { navigateToHome(); updateUI(); updatePreviousNextTabViewsVisibility(); } else removeCurrentTab(); } }); mQuickButton = (ImageButton) findViewById(R.id.QuickBtn); mQuickButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { onQuickButton(); } }); mFindPreviousButton = (ImageButton) findViewById(R.id.find_previous); mFindPreviousButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCurrentWebView.findNext(false); hideKeyboardFromFindDialog(); } }); mFindNextButton = (ImageButton) findViewById(R.id.find_next); mFindNextButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCurrentWebView.findNext(true); hideKeyboardFromFindDialog(); } }); mFindCloseButton = (ImageButton) findViewById(R.id.find_close); mFindCloseButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { closeFindDialog(); } }); mFindText = (EditText) findViewById(R.id.find_value); mFindText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { doFind(); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } }); }
由这一大堆源代码,我们可以总结出这样的功能特点:
①我们为了满足自己的代码的需求初始化了QuickActionGrid这个控件,这个控件添加了主页,标签,添加标签功能到这个控件中。
②为了QuickActionGrid这个控件,赋予相应的事件,不同的事件做不同的动作。
③监听了相应动作手势的变化。
④找到相应的按钮控件,赋予相应的按钮控件的点击事件。
⑤实例化相应progressbar,使他的最大值是100.
⑥找到相应的匹配的文本框,从而为其监听文本变化的事件,从而完全实现匹配的效果。
⑦声明一个adapter,把相应数据填充出来。
这个重头戏介绍完成以后,我们在看看sharedpreference中处理方法,这些处理方法,主要是处理一些配置类的信息。
/** * 注册一个preference的监听者 */ private void registerPreferenceChangeListener() { mPreferenceChangeListener = new OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals(Constants.PREFERENCE_BOOKMARKS_DATABASE)) { updateBookmarksDatabaseSource(); } } }; PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(mPreferenceChangeListener); } /** * Apply preferences to the current UI objects. */ public void applyPreferences() { // To update to Bubble position. setToolbarsVisibility(false); updateSwitchTabsMethod(); for (CustomWebView view : mWebViews) { view.initializeOptions(); } }
这段代码给予我们起始有这么几点:
①读取相应的数据库配置信息,更新标签的数据源。为相应的数据类注册一个监听者。
②为相应ui 对象赋值一些数据信息。
浏览器中webview是一个浏览器重中之重,我们在下面篇幅中,主要来自己初始化一个webview,源代码如下:
/** * Initialize a newly created WebView. */ private void initializeCurrentWebView() { mCurrentWebView.setWebViewClient(new CustomWebViewClient(this)); mCurrentWebView.setOnTouchListener(this); mCurrentWebView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() { @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { HitTestResult result = ((WebView) v).getHitTestResult(); int resultType = result.getType(); if ((resultType == HitTestResult.ANCHOR_TYPE) || (resultType == HitTestResult.IMAGE_ANCHOR_TYPE) || (resultType == HitTestResult.SRC_ANCHOR_TYPE) || (resultType == HitTestResult.SRC_IMAGE_ANCHOR_TYPE)) { Intent i = new Intent(); i.putExtra(Constants.EXTRA_ID_URL, result.getExtra()); MenuItem item = menu.add(0, CONTEXT_MENU_OPEN, 0, R.string.Main_MenuOpen); item.setIntent(i); item = menu.add(0, CONTEXT_MENU_OPEN_IN_NEW_TAB, 0, R.string.Main_MenuOpenNewTab); item.setIntent(i); item = menu.add(0, CONTEXT_MENU_COPY, 0, R.string.Main_MenuCopyLinkUrl); item.setIntent(i); item = menu.add(0, CONTEXT_MENU_DOWNLOAD, 0, R.string.Main_MenuDownload); item.setIntent(i); item = menu.add(0, CONTEXT_MENU_SHARE, 0, R.string.Main_MenuShareLinkUrl); item.setIntent(i); menu.setHeaderTitle(result.getExtra()); } else if (resultType == HitTestResult.IMAGE_TYPE) { Intent i = new Intent(); i.putExtra(Constants.EXTRA_ID_URL, result.getExtra()); MenuItem item = menu.add(0, CONTEXT_MENU_OPEN, 0, R.string.Main_MenuViewImage); item.setIntent(i); item = menu.add(0, CONTEXT_MENU_COPY, 0, R.string.Main_MenuCopyImageUrl); item.setIntent(i); item = menu.add(0, CONTEXT_MENU_DOWNLOAD, 0, R.string.Main_MenuDownloadImage); item.setIntent(i); item = menu.add(0, CONTEXT_MENU_SHARE, 0, R.string.Main_MenuShareImageUrl); item.setIntent(i); menu.setHeaderTitle(result.getExtra()); } else if (resultType == HitTestResult.EMAIL_TYPE) { Intent sendMail = new Intent(Intent.ACTION_VIEW, Uri.parse(WebView.SCHEME_MAILTO + result.getExtra())); MenuItem item = menu.add(0, CONTEXT_MENU_SEND_MAIL, 0, R.string.Main_MenuSendEmail); item.setIntent(sendMail); Intent i = new Intent(); i.putExtra(Constants.EXTRA_ID_URL, result.getExtra()); item = menu.add(0, CONTEXT_MENU_COPY, 0, R.string.Main_MenuCopyEmailUrl); item.setIntent(i); item = menu.add(0, CONTEXT_MENU_SHARE, 0, R.string.Main_MenuShareEmailUrl); item.setIntent(i); menu.setHeaderTitle(result.getExtra()); } } }); mCurrentWebView.setDownloadListener(new DownloadListener() { @Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { doDownloadStart(url, userAgent, contentDisposition, mimetype, contentLength); } }); final Activity activity = this; mCurrentWebView.setWebChromeClient(new WebChromeClient() { @SuppressWarnings("unused") // This is an undocumented method, it _is_ used, whatever Eclipse may think :) // Used to show a file chooser dialog. public void openFileChooser(ValueCallback<Uri> uploadMsg) { mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); MainActivity.this.startActivityForResult( Intent.createChooser(i, MainActivity.this.getString(R.string.Main_FileChooserPrompt)), OPEN_FILE_CHOOSER_ACTIVITY); } @Override public Bitmap getDefaultVideoPoster() { if (mDefaultVideoPoster == null) { mDefaultVideoPoster = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.drawable.default_video_poster); } return mDefaultVideoPoster; } @Override public View getVideoLoadingProgressView() { if (mVideoProgressView == null) { LayoutInflater inflater = LayoutInflater.from(MainActivity.this); mVideoProgressView = inflater.inflate(R.layout.video_loading_progress, null); } return mVideoProgressView; } public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) { showCustomView(view, callback); } @Override public void onHideCustomView() { hideCustomView(); } // @Override // public void onShowCustomView(View view, CustomViewCallback callback) { // super.onShowCustomView(view, callback); // // if (view instanceof FrameLayout) { // mCustomViewContainer = (FrameLayout) view; // mCustomViewCallback = callback; // // mContentView = (LinearLayout) findViewById(R.id.MainContainer); // // if (mCustomViewContainer.getFocusedChild() instanceof VideoView) { // mCustomVideoView = (VideoView) mCustomViewContainer.getFocusedChild(); // // frame.removeView(video); // mContentView.setVisibility(View.GONE); // mCustomViewContainer.setVisibility(View.VISIBLE); // // setContentView(mCustomViewContainer); // //mCustomViewContainer.bringToFront(); // // mCustomVideoView.setOnCompletionListener(new OnCompletionListener() { // @Override // public void onCompletion(MediaPlayer mp) { // mp.stop(); // onHideCustomView(); // } // }); // // mCustomVideoView.setOnErrorListener(new OnErrorListener() { // @Override // public boolean onError(MediaPlayer mp, int what, int extra) { // onHideCustomView(); // return true; // } // }); // // mCustomVideoView.start(); // } // // } // } // // @Override // public void onHideCustomView() { // super.onHideCustomView(); // // if (mCustomVideoView == null) { // return; // } // // mCustomVideoView.setVisibility(View.GONE); // mCustomViewContainer.removeView(mCustomVideoView); // mCustomVideoView = null; // // mCustomViewContainer.setVisibility(View.GONE); // mCustomViewCallback.onCustomViewHidden(); // // mContentView.setVisibility(View.VISIBLE); // setContentView(mContentView); // } @Override public void onProgressChanged(WebView view, int newProgress) { ((CustomWebView) view).setProgress(newProgress); mProgressBar.setProgress(mCurrentWebView.getProgress()); } @Override public void onReceivedIcon(WebView view, Bitmap icon) { new Thread(new FaviconUpdaterRunnable(MainActivity.this, view.getUrl(), view.getOriginalUrl(), icon)).start(); updateFavIcon(); super.onReceivedIcon(view, icon); } @Override public boolean onCreateWindow(WebView view, final boolean dialog, final boolean userGesture, final Message resultMsg) { WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; addTab(false, mViewFlipper.getDisplayedChild()); transport.setWebView(mCurrentWebView); resultMsg.sendToTarget(); return true; } @Override public void onReceivedTitle(WebView view, String title) { setTitle(String.format(getResources().getString(R.string.ApplicationNameUrl), title)); startHistoryUpdaterRunnable(title, mCurrentWebView.getUrl(), mCurrentWebView.getOriginalUrl()); super.onReceivedTitle(view, title); } @Override public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { new AlertDialog.Builder(activity) .setTitle(R.string.Commons_JavaScriptDialog) .setMessage(message) .setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { result.confirm(); } }) .setCancelable(false) .create() .show(); return true; } @Override public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { new AlertDialog.Builder(MainActivity.this) .setTitle(R.string.Commons_JavaScriptDialog) .setMessage(message) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { result.confirm(); } }) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { result.cancel(); } }) .create() .show(); return true; } @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) { final LayoutInflater factory = LayoutInflater.from(MainActivity.this); final View v = factory.inflate(R.layout.javascript_prompt_dialog, null); ((TextView) v.findViewById(R.id.JavaScriptPromptMessage)).setText(message); ((EditText) v.findViewById(R.id.JavaScriptPromptInput)).setText(defaultValue); new AlertDialog.Builder(MainActivity.this) .setTitle(R.string.Commons_JavaScriptDialog) .setView(v) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String value = ((EditText) v.findViewById(R.id.JavaScriptPromptInput)).getText() .toString(); result.confirm(value); } }) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { result.cancel(); } }) .setOnCancelListener( new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { result.cancel(); } }) .show(); return true; } }); }
对于这个方法,我们需要对其进行讨论,
①他需要对其相应按键做出正常的处理,判断他是按键不同,进行不同操作。
②对其相应的下载的接口进行了监听,进行webclient下载的处理。
③对其文件上传,作起处理,跳转到文件上传的页面。
④对其view进行了处理,使其相应progress的view文件进行填充。
⑤创建一个窗体,使其显示是该指定的webview。
⑥对弹出来js源代码进行处理,使其页面上的js代码在webview能够正常的显示。
在该浏览器中添加相应的tab页,是一个重要的功能,因此我们分析分析,源代码如下:
/** * Add a new tab. * @param navigateToHome If True, will load the user home page. * @param parentIndex The index of the new tab. */ private void addTab(boolean navigateToHome, int parentIndex) { if (mFindDialogVisible) { closeFindDialog(); } RelativeLayout view = (RelativeLayout) mInflater.inflate(R.layout.webview, mViewFlipper, false); mCurrentWebView = (CustomWebView) view.findViewById(R.id.webview); initializeCurrentWebView(); synchronized (mViewFlipper) { if (parentIndex != -1) { mWebViews.add(parentIndex + 1, mCurrentWebView); mViewFlipper.addView(view, parentIndex + 1); } else { mWebViews.add(mCurrentWebView); mViewFlipper.addView(view); } mViewFlipper.setDisplayedChild(mViewFlipper.indexOfChild(view)); } updateUI(); updatePreviousNextTabViewsVisibility(); mUrlEditText.clearFocus(); if (navigateToHome) { navigateToHome(); } } /** * Remove the current tab. */ private void removeCurrentTab() { if (mFindDialogVisible) { closeFindDialog(); } int removeIndex = mViewFlipper.getDisplayedChild(); mCurrentWebView.doOnPause(); synchronized (mViewFlipper) { mViewFlipper.removeViewAt(removeIndex); mViewFlipper.setDisplayedChild(removeIndex - 1); mWebViews.remove(removeIndex); } mCurrentWebView = mWebViews.get(mViewFlipper.getDisplayedChild()); updateUI(); updatePreviousNextTabViewsVisibility(); mUrlEditText.clearFocus(); }
我们首先
①找到相应的viewflipper控件,在viewflipper中,显示到该初始化webview。并且对其计数器加一,当前文本框失去焦点。
②移去view的时候,在webview移去,计数器减一,界面更新,文本框失去焦点。
有了这些主要的方法做支持,一个webview就这样显示出来,下节主要讲①一个网页显示在webview控件中,②如何正常隐藏显示标题栏。③如何用runnable来更加快速的显示网页,不使其页面实现卡顿。