webview与javascript交互实现图片点击缩放预览功能,修复部分机型(华为mate9)webview自动添加图片点击功能

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lkjfyy/article/details/81634379

先说下我在使用X5Webview中碰到的一个bug:在华为Mate9  Android8.0.0手机上webview会自动给Html中的图片添加上点击缩放事件。本来这也没什么,但是因为我项目中本来就要实现这个功能,导致图片会被打开两次,体验很不好,目前没在别的手机上发现相同的问题。

解决思路:先去掉自动添加的图片点击事件,然后再自己使用webview和js交互实现图片的点击缩放预览功能

先贴出解决上述bug的关键代码:

private void addImageClickListner(com.tencent.smtt.sdk.WebView webView) {
    //遍历页面中所有img的节点,因为节点里面的图片的url即objs[i].src,保存所有图片的src.
    //为每个图片设置点击事件,objs[i].onclick
    webView.loadUrl(
            "javascript:(function(){" +
                    "var objs = document.getElementsByTagName(\"img\"); " +
                    "for(var i=0;i<objs.length;i++)  " +
                    "{" +
                    "objs[i].addEventListener('click',function(e){" +//去掉默认点击事件
                    "e.preventDefault();" +
                    "});" +
                    "window.imageListener.readImageUrl(objs[i].src);  " +//添加图片集合
                    " objs[i].onclick=function(){  " +
                    " window.imageListener.openImage(this.src);  " +//添加图片点击事件
                    "  }  " +
                    "}" +
                    "})()");
}

其中解决上述bug的关键代码就是注释中的去掉默认点击事件的代码:

objs[i].addEventListener('click',function(e){" +//去掉默认点击事件
"e.preventDefault();" +
"});

对了,我用的是腾讯出的X5Webview,原生的Webview应该一样

下面是实现webview与js交互实现图片点击预览保存功能的具体实现,已经会用的小伙伴可以忽略了。先上效果图:

先说用到的第三方库:

加载图片使用的是Glide

图片缩放用的是PhotoView:implementation 'com.github.chrisbanes:PhotoView:2.0.0'

首先需要自定义WebViewClient继承自com.tencent.smtt.sdk.WebViewClient(项目中我用的是腾讯的X5Webview,再次重申一次哈哈),在webview加载结束后添加图片的点击事件,就用到了与js交互:

public class MyWebViewClient extends com.tencent.smtt.sdk.WebViewClient {

    private static final String TAG = "MyWebViewClient";

    @Override
    public void onPageStarted(com.tencent.smtt.sdk.WebView webView, String s, Bitmap bitmap) {
        super.onPageStarted(webView, s, bitmap);
    }

    @Override
    public boolean shouldOverrideUrlLoading(com.tencent.smtt.sdk.WebView webView, String s) {
        //点击webView中的键接,依然在此webview中显示,而不跳转到别的浏览器
        webView.loadUrl(s);
        return super.shouldOverrideUrlLoading(webView, s);
    }

    @Override
    public void onPageFinished(com.tencent.smtt.sdk.WebView webView, String s) {
        super.onPageFinished(webView, s);
        addImageClickListner(webView);//当页面加载完成,就调用我们的addImageListener()函数
    }


    private void addImageClickListner(com.tencent.smtt.sdk.WebView webView) {
        //遍历页面中所有img的节点,因为节点里面的图片的url即objs[i].src,保存所有图片的src.
        //为每个图片设置点击事件,objs[i].onclick
        webView.loadUrl(
                "javascript:(function(){" +
                        "var objs = document.getElementsByTagName(\"img\"); " +
                        "for(var i=0;i<objs.length;i++)  " +
                        "{" +
                        "objs[i].addEventListener('click',function(e){" +//去掉默认点击事件
                        "e.preventDefault();" +
                        "});" +
                        "window.imageListener.readImageUrl(objs[i].src);  " +//添加图片集合
                        " objs[i].onclick=function(){  " +
                        " window.imageListener.openImage(this.src);  " +//添加图片点击事件
                        "  }  " +
                        "}" +
                        "})()");
    }

}

然后自然就需要添加js接口,自定义JavascriptInterface接口:

public class JavascriptInterface {
    
    private Context context;
    private ArrayList<String> listimg;
    
    public JavascriptInterface(Context context) {
        this.context = context;
        listimg=new ArrayList<>();
    }
    
    @android.webkit.JavascriptInterface
    public void readImageUrl(String img) {     
        //把所有图片的url保存在ArrayList<String>中
        if (!(img.toLowerCase()).endsWith("gif")){
            listimg.add(img);
        }
    }
    
    @android.webkit.JavascriptInterface  //对于targetSdkVersion>=17的,要加这个声明
    //点击图片所调用到的函数
    public void openImage(String clickimg) {
        int index = 0;
        if (!(clickimg.toLowerCase()).endsWith("gif")){
            for(String url:listimg)
                if(url.equals(clickimg)) index = listimg.indexOf(clickimg);//获取点击图片在整个页面图片中的位置
            Intent intent = new Intent();
            Bundle bundle = new Bundle();
            bundle.putStringArrayList("list_image", listimg);
            bundle.putInt("index", index);
            intent.putExtra("bundle", bundle);//将所有图片的url以及点击图片的位置作为参数传给启动的activity
            intent.setClass(context, ShowImgActivity.class);
            context.startActivity(intent);//ShowImgActivity,用于显示图片
        }
    }
}

在WebviewActivity中只需要这样调用即可:

//绑定javasrcipt接口,imageListener为接口的别名
wvArticle.addJavascriptInterface(new JavascriptInterface(
        ArticleDetailsActivity.this), "imageListener");
wvArticle.loadDataWithBaseURL(null, mArticleContent, "text/html", "utf-8", null);
wvArticle.setWebViewClient(new MyWebViewClient());

最后是在ShowImgActivity中:

public class ShowImgActivity extends BaseActivity {

    @BindView(R.id.view_pager)
    ViewPager viewPager;
    @BindView(R.id.indicator)
    TextView mIndicator;
    @BindView(R.id.save)
    TextView save;

    private View mRootView;
    private PhotoView mPhotoView;
    private Bundle mBundle;
    private ArrayList<String> mImgList;
    private int mIndex;
    private int mCount;

    @Override
    protected int setLayoutId() {
        return R.layout.activity_show_img;
    }

    @Override
    protected void initView() {
        mBundle = getIntent().getBundleExtra("bundle");
        mImgList = mBundle.getStringArrayList("list_image");
        mIndex = mBundle.getInt("index");
        mCount = (mImgList == null ? 0 : mImgList.size());
        viewPager.setAdapter(new SamplePagerAdapter());
        viewPager.setCurrentItem(mIndex);
    }

    @Override
    protected void setListener() {
        save.setOnClickListener(this);
    }

    @Override
    protected void initData() {

    }

    @Override
    public void widgetClick(View v) {
        switch (v.getId()) {
            case R.id.save:
                savePhotoToLocal();
                break;
            default:
                break;
        }
    }

    /**
     * 保存图片
     */
    private void savePhotoToLocal() {
        if (mPhotoView != null) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) mPhotoView.getDrawable();
            if (bitmapDrawable == null) {
                return;
            }
            Bitmap bitmap = bitmapDrawable.getBitmap();
            if (bitmap == null) {
                return;
            }
            FileUtils.savePhoto(this, bitmap, new FileUtils.SaveResultCallback() {
                @Override
                public void onSavedSuccess() {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            ToastUtils.showShort("保存成功");
                        }
                    });
                }

                @Override
                public void onSavedFailed() {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            ToastUtils.showShort("保存失败");
                        }
                    });
                }
            });
        }
    }

    class SamplePagerAdapter extends PagerAdapter {
        @Override
        public int getCount() {
            return mCount;
        }

        @Override
        public View instantiateItem(ViewGroup container, int position) {
            mRootView = LayoutInflater.from(ShowImgActivity.this).inflate(R.layout.item_show_img, container, false);
            mPhotoView = mRootView.findViewById(R.id.photoview);
            Glide.with(ShowImgActivity.this)
                    .load(mImgList.get(position))
                    .asBitmap()
                    .placeholder(R.drawable.loading_img)
                    .error(R.drawable.loading_img)
                    .fitCenter()
                    .into(mPhotoView);
            container.addView(mRootView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            return mRootView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            CharSequence text = getString(R.string.viewpager_indicator, position + 1, mCount);
            mIndicator.setText(text);
        }
    }
}

 其中用到的FileUtils关键代码:

public class FileUtils {

    public static void savePhoto(final Context context, final Bitmap bmp, final SaveResultCallback saveResultCallback) {
        final File sdDir = getSDPath();
        if (sdDir == null) {
            Toast.makeText(context, "设备自带的存储不可用", Toast.LENGTH_SHORT).show();
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                File appDir = new File(sdDir, "学管通");
                if (!appDir.exists()) {
                    appDir.mkdir();
                }
                SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置以当前时间格式为图片名称
                String fileName = df.format(new Date()) + ".png";
                File file = new File(appDir, fileName);
                try {
                    FileOutputStream fos = new FileOutputStream(file);
                    bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
                    fos.flush();
                    fos.close();
                    saveResultCallback.onSavedSuccess();
                } catch (FileNotFoundException e) {
                    saveResultCallback.onSavedFailed();
                    e.printStackTrace();
                } catch (IOException e) {
                    saveResultCallback.onSavedFailed();
                    e.printStackTrace();
                }

                //保存图片后发送广播通知更新数据库
                Uri uri = Uri.fromFile(file);
                context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
            }
        }).start();
    }


    public static File getSDPath() {
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); //判断sd卡是否存在
        if (sdCardExist) {
            sdDir = Environment.getExternalStorageDirectory();//获取跟目录
        }
        return sdDir;
    }

    public interface SaveResultCallback {
        void onSavedSuccess();

        void onSavedFailed();
    }
}

WebviewActivity中布局文件只有一个webview

ShowImgActivity中布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:background="#000000">
    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <TextView
        android:id="@+id/indicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:padding="15dp"
        android:textSize="16sp"
        android:textColor="@android:color/white"
        android:gravity="center"
        android:text="@string/viewpager_indicator"
        android:background="#80000000"/>

    <TextView
        android:id="@+id/save"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:padding="15dp"
        android:textSize="16sp"
        android:text="保存"
        android:textColor="@android:color/white"
        android:background="#80000000"/>
</RelativeLayout>

PagerAdapter的item布局只有一个PhotoView

就酱,拜拜

猜你喜欢

转载自blog.csdn.net/lkjfyy/article/details/81634379