Android 实现WebView点击图片查看大图列表及图片保存功能

Android 实现WebView点击图片查看大图列表及图片保存功能,第1张

概述 在日常开发过程中,有时候会遇到需要在app中嵌入网页,此时使用WebView实现效果,但在默认情况下是无法点击图片查看大图的,更无法保存图片。本文将就这一系列问题的实现进行说明。

 在日常开发过程中,有时候会遇到需要在app中嵌入网页,此时使用WebVIEw实现效果,但在默认情况下是无法点击图片查看大图的,更无法保存图片。本文将就这一系列问题的实现进行说明。

图示:

项目的知识点:

加载网页后如何捕捉网页中的图片点击事件;

获取点击的图片资源后进行图片显示,获取整个页面所有的图片;

支持查看上下一张的图片以及对图片缩放显示;

对图片进行保存;

其他:图片缓存的处理(不用每次都重新加载已查看过的图片)

项目代码结构:

前期准备(添加权限、依赖和混淆设置):

添加权限:

 <uses-permission androID:name="androID.permission.INTERNET" /> <uses-permission androID:name="androID.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission androID:name="androID.permission.MOUNT_UNMOUNT_fileSYstemS"/>

添加依赖:

 compile 'com.bm.photovIEw:library:1.4.1' compile 'com.github.bumptech.glIDe:glIDe:3.7.0' compile 'com.androID.support:support-v4:25.0.0'

混淆文件设置:

-keep public class * implements com.bumptech.glIDe.module.GlIDeModule -keep public enum com.bumptech.glIDe.load.resource.bitmap.ImageheaderParser$** {  **[] $VALUES;  public *; } 

代码解析:

MainActivity很简单,代码如下:

@OverrIDe  public voID onCreate(Bundle savedInstanceState) {   super.onCreate(savedInstanceState);   setContentVIEw(R.layout.activity_main);   contentWebVIEw = (WebVIEw) findVIEwByID(R.ID.webVIEw);   contentWebVIEw.getSettings().setJavaScriptEnabled(true);   contentWebVIEw.loadUrl("http://a.mp.uc.cn/article.HTML?uc_param_str=frdnsnpfvecpntnwprdssskt&clIEnt=ucweb&wm_aID=c51bcf6c1553481885da371a16e33dbe&wm_ID=482efebe15ed4922a1f24dc42ab654e6&pagetype=share&btifl=100");   contentWebVIEw.addJavaScriptInterface(new MJavaScriptInterface(this,imageUrls),"imageListener");   contentWebVIEw.setWebVIEwClIEnt(new MyWebVIEwClIEnt());  } 

很显然,就是WebVIEw的基本初始化 *** 作。其中1.自定义了MJavaScriptInterface的类用来实现Js调用本地的方法;2.自定义MyWebVIEwClIEnt来实现对WebVIEw的监听管理。

MyWebVIEwClIEnt代码如下:

public class MyWebVIEwClIEnt extends WebVIEwClIEnt {  @OverrIDe  public voID onPageFinished(WebVIEw vIEw,String url) {   vIEw.getSettings().setJavaScriptEnabled(true);   super.onPageFinished(vIEw,url);   addImageClickListener(vIEw);//待网页加载完全后设置图片点击的监听方法  }  @OverrIDe  public voID onPageStarted(WebVIEw vIEw,String url,Bitmap favicon) {   vIEw.getSettings().setJavaScriptEnabled(true);   super.onPageStarted(vIEw,url,favicon);  }  private voID addImageClickListener(WebVIEw webVIEw) {   webVIEw.loadUrl("JavaScript:(function(){" +     "var obJs = document.getElementsByTagname(\"img\"); " +     "for(var i=0;i<obJs.length;i++) " +     "{"     + " obJs[i].onclick=function() " +     " { "     + "  window.imageListener.openImage(this.src); " +//通过Js代码找到标签为img的代码块,设置点击的监听方法与本地的openImage方法进行连接     " } " +     "}" +     "})()");  } } 

该类继承自WebVIEwClIEnt,在onPageFinished方法中设置addImageClickListener的监听方法――>当整个WebVIEw页面加载完毕后,为每张图片设置监听事件――>这意味着,整个页面未加载完毕时,点击是无效的。
addImageClickListener的代码实现也很简单,通过Js找到相应的img标签,这样就知道是图片了,然后为这些图片设置点击监听事件――>每当点击时调用自定义的openImage(url)方法。这个openImage(url)方法与MJavaScriptInterface中对应的方法交相辉映,这样就形成了Js调用本地的方法。

MJavaScriptInterface代码(主要为与Js对应的本地方法的实现):

public class MJavaScriptInterface {  private Context context;  private String [] imageUrls;  public MJavaScriptInterface(Context context,String[] imageUrls) {   this.context = context;   this.imageUrls = imageUrls;  }  @androID.webkit.JavaScriptInterface  public voID openImage(String img) {   Intent intent = new Intent();   intent.putExtra("imageUrls",imageUrls);   intent.putExtra("curImageUrl",img);   intent.setClass(context,PhotobrowserActivity.class);   context.startActivity(intent);  } } 

可以看到,openImage(url)方法实现的逻辑是:通过传递当前图片的url与该WebVIEw整个页面的图片列表(imageUrls)进行跳转至PhotobrowserActivity中。PhotobrowserActivity就是用来显示大图的图片列表的页面。

此处的疑问:imageUrls怎么获得呢?

方式:1.服务器端直接将WebVIEw中所有的图片按照顺序组合成String数组传递过来;2.或者直接将所有含img标签的HTML代码传递过来,从而让客户端自己解析出所有图片地址组合成的String数组。(此处是采用的第二种,具体如何解析,可以下载源码查看。)

OK,到了这里算是完成了项目知识点的第1点:1.加载网页后如何捕捉网页中的图片点击事件;

接下来就说明后面的几点:

2.获取点击的图片资源后进行图片显示,获取整个页面所有的图片;

3.支持查看上下一张的图片以及对图片缩放显示;

4.对图片进行保存;

其他所有的几点实现均在PhotobrowserActivity中,代码如下:主要就是将图片放进VIEwPager中进行显示:

mPager = (VIEwPager) findVIEwByID(R.ID.pager);   mPager.setPagemargin((int) (getResources().getdisplayMetrics().density * 15));   mPager.setAdapter(new PagerAdapter() {    @OverrIDe    public int getCount() {     return imageUrls.length;    }    @OverrIDe    public boolean isVIEwFromObject(VIEw vIEw,Object object) {     return vIEw == object;    }    @OverrIDe    public Object instantiateItem(VIEwGroup container,final int position) {     if (imageUrls[position] != null && !"".equals(imageUrls[position])) {      final PhotoVIEw vIEw = new PhotoVIEw(PhotobrowserActivity.this);      vIEw.enable();      vIEw.setScaleType(ImageVIEw.ScaleType.FIT_CENTER);      GlIDe.with(PhotobrowserActivity.this).load(imageUrls[position]).overrIDe(Target.SIZE_ORIGINAL,Target.SIZE_ORIGINAL).fitCenter().crossFade().Listener(new RequestListener<String,GlIDeDrawable>() {       @OverrIDe       public boolean onException(Exception e,String model,Target<GlIDeDrawable> target,boolean isFirstResource) {        if (position == curposition) {         hIDeLoadingAnimation();        }        showErrorLoading();        return false;       }       @OverrIDe       public boolean onResourceReady(GlIDeDrawable resource,boolean isFromMemoryCache,boolean isFirstResource) {        occupyOneposition(position);        if (position == curposition) {         hIDeLoadingAnimation();        }        return false;       }      }).into(vIEw);      container.addVIEw(vIEw);      return vIEw;     }     return null;    }    @OverrIDe    public voID destroyItem(VIEwGroup container,int position,Object object) {     releaSEOneposition(position);     container.removeVIEw((VIEw) object);    }   });   curposition = returnClickedposition() == -1 ? 0 : returnClickedposition();   mPager.setCurrentItem(curposition);   mPager.setTag(curposition);   if (initialedpositions[curposition] != curposition) {//如果当前页面未加载完毕,则显示加载动画,反之相反;    showLoadingAnimation();   }   photoOrderTv.setText((curposition + 1) + "/" + imageUrls.length);//设置页面的编号   mPager.addOnPage@R_502_1962@(new VIEwPager.OnPage@R_502_1962@() {    @OverrIDe    public voID onPageScrolled(int position,float positionOffset,int positionOffsetPixels) {    }    @OverrIDe    public voID onPageSelected(int position) {     if (initialedpositions[position] != position) {//如果当前页面未加载完毕,则显示加载动画,反之相反;      showLoadingAnimation();     } else {      hIDeLoadingAnimation();     }     curposition = position;     photoOrderTv.setText((position + 1) + "/" + imageUrls.length);//设置页面的编号     mPager.setTag(position);//为当前vIEw设置tag    }    @OverrIDe    public voID onPageScrollStateChanged(int state) {    }   });  }  private int returnClickedposition() {   if (imageUrls == null || curImageUrl == null) {    return -1;   }   for (int i = 0; i < imageUrls.length; i++) {    if (curImageUrl.equals(imageUrls[i])) {     return i;    }   }   return -1;  } 

1.首先通过returnClickedposition方法来获得用户点击的是哪一张图片的位置并设置当前是哪一个page――>通过遍历当前url与所有url来匹配获取;

2.通过addOnPage@R_502_1962@来实现对页面滑动事件的监听――>此处主要用来处理设置当前页面的position、动画、页面序号显示的逻辑;

3.PagerAdapter的实现――>每一页内容的初始化,主要为instantiateItem,核心代码再次拖出来如下;

if (imageUrls[position] != null && !"".equals(imageUrls[position])) {      final PhotoVIEw vIEw = new PhotoVIEw(PhotobrowserActivity.this);      vIEw.enable();      vIEw.setScaleType(ImageVIEw.ScaleType.FIT_CENTER);      GlIDe.with(PhotobrowserActivity.this).load(imageUrls[position]).overrIDe(Target.SIZE_ORIGINAL,boolean isFirstResource) {        occupyOneposition(position);        if (position == curposition) {         hIDeLoadingAnimation();        }        return false;       }      }).into(vIEw);      container.addVIEw(vIEw);      return vIEw;     } 

大体思路:

1.通过PhotoVIEw来实现图片的伸缩显示;2.通过GlIDe来加载图片等处理;

PhotoVIEw是什么――>就是图片组件,对图片的伸缩、动效、缓存等方面进行了处理,点击地址查看GitHub介绍>>:

Gilde是什么――>Google推荐的图片加载库,此处用它的理由是好用、简单,点击地址查看GitHub介绍>>:

GlIDe的简化形式――>GlIDe.with(...).load(图片地址).overrIDe(加载图片的大小).Listener(设置监听方法).into(某个一个组件,此处是PhotoVIEw),此处使用的是原图加载,监听方法中有两个回调方法:

onException和onResourceReady,此处在onResourceReady做的处理是:当资源加载完毕时调用――>此时取消加载动画的显示。

页面中的“页面编号”和“保存”的组件显示是通过写在整个Activity的布局文件中实现的,而不是通过在每一页中写入这些组件。以下为获取图片资源对象的代码:

private voID savePhotoTolocal() {   VIEwGroup containerTemp = (VIEwGroup) mPager.findVIEwWithTag(mPager.getCurrentItem());   if (containerTemp == null) {    return;   }   PhotoVIEw photoVIEwTemp = (PhotoVIEw) containerTemp.getChildAt(0);   if (photoVIEwTemp != null) {    GlIDeBitmapDrawable glIDeBitmapDrawable = (GlIDeBitmapDrawable) photoVIEwTemp.getDrawable();    if (glIDeBitmapDrawable == null) {     return;    }    Bitmap bitmap = glIDeBitmapDrawable.getBitmap();    if (bitmap == null) {     return;    }    fileUtils.savePhoto(this,bitmap,new fileUtils.SaveResultCallback() {     @OverrIDe     public voID onSavedSuccess() {      runOnUiThread(new Runnable() {       @OverrIDe       public voID run() {        Toast.makeText(PhotobrowserActivity.this,"保存成功",Toast.LENGTH_SHORT).show();       }      });     }     @OverrIDe     public voID onSavedFailed() {      runOnUiThread(new Runnable() {       @OverrIDe       public voID run() {        Toast.makeText(PhotobrowserActivity.this,"保存失败",Toast.LENGTH_SHORT).show();       }      });     }    });   }  } 

因为下载图片需要知道当前处于哪一页,所以在VIEwPager初始化显示和滑动时都给每一页设置了tag,此时就派上了用场――>mPager.findVIEwWithTag获取当前page中的布局对象,然后获得对应的PhotoVIEw对象,从而经过处理最终获取到Bitmap对象。这样已经很简单了,接下来只要将Bitmap对象保存至本地即可,代码如下:

public class fileUtils {  public static voID savePhoto(final Context context,final Bitmap bmp,final SaveResultCallback saveResultCallback) {   new Thread(new Runnable() {    @OverrIDe    public voID run() {     file appDir = new file(Environment.getExternalStorageDirectory(),"out_photo");     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 interface SaveResultCallback{   voID onSavedSuccess();   voID onSavedFailed();  } } 

图片如何保存已经如代码所示,但要注意的是需要将已经保存的图片进行广播通知数据库更新――>这样立马进入微信或者扣扣点击发送图片,就可以看到刚刚保存的图片。

缓存的处理:

使用GlIDe其中的一个好处是会将图片默认缓存,在需要清除缓存时,只需要执行下面的代码(此处是放在MainActivity中,退出页面即清除缓存):

@OverrIDe  protected voID onDestroy() {   new Thread(new Runnable() {    @OverrIDe    public voID run() {     GlIDe.get(MainActivity.this).cleardiskCache();//清理磁盘缓存需要在子线程中执行    }   }).start();   GlIDe.get(this).clearMemory();//清理内存缓存可以在UI主线程中进行   super.onDestroy();  } 

特别注意:

1.若项目配置中将targetSdkVersion 指定为22以上,则要加入动态权限申请的模块,否则在进行保存 *** 作时则会提示失败!

2.项目中暴露的Js接口类:MJavaScriptInterface不能混淆,其调用的方法的声明也不能混淆,所以还要添加如下混淆设置代码(代码因包名而变化):

-keepclassmembers class com.example.administrator.webvIEwpagescannerapp.other.MJavaScriptInterface{  public *; } -keepattributes *Annotation* -keepattributes *JavaScriptInterface* 

源码已经上传至GitHub,点击此处查看>>

以上所述是小编给大家介绍的AndroID 实现WebVIEw点击图片查看大图列表及图片保存功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持!

总结

以上是内存溢出为你收集整理的Android 实现WebView点击图片查看大图列表及图片保存功能全部内容,希望文章能够帮你解决Android 实现WebView点击图片查看大图列表及图片保存功能所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1146894.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存