国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android 實現WebView點擊圖片查看大圖列表及圖片保存功能

2019-12-12 03:40:30
字體:
來源:轉載
供稿:網友

 在日常開發過程中,有時候會遇到需要在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, String model, Target<GlideDrawable> target, 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.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {    @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.通過addOnPageChangeListener來實現對頁面滑動事件的監聽――>此處主要用來處理設置當前頁面的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, 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, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, 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點擊圖片查看大圖列表及圖片保存功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 麻城市| 兴宁市| 阆中市| 专栏| 监利县| 泸州市| 桂平市| 体育| 厦门市| 紫阳县| 化隆| 辛集市| 霸州市| 襄垣县| 赤水市| 福鼎市| 浙江省| 河西区| 天峨县| 武强县| 崇州市| 大洼县| 大埔县| 喜德县| 武川县| 陆丰市| 云安县| 浦北县| 郯城县| 昭苏县| 余庆县| 惠州市| 昭觉县| 博罗县| 沧州市| 长宁县| 赤峰市| 长岭县| 苏尼特左旗| 台南市| 珲春市|