Android實現(xiàn)點擊WebView界面中圖片滑動瀏覽與保存圖片功能
1、找一個比較出名的客戶端有類似功能的,然后 Google 搜索,仿 XXXX,先粗略看一下有沒有現(xiàn)成的 Demo 可以參考,比如我這個需要,先去搜索一下 ”Android 仿微信朋友圈瀏覽圖片效果“ (這個搜索關鍵字很關鍵?。墒枪P者沒找到符合該需要的 Demo。
2、在第一個方案不好使的情況下,我們沒有了參考,那么咱們就得自己思考這個大概實現(xiàn)思路,然后把這個需求進行拆分,逐一擊破。所以思考大概如下:
(1)要想展示圖片那么就得先拿到圖片,要拿到圖片只有兩種可能,第一種可能是 WebView 本身緩存了圖片,我們去緩存中讀取圖片進行顯示,可是想一下,咱們?yōu)g覽微博看圖的時候如果沒有網(wǎng),這時候去點擊圖片那么圖片是加載不出來的,所以這種可能否定了;所以只有第二種可能就是點擊圖片的時候拿到該圖片對應的 URL 網(wǎng)址,然后咱們自己去網(wǎng)絡加載圖片進行顯示,所以這個點我們 Get 到了。
(2)要滑動圖片進行顯示下一張,那么就需要我們能拿到所有要顯示的圖片的 URL ,然后放到一個數(shù)組里面,每次滑動就進行加載一張圖片,那么也就是我們一次性拿到所有 WebView 包含圖片的 URL,這個就不是在點擊圖片的時候去獲取,而是在 WebView 加載完成后獲取到,這怎么能拿到?再想一下,WebView 進行加載顯示的時候其實是加載 HTML(比如 Assets 目錄中的文件)文本的字符串,然后進行渲染處理顯示出來,所以 HTML文本文件里面包含了我們想要的圖片網(wǎng)址,大家看一下下面這張截圖就是一個帶圖片的 WebView 對應加載的 HTML文本文件部分截圖,
其中標簽 src 對象的內容就是我們想要的圖片 URL,所以到這里我們就有了思路,我們先拿到 WebView 加載的 HTML 內容,然后在從 HTML 里面提取我要想要的 URL。
(3)現(xiàn)在我們能拿到所有圖片對應的 URL,那么滑動圖片顯示下一張就簡單了,我們直接用一個 ViewPager 來實現(xiàn)滑動加載圖片即可。
總結要實現(xiàn)這個需要我們需要做的工作有:
- 拿到 WebView 加載的 HTML 文本。
- 從 HTML 文本中提取所有圖片對應的 URL。
- 處理 WebView 中圖片的點擊和長按響應事件。
- 用 ViewPager 來實現(xiàn)滑動加載下一張圖片。
下面我們就按照以上幾個步驟來實現(xiàn)我們想要的功能。
二、主要內容
2.1 獲取 WebView 頁面所有圖片對應地址
2.1.1 解析 WebView 頁面加載的 HTML文本文件
定義供 JavaScript 調用的交互接口
/** *這個接口就是給 JavaScript 調用的,調用結果就是返回 HTML 文本, *然后 getAllImageUrlFromHtml(HTML) *從 HTML文件中提取頁面所有圖片對應的地址對象 **/ private class InJavaScriptLocalObj { /** * 獲取 WebView 加載對應的 HTML 文本 * @param HTML WebView 加載對應的 HTML 文本 */ @android.webkit.JavascriptInterface public void showSource(String html) { //從 HTML 文件中提取頁面所有圖片對應的地址對象 getAllImageUrlFromHtml(html); } }
WebView 開啟 JavaScript 腳本執(zhí)行,調用 JavaScript 代碼
mWebView.getSettings().setJavaScriptEnabled(true); mWebView.addJavascriptInterface(new InJavaScriptLocalObj(), "local_obj"); mWebView.setWebViewClient(new WebViewClient() { // 網(wǎng)頁跳轉 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } // 網(wǎng)頁加載結束 @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); //解析 HTML parseHTML(view); } /** * Java 調取 js 代碼, * @param view WebView */ private void parseHTML(WebView view) { //這段 js 代碼是解析獲取到了 HTML 文本文件,然后調用本地定義的 Java 代碼返回 //解析出來的 HTML 文本文件 view.loadUrl("javascript:window.local_obj.showSource('<head>'+" + "document.getElementsByTagName('html')[0].innerHTML+'</head>');"); }
2.1.2 從獲取到的 HTML文本文件中提取頁面所有圖片對應的地址對象
// 獲取 img 標簽正則 private static final String IMAGE_URL_TAG = "<img.*src=(.*?)[^>]*?>"; // 獲取 src 路徑的正則 private static final String IMAGE_URL_CONTENT = "http:\"?(.*?)(\"|>|\\s+)"; /*** * 獲取頁面所有圖片對應的地址對象, * 例如 <img src="http://sc1.hao123img.com/data/f44d0aab7bc35b8767de3c48706d429e" /> * @param HTML WebView 加載的 HTML 文本 * @return */ private List<String> getAllImageUrlFromHtml(String html) { Matcher matcher = Pattern.compile(IMAGE_URL_TAG).matcher(html); List<String> listImgUrl = new ArrayList<String>(); while (matcher.find()) { listImgUrl.add(matcher.group()); } //從圖片對應的地址對象中解析出 src 標簽對應的內容 getAllImageUrlFormSrcObject(listImgUrl); return listImgUrl; } /*** * 從圖片對應的地址對象中解析出 src 標簽對應的內容,即 url * 例如 "http://sc1.hao123img.com/data/f44d0aab7bc35b8767de3c48706d429e" * @param listImageUrl 圖片地址對象例如 : *<img src="http://sc1.hao123img.com/data/f44daab" /> */ private List<String> getAllImageUrlFormSrcObject(List<String> 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 頁面中所有圖片對象對應的 URL 地址,下面就還差一步,就是在點擊 WebView 界面的圖片時候去響應點擊事件,然后把相應的 URL 地址傳遞給 ViewPager 進行顯示就齊活了。
2.2 響應 WebView 界面圖片的點擊事件
2.2.1定義供 JavaScript 調用的交互接口
// js 通信接口,定義供 JavaScript 調用的交互接口 private class MyJavascriptInterface { private Context context; public MyJavascriptInterface(Context context) { this.context = context; } /** * 點擊圖片啟動新的 ShowImageFromWebActivity,并傳入點擊圖片對應的 url * 和頁面所有圖片對應的 url * @param url 點擊圖片對應的 url */ @android.webkit.JavascriptInterface public void openImage(String url) { Intent intent = new Intent(); intent.putExtra("image", url); //listImgSrc 該參數(shù)為頁面所有圖片對應的 url intent.putStringArrayListExtra(URL_ALL, (ArrayList<String>) listImgSrc); intent.setClass(context, ShowImageFromWebActivity.class); context.startActivity(intent); } }
2.2.2 WebView 開啟 JavaScript 腳本執(zhí)行,調用 JavaScript 代碼
mWebView.getSettings().setJavaScriptEnabled(true); //載入 js mWebView.addJavascriptInterface(new MyJavascriptInterface(this), "imageListener"); mWebView.setWebViewClient(new WebViewClient() { // 網(wǎng)頁跳轉 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } // 網(wǎng)頁加載結束 @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // web 頁面加載完成,添加圖片的點擊 js 函數(shù) addImageClickListener(); } /** * 注入 js 函數(shù),這段 js 函數(shù)的功能就是,遍歷所有的圖片,并添加 onclick 函數(shù), * 實現(xiàn)點擊事件, * 函數(shù)的功能是在圖片點擊的時候調用本地 java 接口并傳遞點擊圖片對應的 url 過去 */ private void addImageClickListener() { mWebView.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); " + " } " + "}" + "})()"); }
到這里我們完成了前兩步,拿去到 WebView 界面圖片對應的所有 URL 地址和響應 WebView 界面圖片的點擊事件,下面的事情就簡單了,用 ViewPager 滑動顯示每一張圖片,再我們進行最后一步之前,我們再來實現(xiàn)一個功能就是長按 WebView 界面圖片,彈出對話框來,然后可以選擇保存圖片功能,代碼如下:
WebView 中圖片長按點擊事件處理
//長按點擊事件 mWebView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { //響應長按事件 responseWebLongClick(v); return false; } }); /** * 響應 WebView 長按圖片的點擊事件 * @param v */ private void responseWebLongClick(View v) { if (v instanceof WebView) { WebView.HitTestResult result = ((WebView) v).getHitTestResult(); if (result != null) { int type = result.getType(); //判斷點擊類型如果是圖片 if (type == WebView.HitTestResult.IMAGE_TYPE || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { longClickUrl = result.getExtra(); //彈出對話框 showDialog(longClickUrl); } } } } /** * 長按 WebView 中圖片彈出對話框,可以選擇保存圖片 * @param url 點擊圖片對應的 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 滑動顯示每一張圖片,PhotoView 實現(xiàn)自由縮放功能
由于這部分代碼比較簡單,這里就直接貼出部分代碼,文章中所用的 Demo 代碼最終會上傳到 GitHub上,有興趣可以去瞧一瞧完整的代碼,這里簡單介紹幾個類,ShowImageFromWebActivity.java 這個類內部就包含一個 ViewPager 和兩個按鈕, ViewPager 用來滑動顯示每一張圖片,按鈕用來顯示滑動的頁數(shù)和實現(xiàn)點擊保存圖片功能,代碼如下:
public class ShowImageFromWebActivity extends Activity implements View.OnClickListener { private ViewPager vpImageBrowser; private TextView tvImageIndex;//顯示滑動頁數(shù) private Button btnSave;//保存圖片按鈕 private ImageBrowserAdapter adapter; private ArrayList<String> imgUrls;//WebView 頁面所有圖片 URL private String url;//WebView 頁面所有圖片中被點擊圖片對應 URL private int currentIndex;//標記被滑動圖片在所有圖片中的位置 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"); //獲取被點擊圖片在所有圖片中的位置 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 對應 xml 文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black" tools:context="activity.ShowImageFromWebActivity"> <view.PhotoViewViewPager android:id="@+id/vp_image_browser" android:layout_width="match_parent" android:layout_height="match_parent" > </view.PhotoViewViewPager> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" android:padding="16dp" > <TextView android:textSize="18sp" android:id="@+id/tv_image_index" android:layout_width="56dp" android:layout_height="36dp" android:background="@drawable/shape_corner_rect_gray" android:gravity="center" android:paddingTop="3dp" android:paddingBottom="3dp" android:paddingRight="10dp" android:paddingLeft="10dp" android:text="1/9" android:textColor="@android:color/white" /> <View android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="1" /> <Button android:id="@+id/btn_save" android:textSize="@dimen/_16sp" android:layout_width="56dp" android:layout_height="36dp" android:background="@drawable/shape_corner_rect_gray" android:gravity="center" android:padding="4dp" android:text="保存" android:textColor="@color/white" /> </LinearLayout> </RelativeLayout>
ImageBrowserAdapter.java 類代碼如下:
public class ImageBrowserAdapter extends PagerAdapter { private Activity context; private List<String> picUrls; public ImageBrowserAdapter(Activity context, ArrayList<String> 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 進行縮放。
//ImageBrowserAdapter Item 布局文件 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <RelativeLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical"> <uk.co.senab.photoview.PhotoView android:id="@+id/pv_show_image" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:src="@drawable/image_default_rect" /> </RelativeLayout> </RelativeLayout>
以上為本次學習內容,如有錯誤還望指正,謝謝!
文章中 Demo 已經(jīng)上傳在 GitHub上,地址為ShowImageFromWebView,大家也可以通過本地下載
總結
以上就是這篇文章的全部內容了,希望本文的內容對各位Android開發(fā)者們能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
Android RecycleView和線型布局制作聊天布局
大家好,本篇文章主要講的是Android RecycleView和線型布局制作聊天布局,感興趣的同學趕緊來看一看吧,對你有幫助的話記得收藏一下2022-01-01Android 實時監(jiān)測(監(jiān)聽)網(wǎng)絡連接狀態(tài)變化
這篇文章主要介紹了Android 實時監(jiān)測(監(jiān)聽)網(wǎng)絡連接狀態(tài)變化的相關知識,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-06-06Android入門之使用SimpleAdapter實現(xiàn)復雜界面布局
這篇文章主要為大家詳細介紹了Android如何使用SimpleAdapter實現(xiàn)復雜的界面布局,文中的示例代碼講解詳細,對我們學習Android有一定的幫助,需要的可以參考一下2022-11-11Android微信自動搶紅包插件優(yōu)化和實現(xiàn)
這篇文章主要為大家詳細介紹了Android微信自動搶紅包插件優(yōu)化和實現(xiàn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12Android自定義WaveView實現(xiàn)波浪進度效果
最近注意到百度外賣以及淘寶個人中心,都用到了類似水波起伏的效果,于是就參照網(wǎng)上的資料然后自己整改,自定義了一個waveView來實現(xiàn)這個效果,文中給出來詳細的實現(xiàn)原理及實例代碼,有需要的朋友們可以參考借鑒,下面來一起看看吧。2017-01-01Android應用中炫酷的橫向和環(huán)形進度條的實例分享
這篇文章主要介紹了Android應用中炫酷的橫向和圓形進度條的實例分享,文中利用了一些GitHub上的插件進行改寫,也是一片很好的二次開發(fā)教學,需要的朋友可以參考下2016-04-04Android實現(xiàn)瘋狂連連看游戲之加載界面圖片和實現(xiàn)游戲Activity(四)
這篇文章主要為大家詳細介紹了Android實現(xiàn)瘋狂連連看游戲之加載界面圖片和實現(xiàn)游戲Activity,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03