• Android网络:开发浏览器(一)——基本的浏览网页功能开发


            我们定义这个版本为1.0版本。

        首先,因为要制作一个浏览器,那么就不能通过调用内置浏览器来实现网页的浏览功能,但是可以使用WebView组件来进行。

        在此之前,我们可以来看看两种网页显示方式:

        1.  Intent调用内置浏览器

    Uri uri = Uri.parse("http://www.baidu.com");

    Intent launchBrowser = new Intent(Intent.ACTION_VIEW, uri);

    startActivity(launchBrowser);

    代码片段10.1.1  Intent调用显示网页

       

        2.  WebView显示网页

    <WebView

           android:id="@+id/web_holder"

           android:layout_width="match_parent"

           android:layout_height="wrap_content"

           />

    代码片段10.1.2  WebView设置在layout布局文件中

       

    WebView webHolder = (WebView) this.findViewById(R.id.web_holder);

    webHolder.loadUrl("http://www.baidu.com");

    代码片段10.1.3  WebView调用显示

       

        以上就是两种调用方式,现在我们通过WebView来简单的实现网页显示的功能。

       

        我们先添加一个WebView给Activity,不过需要注意的是,如果想要调用本应用程序的WebView来显示网页,则需要重写webViewClienet,而且在之前先要进行编码的设置,大致如下:

    package com.example.androidstudy_web;

     

    import android.app.Activity;

    import android.os.Bundle;

    import android.view.Menu;

    import android.webkit.WebSettings;

    import android.webkit.WebView;

    import android.webkit.WebViewClient;

     

    public class MainActivity extends Activity {

     

       private WebView webHolder;

       private WebSettings settings;

       private WebViewClient client;

      

       @Override

       protected void onCreate(Bundle savedInstanceState) {

          super.onCreate(savedInstanceState);

          setContentView(R.layout.activity_main);

         

          this.webHolder = (WebView) this.findViewById(R.id.web_holder);

          this.settings = this.webHolder.getSettings();

          this.client = new OwnerWebView();

         

          this.settings.setDefaultTextEncodingName("UTF-8");

         

          this.webHolder.setWebViewClient(this.client);

         

          this.webHolder.loadUrl("http://www.baidu.com");

         

       }

     

       @Override

       public boolean onCreateOptionsMenu(Menu menu) {

          getMenuInflater().inflate(R.menu.main, menu);

          return true;

       }

      

       private class OwnerWebView extends WebViewClient{

     

          @Override

          public boolean shouldOverrideUrlLoading(WebView view, String url) {

             view.loadUrl(url);

             return true;

          }

         

       }

     

    }

    代码片段10.1.4  简单的浏览器

       

        基本的功能做完了,这个浏览器现在能做的就是显示一个百度页面,而我们不能更改。那么接下来的工作就是给它添加一个地址输入栏了。

       

        我们可以设置一个LinerLayout,作为导航,里面包括地址栏和一个按钮,我们可以添加按钮监听事件,当点击的时候进行地址载入,当然,这个地址得进行检测:

    private class ButtonClickedListener implements OnClickListener{

     

          @Override

          public void onClick(View v) {

             if(v.getId()==R.id.web_url_goto){

                String url = webUrlStr.getText().toString();

                if(URLUtil.isNetworkUrl(url)&&URLUtil.isValidUrl(url)){

                    webHolder.loadUrl(url);

                }else{

                    new AlertDialog.Builder(MainActivity.this)

                       .setTitle("警告")

                      .setMessage("不是有效的网址")

                       .create()

                       .show();

                }

             }

          }

         

       }

    代码片段10.1.5  按钮事件监听

    <EditText

               android:id="@+id/web_url_input"

               android:layout_width="0dp"

               android:layout_height="match_parent"

               android:layout_weight="0.8"

               android:hint="@string/webUrlHint"

               android:inputType="textUri"

              />

            <Button

               android:id="@+id/web_url_goto"

               android:layout_width="0dp"

               android:layout_height="match_parent"

                android:layout_weight="0.2"

               android:text="@string/webUrlGoto"

               />

    代码片段10.1.6  导航栏

       

    需要注意的是地址栏的inputType设置,因为我们需要输入的是一个网址,所以这里的输入类型需要更改为textUri

    现在基本功能已经做好,在这个基本功能的基础上,我们可以进行一些完善。

    比如:

    1.  在输入地址的情况下,具有自动提示的功能

    2.  在输入的构成中判断地址的有效性,有效按钮为“进入”,无效为“取消”

     

    要实现这个其实还是比较简单的,就是监听输入的改变情况,来验证地址的有效性,以此判断按钮是否为“进入”状态。

    实现这个需要实现TextWatcher接口:

    /**

        * TextWatcher自定义继承类

        * 覆盖方法如下:

        * 1. afterTextChanged

        * 2. beforeTextChanged

        * 3. onTextChanged

        *     实现更改地址的时候进行地址合法性检测

        * */

       private class WebUrlStrChangedListener implements TextWatcher{

     

          @Override

          public void afterTextChanged(Editable editable) {

          }

          @Override

          public void beforeTextChanged(CharSequence charsequence, int i, int j,

                int k) {

         

    }

     

          @Override

          public void onTextChanged(CharSequence charsequence, int i, int j, int k) {

             url = charsequence.toString();

             if(!(url.startsWith("http://")||url.startsWith("https://"))){

                url = "http://"+url;

             }

             Log.d(DEG_TAG,"onchangeText:"+url);

             if(URLUtil.isNetworkUrl(url)&&URLUtil.isValidUrl(url)){

                //改变按钮的函数实现

                changeStatueOfWebGoto(true);

             }else{

                changeStatueOfWebGoto(false);

             }

          }

         

       }

    代码片段10.1.7  TextWacher实现类

    3.  找不到网站的时候就以百度为默认搜索,进行搜索

     

    这个功能,因为需要判断是否能找到网站,所以我通过异常的处理来进行这个操作,当出现无法找到网页的时候,它就会返回一个errorCode,这个errorCode的所有值都为负数,而无法找到网页的错误代号为-2,所以判断返回的errorCode是否等于-2,如果相等,则将输入的内容作为搜索关键字处理。

        关键代码:

    if(errorCode==WebViewClient.ERROR_HOST_LOOKUP){

                //找不到页面,调用百度搜搜

                url = "http://www.baidu.com/baidu?word=" + url;

                Log.d(DEG_TAG, "errorRedirect:"+url);

                webHolder.loadUrl(url);

             }

    代码片段10.1.8  找不到页面,调用百度搜索

    这个监控的是通过继承WebViewClient,然后覆盖里面的onReceivedError方法进行实现。

    4.  按物理返回键返回前一个页面,按两次退出

     

    在Activity中,自己默认有一个onBackPressed方法,这个方法是用来实现按物理返回键的方法的,其实可以通过覆盖keydown的方法来实现,不过这个更改好些。

    @Override

       public void onBackPressed() {

          //判断是否可后退,是则后退,否则按两次退出程序

          if(webHolder.canGoBack()){

             webHolder.goBack();

             //更改其他按钮状态(不妨碍物理返回效果的实现)

             //changeStatueOfWebToolsButton();

          }else{

             if(!isExit){

                isExit = true;

                Toast.makeText(getApplicationContext(), "再按一次退出程序",

                           Toast.LENGTH_SHORT).show();

                handler.sendEmptyMessageDelayed(0,2000);

             }else{

                finish();

                System.exit(0);

             }

          }

    }

    代码片段10.1.9  实现返回效果

    5.  完成加载后自动隐藏地址栏

       

        在WebViewClient继承类中的onPageFinished方法可以实现

    @Override

    public void onPageFinished(WebView view, String url) {

       super.onPageFinished(view, url);       

       //隐藏地址栏

    webUrlLayout.setVisibility(View.GONE);

    //更改其他按钮状态(不妨碍影藏地址栏实现)

       //changeStatueOfWebToolsButton();   

    }

    代码片段10.1.10 实现隐藏工具栏

    6.  页面加载后向上滑动到顶部显示地址栏,向下滑动到底部,隐藏地址栏

       

        因为这个设计到了手势的运用,为了方便的管理手势,Android其实已经提供了一个类,能够自动识别获取到的手势,这个类就是GestureDetector:

    /**

     * GestureDetector.OnGestureListener自定义继承类

    * 解决各种手势的相对应策略

    * 1. 向上滑动webView到顶触发事件,显示地址栏

    * 2. 向下滑动webView触发时间,隐藏地址栏

     * */

    private class GestureListener implementsGestureDetector.OnGestureListener{

     

    @Override

    public boolean onDown(MotionEvent e) {

       return false;

    }

     

    @Override

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {

       if(webHolder.getScrollY()==0){

          //滑倒顶部

          webUrlLayout.setVisibility(View.VISIBLE);

       }

       if(webHolder.getScrollY()>0){

          //滑倒底部

          webUrlLayout.setVisibility(View.GONE);

       }

       return true;

    }

     

    @Override

    public void onLongPress(MotionEvent e) {

    }

     

    @Override

    public boolean onScroll(MotionEvent e1, MotionEvent e2,

                float distanceX, float distanceY) {

       return false;

    }

     

    @Override

    public void onShowPress(MotionEvent e) {

    }

     

    @Override

    public boolean onSingleTapUp(MotionEvent e) {

       return false;

    }

    }

    代码片段10.1.11 GestureDirector.OnGestureListener实现

    已经实现了手势识别的方法,那么现在只需要获取手势,并且将获取到的交给手势识别类(即上述的GestureDirector)识别即可。

    手势是对于webView这个组件来说的,所以只需要这个组件添加了OnTouchListener方法即可,这个方法会获取到手势产生的事件:

    /**

     * OnTouchListener自定义继承类

     * 解决将手势交给GestureDetector类解决

     * */

    private class WebViewTouchListener implements OnTouchListener{

       @Override

       public boolean onTouch(View v, MotionEvent event) {

          if(v.getId()==R.id.web_holder){

             return mGestureDetector.onTouchEvent(event);

          }

          return false;

       }

    }

    代码片段10.1.12 获取手势事件

    注释:mGestureDetector即为代码偏单10.1.11中的类的实例

    7.  添加刷新功能

       

        这个较为简单,只需要将当前的url地址重新加载就行:

    else if(v.getId()==R.id.tools_normal_refresh){

                //刷新

                if(!(url.equals("")&&url.equals("http://"))){

                    webHolder.loadUrl(url);

                }

             }

    代码片段10.1.12-1   refresh功能

               

       

    8.  添加进度条

       

        为了美观,我并没有采用系统的进度条,而是自己创建了一个进度条,并且在webChromeClient的onProgressChanged方法中同步进度。

    /**

        * WebChromeClient自定义继承类

        * 覆盖如下方法

        * 1. onProgressChanged

        *     用来解决进度条显示问题

        * */

       private class OwnerChromeClient extends WebChromeClient{

     

          @Override

          public void onProgressChanged(WebView view, int newProgress) {

             super.onProgressChanged(view, newProgress);

             //MainActivity.this.setProgress(newProgress* 100);

             if(newProgress==100){

                webProgressBar.setVisibility(View.GONE);

             }else{

                webProgressBar.setVisibility(View.VISIBLE);

                webProgressBar.setProgress(newProgress);

             }

          }

         

       }

    代码片段10.1.13 进度条同步

       

    9.  设置点击链接,设置地址栏地址

       

        这个功能在页面加载的时候,可以通过一个覆盖函数,在webViewClient中进行操作

    @Override

    public void onPageFinished(WebView view, String url) {

       super.onPageFinished(view, url);

       //设置地址栏地址

       webUrlStr.setText(url);

       webUrlLayout.setVisibility(View.GONE);

    //在每次页面加载完成后查看是否有可以回溯的历史

       changeStatueOfWebToolsButton();

    }

    代码片段10.1.14 页面加载完成后设置地址栏

       

    10. 设置向前向后按钮,无则灰色

       

        因为按钮的不同状态图片也不相同,这个时候就需要使用selector标签,如下:

       

    <?xml version="1.0"encoding="utf-8"?>

    <selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true"android:drawable="@drawable/next_button_keydown"></item>

    <item android:state_enabled="false"android:drawable="@drawable/next_button_unavailable"></item>

    <item android:drawable="@drawable/next_button_normal"></item>

    </selector>

    代码片段10.1.15 按钮的三态

                   

    注释:state_pressed表示按钮按下的状态时候为真,则显示drawable中的资源,其他两个也是相同;enabled可使用为假时,进行引用等

    /**

     * 设置工具栏回溯历史是否可用

     * */

    private void changeStatueOfWebToolsButton(){

       if(webHolder.canGoBack()){

          //设置可使用状态

          preButton.setEnabled(true);

       }else{

          //设置禁止状态

          preButton.setEnabled(false);

       }

       if(webHolder.canGoForward()){

          //设置可使用状态

          nextButton.setEnabled(true);

       }else{

          //设置禁止状态

          nextButton.setEnabled(false);

       }

    }

    代码片段10.1.16 设置工具栏中的回溯历史的按钮

       

    11. 工具栏功能实现,包括总工具窗口显示实现,主页返回实现

       

        这个通过popupwindow和tabActivity结合来实现:

        基本的:

    private void initTab(){

           this.toolsTabViewthis.toolsTabInflater.inflate(R.layout.tabactivity_tools,null);

           this.toolsTab = (TabHost) this.toolsTabView.findViewById(android.R.id.tabhost);       //获取tabhost

           this.toolsTab.setup();           //使用findViewById()加载tabhost时在调用addTab前必须调用

     

           this.toolsTab.addTab(this.toolsTab.newTabSpec("normal").setIndicator("常用").setContent(R.id.tools_normal));

     

       this.toolsTab.addTab(this.toolsTab.newTabSpec("setttings").setIndicator("设置").setContent(R.id.tools_settings));

           this.toolsTab.addTab(this.toolsTab.newTabSpec("tool").setIndicator("工具").setContent(R.id.tools_tool));

           this.toolsTab.setCurrentTab(0);                                            //设置默认选种标签

        }

    代码片段10.1.17 实现tab

       

    /**

         * 构造函数

         * @param context Context

         * @param width int

         * @param height int

         * */

        public ToolsPopWindow(Contextcontext, int width, int height){

           super(context);

           this.context = context;

           this.toolsTabInflater = LayoutInflater.from(this.context);

          

           //创建标签

           this.initTab();

          

           //设置默认选项

           setWidth(width);

           setHeight(height);

           setContentView(toolsTab);

           setOutsideTouchable(true);

           setFocusable(true);

        }

    代码片段10.1.8  popupWindow实现

       

       

        基本的浏览器功能已经实现。


    代码:

    AndroidStudy_web1.0

    PS:转载请注明出处谢谢!

  • 相关阅读:
    Select列表操作函数
    IBM职业之路—职业规划和技术发展(转自LU)听听前辈的意见
    C#上传下载文件ftp操作类FTPClient代码(转)
    C# FTP操作类
    UML基础
    DevExpress控件之XtraTreeList
    认识UML类图元素
    C#读写EXCEL
    C#正则表达式整理备忘
    面向对象程序可视化类图的逆向自动生成
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3275419.html
Copyright © 2020-2023  润新知