多个Frament内嵌套WebView以及返回键监听(附带底部Menu的SelectUI变化)

版权声明:转载注明出处就可以啦~ https://blog.csdn.net/weixin_41957078/article/details/82221951

多个Frament内嵌套WebView以及返回键监听

刚参加工作,越来越觉得大学时学的东西实在是少之又少……最近在工作中有一个项目需要做一个内嵌WebView的安卓“外壳”,里边的H5由别人开发,我需要做一个外壳来承载这些页面,在这个过程中却是经历了无数的磨难,心塞啊。。好在在一周的努力学习下,终于成功的将这个“外壳”交了上去。

这个外壳是一个仿淘宝的主页框架,里边可以放WebView之类的种种,还算是比较通用的,主要是UI和一些逻辑的框架,没有JavaScript的数据交互部分,效果图如下。有需要的小伙伴们来看看吧~

  • 效果图
    这里写图片描述

下边做一下笔记,也是第一次在CSDN上发表自己的收获,还请来看的各位多提意见,哪里写的不对不清楚的也可说出来,只要能让彼此提高,让这篇文章有质量,让后学者又得,在下就感激不尽。

注:本文讨论的是在Eclipse上开发的,不过并不影响AS上的正常运行

—————————————-我是分割线————————————————–

正文开始

整体预览

项目结构整体如下(没有分层,只是简单实现了本文所讨论的功能)

这里写图片描述

同时需要为项目设置联网权限,在AndroidMainFest.xml中:

<uses-permission android:name="android.permission.INTERNET"/>

布局文件

由于是要在Fragment中嵌套WebView,同时底部还要有几个按钮来控制切换Fragment,所以做了如下布局。

  • activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="10">

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="9"/>

    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal"
        android:layout_margin="5sp"
        android:weightSum="5">

        <LinearLayout 
            android:id="@+id/index_menu_1"
            android:orientation="vertical"
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:layout_weight="1">

            <ImageView 
                android:id="@+id/index_menu_1_img"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/bt_bg_index"/>

        </LinearLayout>

        <LinearLayout 
            android:id="@+id/index_menu_2"
            android:orientation="vertical"
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:layout_weight="1">

            <ImageView 
                android:id="@+id/index_menu_2_img"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/bt_bg_type"/>

        </LinearLayout>

        <LinearLayout 
            android:id="@+id/index_menu_3"
            android:orientation="vertical"
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:layout_weight="1">

            <ImageView 
                android:id="@+id/index_menu_3_img"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/bt_bg_contact_us"/>

        </LinearLayout>

        <LinearLayout 
            android:id="@+id/index_menu_4"
            android:orientation="vertical"
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:layout_weight="1">

            <ImageView 
                android:id="@+id/index_menu_4_img"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/bt_bg_shopping_cart"/>

        </LinearLayout>

        <LinearLayout 
            android:id="@+id/index_menu_5"
            android:orientation="vertical"
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:layout_weight="1">

            <ImageView 
                android:id="@+id/index_menu_5_img"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/bt_bg_mine"/>

        </LinearLayout>

    </LinearLayout>

</LinearLayout>

有点冗长啊……确实是没什么,就是一个用来承载Fragment的FrameLayout和底部几个按钮而已。

  • fragment1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:background="#000">

    <WebView
        android:id="@+id/webview1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <ProgressBar
        android:id="@+id/progressbar1"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="3dip"
        android:max="100"
        android:progress="0"
        android:visibility="gone"/>

</LinearLayout>

几个fragment的布局文件内容都是一样的,都是一个WebView加一个ProgressBar。

Activity文件

  • MainActivity.java
public class MainActivity extends FragmentActivity implements OnClickListener , BackHandledInterface{

    private BaseFragment mBackHandedFragment;

    private ImageView imageView1;
    private ImageView imageView2;
    private ImageView imageView3;
    private ImageView imageView4;
    private ImageView imageView5;

    private String nowFragment = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
    }

    private void initView() {
        imageView1 = (ImageView) findViewById(R.id.index_menu_1_img);
        imageView1.setOnClickListener(this);
        imageView2 = (ImageView) findViewById(R.id.index_menu_2_img);
        imageView2.setOnClickListener(this);
        imageView3 = (ImageView) findViewById(R.id.index_menu_3_img);
        imageView3.setOnClickListener(this);
        imageView4 = (ImageView) findViewById(R.id.index_menu_4_img);
        imageView4.setOnClickListener(this);
        imageView5 = (ImageView) findViewById(R.id.index_menu_5_img);
        imageView5.setOnClickListener(this);

        //初始化主页,默认显示的是第一个页面
        FragmentManager manager = getSupportFragmentManager();
//      Log.e("backPress","当前Fragment数量:"+manager.getBackStackEntryCount());
        while(manager.getBackStackEntryCount()>1) {manager.popBackStack();}

        Fragment1 fragment1 = new Fragment1();
        changeFragment(fragment1);
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        switch (id) {
        case R.id.index_menu_1_img:
            Fragment1 fragment1 = new Fragment1();
            changeFragment(fragment1);
            break;

        case R.id.index_menu_2_img:
            Fragment2 fragment2 = new Fragment2();
            changeFragment(fragment2);
//          Log.e("Click","当前Fragment数量:"+getSupportFragmentManager().getBackStackEntryCount());
            break;

        case R.id.index_menu_3_img:
            Fragment3 fragment3 = new Fragment3();
            changeFragment(fragment3);
            break;

        case R.id.index_menu_4_img:
            Fragment4 fragment4 = new Fragment4();
            changeFragment(fragment4);
//          player.start();
            break;

        case R.id.index_menu_5_img:
//          Log.i("tag", "点击了--3");
            Fragment5 fragment5 = new Fragment5();
            changeFragment(fragment5);
//          player.stop();
            break;

        default:
            break;
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode == KeyEvent.KEYCODE_BACK) {
            if(mBackHandedFragment == null || !mBackHandedFragment.onBackPressed()){
                //Fragment1/2/3/4/5 中的onBackPressed方法返回值就是来这里进行判断的
                //判断当前Fragment是否需要消费该事件,如果没有Fragment消费才会自己消费
                backFragment();
            }
            return true;
        }else {
            return super.onKeyDown(keyCode, event);
        }
    }

    @Override
    public void setSelectedFragment(BaseFragment selectedFragment) {
        this.mBackHandedFragment = selectedFragment;
    }

    /**
     * 底部MenuUI的回退逻辑
     * @return true:回退成功;false:回退栈元素不足
     */
    @Override
    public boolean backFragment() {
        FragmentManager manager = getSupportFragmentManager();
//      Log.e("backPress","当前Fragment数量:"+manager.getBackStackEntryCount());
        if(manager.getBackStackEntryCount()<=1) {
            //仅剩当前主页,再按返回键则退出程序
            finish();
            return false;
        }else {
            BaseFragment nf = (BaseFragment)manager.findFragmentByTag(nowFragment);
            flushMenuUI(nf.back);
            manager.popBackStack();

            setSelectedFragment((BaseFragment)manager.findFragmentByTag(nowFragment));
            //按了返回键之后,最上层的Fragment已经替换,所以这里也要重新设置一下,不然会执行之前BaseFragment子类的onBackPressed方法

            return true;
        }
    }

    /**
     * 根据需要更新的Fragment设定的UI更新逻辑
     * @param fragment 需要更新的Fragment
     */
    private void changeFragment(BaseFragment fragment) {
        String tagName = fragment.toString();
        Log.e("changeFragment","点击"+tagName);
        if(tagName.equals(nowFragment)) {
            //点击的menu与当前显示Fragment一致,重新加载当前Fragment

        }else {
            FragmentManager manager = getSupportFragmentManager();
            FragmentTransaction transaction = manager.beginTransaction();
//          Log.e("changeFragment",tagName+" "+((manager.findFragmentByTag(tagName) != null)?"已存在":"不存在"));
            if(manager.findFragmentByTag(tagName) == null) {
                //backStack中没有tagName,新增Fragment
                transaction.add(R.id.fragment_container, fragment,tagName);
                transaction.addToBackStack(tagName);
                fragment.back = nowFragment;
            }else {
                //backStack中有此Fragment,直接回退至tagName
                manager.popBackStack(tagName,0);
            }
            flushMenuUI(tagName);
            transaction.commit();
        }
    }

    public void flushMenuUI(String newFragment) {
//      Log.e("flushMenuUI", "当前:"+nowFragment+"   新的:"+newFragment);
        if(!nowFragment.equals(newFragment)) { 
            if(!nowFragment.equals("")) {
                clearSelect();
            }
            setSelect(newFragment);
            nowFragment = newFragment;
        }
    }

    /**
     * 重置已选menu
     */
    public void clearSelect() {
//      Log.e("clearSelect", nowFragment);
        new Thread() {
            public void run() {
                if(nowFragment.equals("Fragment1")) {
                    imageView1.setImageResource(R.drawable.bt_bg_index);
                }else if(nowFragment.equals("Fragment2")) {
                    imageView2.setImageResource(R.drawable.bt_bg_type);
                }else if(nowFragment.equals("Fragment3")) {
                    imageView3.setImageResource(R.drawable.bt_bg_contact_us);
                }else if(nowFragment.equals("Fragment4")) {
                    imageView4.setImageResource(R.drawable.bt_bg_shopping_cart);
                }else if(nowFragment.equals("Fragment5")) {
                    imageView5.setImageResource(R.drawable.bt_bg_mine);
                }
            };
        }.run();
        //本来是直接更新了UI,但是不知道怎么总会出现更新不了的情况,加了个线程莫名就好了。也不知道具体为什么……
    }

    /**
     * 设置已选menu
     */
    public void setSelect(final String newFragment) {
//      Log.e("setSelect", newFragment);
        new Thread() {
            public void run() {
                if(newFragment.equals("Fragment1")) {
                    imageView1.setImageResource(R.drawable.bt_bg_index_selected);
                }else if(newFragment.equals("Fragment2")) {
                    imageView2.setImageResource(R.drawable.bt_bg_type_selected);
                }else if(newFragment.equals("Fragment3")) {
                    imageView3.setImageResource(R.drawable.bt_bg_contact_us_selected);
                }else if(newFragment.equals("Fragment4")) {
                    imageView4.setImageResource(R.drawable.bt_bg_shopping_cart_selected);
                }else if(newFragment.equals("Fragment5")) {
                    imageView5.setImageResource(R.drawable.bt_bg_mine_selected);
                }
            };
        }.run();
    }
}

写了非常多的注释,博客里,额。。。好像也没啥好说的了。都在代码里了……下边是Fragment1.java。

  • Fragment1.java
public class Fragment1 extends BaseFragment {

    private WebView webView1;
    private WebSettings webSettings;
    private ProgressBar progressBar1;
    private View view;

    private String url = "https://www.baidu.com/";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment1,container,false);

        initView();

        webSettings = webView1.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setUseWideViewPort(true);
        webSettings.setLoadWithOverviewMode(true);
        //设置了一些WebView的参数,包括能不能使用JavaScript之类的

        webView1.setWebViewClient(new MyWebViewClient());
        webView1.loadUrl(url);

        return view;
    }   

    private void initView() {
        progressBar1= (ProgressBar) view.findViewById(R.id.progressbar1);//进度条
        webView1 = (WebView) view.findViewById(R.id.webview1);
    }

    private class MyWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

        @Override
        public void onReceivedError(WebView view, int errorCode,
                                    String description, String failingUrl) {
        }

        @Override
        public void onPageFinished(WebView view, String url) {//页面加载完成
            progressBar1.setVisibility(View.GONE);
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {//页面开始加载
            progressBar1.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public  boolean onBackPressed(){

        if(webView1.canGoBack()){
            webView1.goBack();
            Log.v("onBackPressed", this.toString()+"webView.goBack()");
            return true;
            //当前Fragment内的WebView可以返回,WebView进行返回,将true返回值给载体MainActivity
        }else{
            Log.e("onBackPressed",this.toString());
            return false;
          //当前Fragment内的WebView已经无法返回,将false返回值给载体MainActivity
        }

    }

    @Override
    public String toString() {
        return "Fragment1";
    }

}

同样,看代码里的注释。剩下的几个Fragmet*.java我只写了一个Fragment2做测试用,内容基本与Fragment1.java一样。

  • BaseFragment.java(几个Fragment的父类)

import android.os.Bundle;
import android.support.v4.app.Fragment;

public abstract class BaseFragment extends Fragment{
    public String back;

    //接口
    protected BackHandledInterface mBackHandledInterface;

    //返回键事件
    public abstract boolean onBackPressed();

    /**
     * 所有继承BackHandledFragment的子类都将在这个方法中实现物理Back键按下后的逻辑
     * FragmentActivity捕捉到物理返回键点击事件后会首先询问Fragment是否消费该事件
     * 如果没有Fragment消息时FragmentActivity自己才会消费该事件
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(!(getActivity() instanceof BackHandledInterface)){
            throw new ClassCastException("Hosting Activity must implement BackHandledInterface");
        }else{
            this.mBackHandledInterface = (BackHandledInterface)getActivity();
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        //在new一个当前fragment的子类时,设置绑定至承载体的返回栈栈顶
        mBackHandledInterface.setSelectedFragment(this);
    }
}

BaseFragment.java内主要定义了一些共有的,必须的一些参数和方法。老规矩,详见代码内注释。

  • BackHandledInterface.java(返回键接口)
public interface BackHandledInterface {
    void setSelectedFragment(BaseFragment selectedFragment);
    boolean backFragment();
}

代码已经都贴到这里了。完整的源码包会在下面贴出来。

还请各位多多指教,有任何疑问或者观点都可以在评论区留言,我会第一时间回复并改正博客内的错误。也可以加我QQ(543844351)一起讨论,加QQ实际的将验证信息写本博客题目名即可。

另:

  1. 因为我也是现学现卖,在CSDN里看了关于Fragment的文章和一些WebView的文章,所以如有雷同……额没错,就是学来的。在此向前辈们表示深深地谢意~
  2. 不过!请尊重劳动果实!转载请注明出处https://blog.csdn.net/weixin_41957078/article/details/82221951
  3. 源码下载链接:https://download.csdn.net/download/weixin_41957078/10637183

猜你喜欢

转载自blog.csdn.net/weixin_41957078/article/details/82221951