一、實(shí)現(xiàn)需求
創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站設(shè)計(jì)制作、做網(wǎng)站、蘭西網(wǎng)絡(luò)推廣、重慶小程序開發(fā)公司、蘭西網(wǎng)絡(luò)營銷、蘭西企業(yè)策劃、蘭西品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供蘭西建站搭建服務(wù),24小時(shí)服務(wù)熱線:028-86922220,官方網(wǎng)址:www.cdcxhl.com
最近在公司的項(xiàng)目中遇到需求如下:
1、點(diǎn)擊 WebView 頁面的圖片實(shí)現(xiàn)開啟查看圖片模式,即可以顯示點(diǎn)擊的圖片,然后滑動(dòng)顯示下一張圖片。
3、長按 WebView 頁面圖片彈出對(duì)話框可以選擇保存長按的圖片到本地相冊。
拿到這個(gè)需求筆者第一反應(yīng)是沒做過 WebView 相關(guān)的交互,甚至分不清這個(gè)需求是否需要服務(wù)端配合完成 Java 與 JavaScript 的互相調(diào)用,一臉茫然。
遇到這種情況筆者的解決思路一般分兩個(gè)方向:
1、找一個(gè)比較出名的客戶端有類似功能的,然后 Google 搜索,仿 XXXX,先粗略看一下有沒有現(xiàn)成的 Demo 可以參考,比如我這個(gè)需要,先去搜索一下 ”Android 仿微信朋友圈瀏覽圖片效果“ (這個(gè)搜索關(guān)鍵字很關(guān)鍵?。墒枪P者沒找到符合該需要的 Demo。
2、在第一個(gè)方案不好使的情況下,我們沒有了參考,那么咱們就得自己思考這個(gè)大概實(shí)現(xiàn)思路,然后把這個(gè)需求進(jìn)行拆分,逐一擊破。所以思考大概如下:
(1)要想展示圖片那么就得先拿到圖片,要拿到圖片只有兩種可能,第一種可能是 WebView 本身緩存了圖片,我們?nèi)ゾ彺嬷凶x取圖片進(jìn)行顯示,可是想一下,咱們?yōu)g覽微博看圖的時(shí)候如果沒有網(wǎng),這時(shí)候去點(diǎn)擊圖片那么圖片是加載不出來的,所以這種可能否定了;所以只有第二種可能就是點(diǎn)擊圖片的時(shí)候拿到該圖片對(duì)應(yīng)的 URL 網(wǎng)址,然后咱們自己去網(wǎng)絡(luò)加載圖片進(jìn)行顯示,所以這個(gè)點(diǎn)我們 Get 到了。
(2)要滑動(dòng)圖片進(jìn)行顯示下一張,那么就需要我們能拿到所有要顯示的圖片的 URL ,然后放到一個(gè)數(shù)組里面,每次滑動(dòng)就進(jìn)行加載一張圖片,那么也就是我們一次性拿到所有 WebView 包含圖片的 URL,這個(gè)就不是在點(diǎn)擊圖片的時(shí)候去獲取,而是在 WebView 加載完成后獲取到,這怎么能拿到?再想一下,WebView 進(jìn)行加載顯示的時(shí)候其實(shí)是加載 HTML(比如 Assets 目錄中的文件)文本的字符串,然后進(jìn)行渲染處理顯示出來,所以 HTML文本文件里面包含了我們想要的圖片網(wǎng)址,大家看一下下面這張截圖就是一個(gè)帶圖片的 WebView 對(duì)應(yīng)加載的 HTML文本文件部分截圖,
其中標(biāo)簽 src 對(duì)象的內(nèi)容就是我們想要的圖片 URL,所以到這里我們就有了思路,我們先拿到 WebView 加載的 HTML 內(nèi)容,然后在從 HTML 里面提取我要想要的 URL。
(3)現(xiàn)在我們能拿到所有圖片對(duì)應(yīng)的 URL,那么滑動(dòng)圖片顯示下一張就簡單了,我們直接用一個(gè) ViewPager 來實(shí)現(xiàn)滑動(dòng)加載圖片即可。
總結(jié)要實(shí)現(xiàn)這個(gè)需要我們需要做的工作有:
下面我們就按照以上幾個(gè)步驟來實(shí)現(xiàn)我們想要的功能。
二、主要內(nèi)容
2.1 獲取 WebView 頁面所有圖片對(duì)應(yīng)地址
2.1.1 解析 WebView 頁面加載的 HTML文本文件
定義供 JavaScript 調(diào)用的交互接口
/** *這個(gè)接口就是給 JavaScript 調(diào)用的,調(diào)用結(jié)果就是返回 HTML 文本, *然后 getAllImageUrlFromHtml(HTML) *從 HTML文件中提取頁面所有圖片對(duì)應(yīng)的地址對(duì)象 **/ private class InJavaScriptLocalObj { /** * 獲取 WebView 加載對(duì)應(yīng)的 HTML 文本 * @param HTML WebView 加載對(duì)應(yīng)的 HTML 文本 */ @android.webkit.JavascriptInterface public void showSource(String html) { //從 HTML 文件中提取頁面所有圖片對(duì)應(yīng)的地址對(duì)象 getAllImageUrlFromHtml(html); } }
WebView 開啟 JavaScript 腳本執(zhí)行,調(diào)用 JavaScript 代碼
mWebView.getSettings().setJavaScriptEnabled(true); mWebView.addJavascriptInterface(new InJavaScriptLocalObj(), "local_obj"); mWebView.setWebViewClient(new WebViewClient() { // 網(wǎng)頁跳轉(zhuǎn) @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } // 網(wǎng)頁加載結(jié)束 @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); //解析 HTML parseHTML(view); } /** * Java 調(diào)取 js 代碼, * @param view WebView */ private void parseHTML(WebView view) { //這段 js 代碼是解析獲取到了 HTML 文本文件,然后調(diào)用本地定義的 Java 代碼返回 //解析出來的 HTML 文本文件 view.loadUrl("javascript:window.local_obj.showSource(''+" + "document.getElementsByTagName('html')[0].innerHTML+'');"); }
2.1.2 從獲取到的 HTML文本文件中提取頁面所有圖片對(duì)應(yīng)的地址對(duì)象
// 獲取 img 標(biāo)簽正則 private static final String IMAGE_URL_TAG = "]*?>"; // 獲取 src 路徑的正則 private static final String IMAGE_URL_CONTENT = "http:\"?(.*?)(\"|>|\\s+)"; /*** * 獲取頁面所有圖片對(duì)應(yīng)的地址對(duì)象, * 例如 * @param HTML WebView 加載的 HTML 文本 * @return */ private List getAllImageUrlFromHtml(String html) { Matcher matcher = Pattern.compile(IMAGE_URL_TAG).matcher(html); List listImgUrl = new ArrayList (); while (matcher.find()) { listImgUrl.add(matcher.group()); } //從圖片對(duì)應(yīng)的地址對(duì)象中解析出 src 標(biāo)簽對(duì)應(yīng)的內(nèi)容 getAllImageUrlFormSrcObject(listImgUrl); return listImgUrl; } /*** * 從圖片對(duì)應(yīng)的地址對(duì)象中解析出 src 標(biāo)簽對(duì)應(yīng)的內(nèi)容,即 url * 例如 "http://sc1.hao123img.com/data/f44d0aab7bc35b8767de3c48706d429e" * @param listImageUrl 圖片地址對(duì)象例如 : * */ private List getAllImageUrlFormSrcObject(List listImageUrl) { for (String image : listImageUrl) { Matcher matcher = Pattern.compile(IMAGE_URL_CONTENT).matcher(image); while (matcher.find()) { listImgSrc.add(matcher.group().substring(0, matcher.group().length() - 1)); } } return listImgSrc; }
到這里我們獲取到了 WebView 頁面中所有圖片對(duì)象對(duì)應(yīng)的 URL 地址,下面就還差一步,就是在點(diǎn)擊 WebView 界面的圖片時(shí)候去響應(yīng)點(diǎn)擊事件,然后把相應(yīng)的 URL 地址傳遞給 ViewPager 進(jìn)行顯示就齊活了。
2.2 響應(yīng) WebView 界面圖片的點(diǎn)擊事件
2.2.1定義供 JavaScript 調(diào)用的交互接口
// js 通信接口,定義供 JavaScript 調(diào)用的交互接口 private class MyJavascriptInterface { private Context context; public MyJavascriptInterface(Context context) { this.context = context; } /** * 點(diǎn)擊圖片啟動(dòng)新的 ShowImageFromWebActivity,并傳入點(diǎn)擊圖片對(duì)應(yīng)的 url * 和頁面所有圖片對(duì)應(yīng)的 url * @param url 點(diǎn)擊圖片對(duì)應(yīng)的 url */ @android.webkit.JavascriptInterface public void openImage(String url) { Intent intent = new Intent(); intent.putExtra("image", url); //listImgSrc 該參數(shù)為頁面所有圖片對(duì)應(yīng)的 url intent.putStringArrayListExtra(URL_ALL, (ArrayList) listImgSrc); intent.setClass(context, ShowImageFromWebActivity.class); context.startActivity(intent); } }
2.2.2 WebView 開啟 JavaScript 腳本執(zhí)行,調(diào)用 JavaScript 代碼
mWebView.getSettings().setJavaScriptEnabled(true); //載入 js mWebView.addJavascriptInterface(new MyJavascriptInterface(this), "imageListener"); mWebView.setWebViewClient(new WebViewClient() { // 網(wǎng)頁跳轉(zhuǎn) @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } // 網(wǎng)頁加載結(jié)束 @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // web 頁面加載完成,添加監(jiān)聽圖片的點(diǎn)擊 js 函數(shù) addImageClickListener(); } /** * 注入 js 函數(shù)監(jiān)聽,這段 js 函數(shù)的功能就是,遍歷所有的圖片,并添加 onclick 函數(shù), * 實(shí)現(xiàn)點(diǎn)擊事件, * 函數(shù)的功能是在圖片點(diǎn)擊的時(shí)候調(diào)用本地 java 接口并傳遞點(diǎn)擊圖片對(duì)應(yīng)的 url 過去 */ private void addImageClickListener() { mWebView.loadUrl("javascript:(function(){" + "var objs = document.getElementsByTagName(\"img\"); " + "for(var i=0;i
到這里我們完成了前兩步,拿去到 WebView 界面圖片對(duì)應(yīng)的所有 URL 地址和響應(yīng) WebView 界面圖片的點(diǎn)擊事件,下面的事情就簡單了,用 ViewPager 滑動(dòng)顯示每一張圖片,再我們進(jìn)行最后一步之前,我們再來實(shí)現(xiàn)一個(gè)功能就是長按 WebView 界面圖片,彈出對(duì)話框來,然后可以選擇保存圖片功能,代碼如下:
WebView 中圖片長按點(diǎn)擊事件處理
//長按點(diǎn)擊事件 mWebView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { //響應(yīng)長按事件 responseWebLongClick(v); return false; } }); /** * 響應(yīng) WebView 長按圖片的點(diǎn)擊事件 * @param v */ private void responseWebLongClick(View v) { if (v instanceof WebView) { WebView.HitTestResult result = ((WebView) v).getHitTestResult(); if (result != null) { int type = result.getType(); //判斷點(diǎn)擊類型如果是圖片 if (type == WebView.HitTestResult.IMAGE_TYPE || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { longClickUrl = result.getExtra(); //彈出對(duì)話框 showDialog(longClickUrl); } } } } /** * 長按 WebView 中圖片彈出對(duì)話框,可以選擇保存圖片 * @param url 點(diǎn)擊圖片對(duì)應(yīng)的 url */ private void showDialog(final String url) { new ActionSheetDialog(this) .builder() .setCancelable(true) .setCanceledOnTouchOutside(true) .addSheetItem( "保存到相冊", ActionSheetDialog.SheetItemColor.Blue, new ActionSheetDialog.OnSheetItemClickListener() { @Override public void onClick(int which) { //下載圖片 downloadImage(url); } }).show(); }
2.3 ViewPager 滑動(dòng)顯示每一張圖片,PhotoView 實(shí)現(xiàn)自由縮放功能
由于這部分代碼比較簡單,這里就直接貼出部分代碼,文章中所用的 Demo 代碼最終會(huì)上傳到 GitHub上,有興趣可以去瞧一瞧完整的代碼,這里簡單介紹幾個(gè)類,ShowImageFromWebActivity.java 這個(gè)類內(nèi)部就包含一個(gè) ViewPager 和兩個(gè)按鈕, ViewPager 用來滑動(dòng)顯示每一張圖片,按鈕用來顯示滑動(dòng)的頁數(shù)和實(shí)現(xiàn)點(diǎn)擊保存圖片功能,代碼如下:
public class ShowImageFromWebActivity extends Activity implements View.OnClickListener { private ViewPager vpImageBrowser; private TextView tvImageIndex;//顯示滑動(dòng)頁數(shù) private Button btnSave;//保存圖片按鈕 private ImageBrowserAdapter adapter; private ArrayListimgUrls;//WebView 頁面所有圖片 URL private String url;//WebView 頁面所有圖片中被點(diǎn)擊圖片對(duì)應(yīng) URL private int currentIndex;//標(biāo)記被滑動(dòng)圖片在所有圖片中的位置 private Handler mHandler;//異步發(fā)送消息 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_show_image_from_web); initView(); initListener(); initData(); } private void initView(){ vpImageBrowser = (ViewPager) findViewById(R.id.vp_image_browser); tvImageIndex = (TextView) findViewById(R.id.tv_image_index); btnSave = (Button) findViewById(R.id.btn_save); } private void initData(){ mHandler = new Handler(); imgUrls=getIntent().getStringArrayListExtra(MainActivity.URL_ALL); url=getIntent().getStringExtra("image"); //獲取被點(diǎn)擊圖片在所有圖片中的位置 int position=imgUrls.indexOf(url); adapter=new ImageBrowserAdapter(this,imgUrls); vpImageBrowser.setAdapter(adapter); final int size=imgUrls.size(); if(size > 1) { tvImageIndex.setVisibility(View.VISIBLE); tvImageIndex.setText((position+1) + "/" + size); } else { tvImageIndex.setVisibility(View.GONE); } vpImageBrowser.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int arg0) { currentIndex=arg0; int index = arg0 % size; tvImageIndex.setText((index+1) + "/" + size); } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub } }); vpImageBrowser.setCurrentItem(position); } private void initListener(){ btnSave.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.btn_save : Toast.makeText(getApplicationContext(), "開始下載圖片", Toast.LENGTH_SHORT).show(); downloadImage(); break; } /** * 開始下載圖片 */ private void downloadImage() { downloadAsync(imgUrls.get(currentIndex), Environment.getExternalStorageDirectory().getAbsolutePath() + "/ImagesFromWebView"); } }
ShowImageFromWebActivity.java 對(duì)應(yīng) xml 文件
<?xml version="1.0" encoding="utf-8"?>
ImageBrowserAdapter.java 類代碼如下:
public class ImageBrowserAdapter extends PagerAdapter { private Activity context; private ListpicUrls; public ImageBrowserAdapter(Activity context, ArrayList picUrls) { this.context = context; this.picUrls = picUrls; } @Override public int getCount() { return picUrls.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public View instantiateItem(ViewGroup container, int position) { View view = View.inflate(context, R.layout.item_image_browser, null); ImageView iv_image_browser = (ImageView) view.findViewById(R.id.show_webimage_imageview); String picUrl = picUrls.get(position); final PhotoViewAttacher photoViewAttacher=new PhotoViewAttacher(iv_image_browser); photoViewAttacher.setScaleType(ImageView.ScaleType.FIT_CENTER); //顯示圖片 Glide.with(context). load(picUrl) .crossFade() .placeholder(R.drawable.avatar_default) .error(R.drawable.image_default_rect) .into(new GlideDrawableImageViewTarget(iv_image_browser){ @Override public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) { super.onResourceReady(resource, animation); photoViewAttacher.update(); } }); container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); }
上面代碼也很簡單,就是根據(jù) URL 來加載顯示圖片,然后利用 PhotoView 進(jìn)行縮放。
//ImageBrowserAdapter Item 布局文件 <?xml version="1.0" encoding="utf-8"?>
以上為本次學(xué)習(xí)內(nèi)容,如有錯(cuò)誤還望指正,謝謝!
文章中 Demo 已經(jīng)上傳在 GitHub上,地址為ShowImageFromWebView,大家也可以通過本地下載
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)各位Android開發(fā)者們能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對(duì)創(chuàng)新互聯(lián)的支持。