Android實(shí)現(xiàn)點(diǎn)擊WebView界面中圖片滑動(dòng)瀏覽與保存圖片功能
1、找一個(gè)比較出名的客戶端有類(lèi)似功能的,然后 Google 搜索,仿 XXXX,先粗略看一下有沒(méi)有現(xiàn)成的 Demo 可以參考,比如我這個(gè)需要,先去搜索一下 ”Android 仿微信朋友圈瀏覽圖片效果“ (這個(gè)搜索關(guān)鍵字很關(guān)鍵?。墒枪P者沒(méi)找到符合該需要的 Demo。
2、在第一個(gè)方案不好使的情況下,我們沒(méi)有了參考,那么咱們就得自己思考這個(gè)大概實(shí)現(xiàn)思路,然后把這個(gè)需求進(jìn)行拆分,逐一擊破。所以思考大概如下:
(1)要想展示圖片那么就得先拿到圖片,要拿到圖片只有兩種可能,第一種可能是 WebView 本身緩存了圖片,我們?nèi)ゾ彺嬷凶x取圖片進(jìn)行顯示,可是想一下,咱們?yōu)g覽微博看圖的時(shí)候如果沒(méi)有網(wǎng),這時(shí)候去點(diǎn)擊圖片那么圖片是加載不出來(lái)的,所以這種可能否定了;所以只有第二種可能就是點(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)行渲染處理顯示出來(lái),所以 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)圖片顯示下一張就簡(jiǎn)單了,我們直接用一個(gè) ViewPager 來(lái)實(shí)現(xiàn)滑動(dòng)加載圖片即可。
總結(jié)要實(shí)現(xiàn)這個(gè)需要我們需要做的工作有:
- 拿到 WebView 加載的 HTML 文本。
- 從 HTML 文本中提取所有圖片對(duì)應(yīng)的 URL。
- 處理 WebView 中圖片的點(diǎn)擊和長(zhǎng)按響應(yīng)事件。
- 用 ViewPager 來(lái)實(shí)現(xiàn)滑動(dòng)加載下一張圖片。
下面我們就按照以上幾個(gè)步驟來(lái)實(shí)現(xiàn)我們想要的功能。
二、主要內(nèi)容
2.1 獲取 WebView 頁(yè)面所有圖片對(duì)應(yīng)地址
2.1.1 解析 WebView 頁(yè)面加載的 HTML文本文件
定義供 JavaScript 調(diào)用的交互接口
/**
*這個(gè)接口就是給 JavaScript 調(diào)用的,調(diào)用結(jié)果就是返回 HTML 文本,
*然后 getAllImageUrlFromHtml(HTML)
*從 HTML文件中提取頁(yè)面所有圖片對(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 文件中提取頁(yè)面所有圖片對(duì)應(yīng)的地址對(duì)象
getAllImageUrlFromHtml(html);
}
}WebView 開(kāi)啟 JavaScript 腳本執(zhí)行,調(diào)用 JavaScript 代碼
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new InJavaScriptLocalObj(), "local_obj");
mWebView.setWebViewClient(new WebViewClient() {
// 網(wǎng)頁(yè)跳轉(zhuǎn)
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
// 網(wǎng)頁(yè)加載結(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 代碼返回
//解析出來(lái)的 HTML 文本文件
view.loadUrl("javascript:window.local_obj.showSource('<head>'+"
+ "document.getElementsByTagName('html')[0].innerHTML+'</head>');");
}2.1.2 從獲取到的 HTML文本文件中提取頁(yè)面所有圖片對(duì)應(yīng)的地址對(duì)象
// 獲取 img 標(biāo)簽正則
private static final String IMAGE_URL_TAG = "<img.*src=(.*?)[^>]*?>";
// 獲取 src 路徑的正則
private static final String IMAGE_URL_CONTENT = "http:\"?(.*?)(\"|>|\\s+)";
/***
* 獲取頁(yè)面所有圖片對(duì)應(yīng)的地址對(duì)象,
* 例如 <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());
}
//從圖片對(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ì)象例如 :
*<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 頁(yè)面中所有圖片對(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
* 和頁(yè)面所有圖片對(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ù)為頁(yè)面所有圖片對(duì)應(yīng)的 url
intent.putStringArrayListExtra(URL_ALL, (ArrayList<String>) listImgSrc);
intent.setClass(context, ShowImageFromWebActivity.class);
context.startActivity(intent);
}
}2.2.2 WebView 開(kāi)啟 JavaScript 腳本執(zhí)行,調(diào)用 JavaScript 代碼
mWebView.getSettings().setJavaScriptEnabled(true);
//載入 js
mWebView.addJavascriptInterface(new MyJavascriptInterface(this), "imageListener");
mWebView.setWebViewClient(new WebViewClient() {
// 網(wǎng)頁(yè)跳轉(zhuǎn)
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
// 網(wǎng)頁(yè)加載結(jié)束
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
// web 頁(yè)面加載完成,添加圖片的點(diǎn)擊 js 函數(shù)
addImageClickListener();
}
/**
* 注入 js 函數(shù),這段 js 函數(shù)的功能就是,遍歷所有的圖片,并添加 onclick 函數(shù),
* 實(shí)現(xiàn)點(diǎn)擊事件,
* 函數(shù)的功能是在圖片點(diǎn)擊的時(shí)候調(diào)用本地 java 接口并傳遞點(diǎn)擊圖片對(duì)應(yīng)的 url 過(guò)去
*/
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 界面圖片對(duì)應(yīng)的所有 URL 地址和響應(yīng) WebView 界面圖片的點(diǎn)擊事件,下面的事情就簡(jiǎn)單了,用 ViewPager 滑動(dòng)顯示每一張圖片,再我們進(jìn)行最后一步之前,我們?cè)賮?lái)實(shí)現(xiàn)一個(gè)功能就是長(zhǎng)按 WebView 界面圖片,彈出對(duì)話框來(lái),然后可以選擇保存圖片功能,代碼如下:
WebView 中圖片長(zhǎng)按點(diǎn)擊事件處理
//長(zhǎng)按點(diǎn)擊事件
mWebView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//響應(yīng)長(zhǎng)按事件
responseWebLongClick(v);
return false;
}
});
/**
* 響應(yīng) WebView 長(zhǎng)按圖片的點(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)擊類(lèi)型如果是圖片
if (type == WebView.HitTestResult.IMAGE_TYPE || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
longClickUrl = result.getExtra();
//彈出對(duì)話框
showDialog(longClickUrl);
}
}
}
}
/**
* 長(zhǎng)按 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(
"保存到相冊(cè)",
ActionSheetDialog.SheetItemColor.Blue,
new ActionSheetDialog.OnSheetItemClickListener() {
@Override
public void onClick(int which) {
//下載圖片
downloadImage(url);
}
}).show();
}2.3 ViewPager 滑動(dòng)顯示每一張圖片,PhotoView 實(shí)現(xiàn)自由縮放功能
由于這部分代碼比較簡(jiǎn)單,這里就直接貼出部分代碼,文章中所用的 Demo 代碼最終會(huì)上傳到 GitHub上,有興趣可以去瞧一瞧完整的代碼,這里簡(jiǎn)單介紹幾個(gè)類(lèi),ShowImageFromWebActivity.java 這個(gè)類(lèi)內(nèi)部就包含一個(gè) ViewPager 和兩個(gè)按鈕, ViewPager 用來(lái)滑動(dòng)顯示每一張圖片,按鈕用來(lái)顯示滑動(dòng)的頁(yè)數(shù)和實(shí)現(xiàn)點(diǎn)擊保存圖片功能,代碼如下:
public class ShowImageFromWebActivity extends Activity implements View.OnClickListener {
private ViewPager vpImageBrowser;
private TextView tvImageIndex;//顯示滑動(dòng)頁(yè)數(shù)
private Button btnSave;//保存圖片按鈕
private ImageBrowserAdapter adapter;
private ArrayList<String> imgUrls;//WebView 頁(yè)面所有圖片 URL
private String url;//WebView 頁(yè)面所有圖片中被點(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(), "開(kāi)始下載圖片", Toast.LENGTH_SHORT).show();
downloadImage();
break;
}
/**
* 開(kāi)始下載圖片
*/
private void downloadImage() {
downloadAsync(imgUrls.get(currentIndex), Environment.getExternalStorageDirectory().getAbsolutePath() + "/ImagesFromWebView");
}
}ShowImageFromWebActivity.java 對(duì)應(yīng) 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 類(lèi)代碼如下:
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);
}上面代碼也很簡(jiǎn)單,就是根據(jù) URL 來(lái)加載顯示圖片,然后利用 PhotoView 進(jìn)行縮放。
//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>
以上為本次學(xué)習(xí)內(nèi)容,如有錯(cuò)誤還望指正,謝謝!
文章中 Demo 已經(jīng)上傳在 GitHub上,地址為ShowImageFromWebView,大家也可以通過(guò)本地下載
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)各位Android開(kāi)發(fā)者們能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Android RecycleView和線型布局制作聊天布局
大家好,本篇文章主要講的是Android RecycleView和線型布局制作聊天布局,感興趣的同學(xué)趕緊來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01
Android 實(shí)時(shí)監(jiān)測(cè)(監(jiān)聽(tīng))網(wǎng)絡(luò)連接狀態(tài)變化
這篇文章主要介紹了Android 實(shí)時(shí)監(jiān)測(cè)(監(jiān)聽(tīng))網(wǎng)絡(luò)連接狀態(tài)變化的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-06-06
Android入門(mén)之使用SimpleAdapter實(shí)現(xiàn)復(fù)雜界面布局
這篇文章主要為大家詳細(xì)介紹了Android如何使用SimpleAdapter實(shí)現(xiàn)復(fù)雜的界面布局,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Android有一定的幫助,需要的可以參考一下2022-11-11
Android微信自動(dòng)搶紅包插件優(yōu)化和實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Android微信自動(dòng)搶紅包插件優(yōu)化和實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
Android自定義WaveView實(shí)現(xiàn)波浪進(jìn)度效果
最近注意到百度外賣(mài)以及淘寶個(gè)人中心,都用到了類(lèi)似水波起伏的效果,于是就參照網(wǎng)上的資料然后自己整改,自定義了一個(gè)waveView來(lái)實(shí)現(xiàn)這個(gè)效果,文中給出來(lái)詳細(xì)的實(shí)現(xiàn)原理及實(shí)例代碼,有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2017-01-01
android socket聊天室功能實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了android socket聊天室功能實(shí)現(xiàn)方法,不單純是聊天室,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
基于Android XML解析與保存的實(shí)現(xiàn)
本篇文章小編為大家介紹,基于Android XML解析與保存的實(shí)現(xiàn)。需要的朋友參考下2013-04-04
Android應(yīng)用中炫酷的橫向和環(huán)形進(jìn)度條的實(shí)例分享
這篇文章主要介紹了Android應(yīng)用中炫酷的橫向和圓形進(jìn)度條的實(shí)例分享,文中利用了一些GitHub上的插件進(jìn)行改寫(xiě),也是一片很好的二次開(kāi)發(fā)教學(xué),需要的朋友可以參考下2016-04-04
android閃關(guān)燈的開(kāi)啟和關(guān)閉方法代碼實(shí)例
這篇文章主要介紹了android閃關(guān)燈的開(kāi)啟和關(guān)閉方法代碼實(shí)例,本文直接給出代碼和配置實(shí)例,需要的朋友可以參考下2015-05-05
Android實(shí)現(xiàn)瘋狂連連看游戲之加載界面圖片和實(shí)現(xiàn)游戲Activity(四)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)瘋狂連連看游戲之加載界面圖片和實(shí)現(xiàn)游戲Activity,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03

