[Android]网页内图片点击查看大图/识别二维码/下载
16lz
2021-01-25
场景
项目中的广告详情页面是个webView加载的富文本,包含图片,需要点击查看大图,长按识别二维码功能。
实现
- webView基础设置
val webView = fragment.binding.webView webView.settings.javaScriptEnabled = true webView.settings.builtInZoomControls = false webView.settings.displayZoomControls = true webView.settings.setSupportZoom(false)//不支持缩放功能 webView.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY //取消滚动条白边效果 webView.webChromeClient = WebChromeClient() webView.webViewClient = MyWebViewClient() webView.addJavascriptInterface(MJavascriptInterface(fragment.activity,fragment),"imagelistener") webView.settings.defaultTextEncodingName = "UTF-8" webView.settings.blockNetworkImage = false if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { webView.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW //注意安卓5.0以上的权限 } if (detail.content.checkNotNull()) { val css = "" val html = css + "" + detail.content + "" webView.loadDataWithBaseURL(null, ImageUtil.getNewContent(html), "text/html", "UTF-8", null) } webView.setOnLongClickListener(object : View.OnLongClickListener { override fun onLongClick(v: View?): Boolean { val result =webView.hitTestResult if (!result.checkNotNull()) { return false } val type = result.type when (type) { // 超链接 WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE,/*带有链接的图片类型*/WebView.HitTestResult.IMAGE_TYPE -> { // 处理长按图片的菜单项 val coverUrl = result.extra if (URLUtil.isValidUrl(coverUrl) || coverUrl.startsWith("data:image")) { UiUtils.webViewLongClick(fragment, webView.context, coverUrl) return true } } } return false } })
- webViewLongClick
/*网页长按弹窗(识别二维码,下载图片)*/ @JvmStatic fun webViewLongClick(fragment: BaseFragment, context: Context, coverUrl: String) { openSelect(fragment, context, coverUrl) } /*网页长按弹窗(识别二维码,下载图片)*/ private fun openSelect(fragment: BaseFragment, context: Context, coverUrl: String) { val dialog = BottomSheetDialog(context) val layoutView = LayoutInflater.from(context).inflate(R.layout.dialog_select_qrcode_down_img, null) layoutView.findViewById(R.id.tv_qrcode).setOnClickListener { //图片url Glide.with(context.applicationContext).asBitmap().load(coverUrl) .into(object : SimpleTarget() { override fun onResourceReady(resource: Bitmap, transition: Transition?) { CodeUtils.analyzeBitmap(resource, object : CodeUtils.AnalyzeCallback { override fun onAnalyzeSuccess(mBitmap: Bitmap, result: String) { fragment.start(WebFragment.newInstance("", result)) } override fun onAnalyzeFailed() { "未识别到二维码".toast() } }) dialog.dismiss() } }) } layoutView.findViewById(R.id.tv_download).setOnClickListener { if (coverUrl.startsWith("data:image")) { var fileName: String? = null if (MimeTypeMap.getFileExtensionFromUrl(coverUrl) == "") { fileName = System.currentTimeMillis().toString() + ".jpg" } else { fileName = System.currentTimeMillis().toString() + "." + MimeTypeMap.getFileExtensionFromUrl(coverUrl) } val file = BitmapUtils.saveBitmapFile(AndroidtoJs.stringToBitmap(coverUrl), DownLoadImageRunnable.SAVE_DOWNLOAD_IMAGE_PATH + fileName) if (file.checkNotNull()) { "已保存".toast() } else { "保存失败".toast() } } else { ImageUtil.downLoadImg(context, coverUrl) } dialog.dismiss() } dialog.setContentView(layoutView) dialog.show() }
- 弹窗布局dialog_select_qrcode_down_img.xml
<?xml version="1.0" encoding="utf-8"?>
- MyWebViewClient
import android.graphics.Bitmap;import android.webkit.WebView;import android.webkit.WebViewClient;/** * Created by Administrator on 2017/2/10. */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\");" + " " + " var array=new Array(); " + " for(var j=0;j
- MJavascriptInterface
import android.app.Activity;import android.widget.ImageView;import com.xlj.app.global.base.BaseFragment;import com.xlj.app.widget.ninegrid.ImageInfo;import java.util.ArrayList;public class MJavascriptInterface { private Activity context; private BaseFragment fragment; private static final String TAG = "SIMON"; ArrayList images = new ArrayList<>(); public MJavascriptInterface(Activity context, BaseFragment fragment) { this.context = context; this.fragment = fragment; } @android.webkit.JavascriptInterface //必须添加 public void openImage(String img, String[] array) { int index = 0; ArrayList imageInfo = new ArrayList<>(); for (int i = 0; i < array.length; i++) { ImageInfo imInfo = new ImageInfo(); imInfo.thumbnailUrl = array[i]; imInfo.bigImageUrl = array[i]; imageInfo.add(imInfo); if (array[i].equals(img)) { index = printArray(array, img); } } ImageView imageView = new ImageView(context); fragment.previewPhoto(imageView, imageInfo, index, false, true,true); } //遍历数组 private int printArray(String[] array, String value) { for (int i = 0; i < array.length; i++) { if (array[i].equals(value)) { return i; } } return -1;//当if条件不成立时,默认返回一个负数值-1 }}
- 大图查看
//图片预览 fun previewPhoto(clickImageView: ImageView, imageInfo: List, index: Int, finishAnimator: Boolean = true, isShowShare: Boolean = false,isSeeCode:Boolean=false) { if (imageInfo.isNotEmpty()) { val info: ImageInfo = imageInfo[0] imageInfo.forEach { it.imageViewWidth = clickImageView.width it.imageViewHeight = clickImageView.height val points = IntArray(2) clickImageView.getLocationInWindow(points) info.imageViewX = points[0] info.imageViewY = points[1] - StatusBarUtil.getStatusBarHeight(activity) } val intent = Intent(context, ImagePreviewActivity::class.java) val bundle = Bundle() bundle.putSerializable(ImagePreviewActivity.IMAGE_INFO, imageInfo as Serializable) bundle.putInt(ImagePreviewActivity.CURRENT_ITEM, index) bundle.putBoolean(ImagePreviewActivity.FINISH_ANIMATION, finishAnimator) bundle.putBoolean(ImagePreviewActivity.IS_SHOW_SHARE, isShowShare) bundle.putBoolean(ImagePreviewActivity.IS_SEE_CODE, isSeeCode) intent.putExtras(bundle) context!!.startActivity(intent) activity!!.overridePendingTransition(0, 0) } }
- 下面是图片预览的activity -----ImagePreviewActivity
import android.animation.Animator;import android.animation.ValueAnimator;import android.app.Activity;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Color;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.support.v4.view.ViewPager;import android.util.DisplayMetrics;import android.view.View;import android.view.ViewTreeObserver;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.TextView;import com.bigkoo.alertview.AlertView;import com.bigkoo.alertview.OnItemClickListener;import com.bumptech.glide.Glide;import com.bumptech.glide.request.target.SimpleTarget;import com.bumptech.glide.request.transition.Transition;import com.dtr.zxing.utils.CodeUtils;import com.kaopiz.kprogresshud.KProgressHUD;import com.tencent.qcloud.tim.uikit.component.photoview.downloadimg.ImageUtil;import com.tencent.qcloud.tim.uikit.utils.ToastUtil;import com.umeng.analytics.MobclickAgent;import com.umeng.socialize.UMShareAPI;import com.xlj.app.R;import com.xlj.app.global.Constant;import com.xlj.app.mvvm.main.activity.WebActivity;import com.xlj.app.mvvm.main.fragment.WebFragment;import com.xlj.app.utils.EventBusUtils;import com.xlj.app.utils.Toast.ToastUtils;import com.xlj.app.widget.ninegrid.ImageInfo;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.util.List;public class ImagePreviewActivity extends Activity implements ViewTreeObserver.OnPreDrawListener { public static final String IMAGE_INFO = "IMAGE_INFO"; public static final String CURRENT_ITEM = "CURRENT_ITEM"; public static final String FINISH_ANIMATION = "FINISH_ANIMATION"; public static final String IS_SHOW_SHARE = "IS_SHOW_SHARE"; //是否有 识别二维码 public static final String IS_SEE_CODE = "IS_SEE_CODE"; public static final int ANIMATE_DURATION = 200; private RelativeLayout rootView; private ImagePreviewAdapter imagePreviewAdapter; private List imageInfo; private int currentItem; private int imageHeight; private int imageWidth; private int screenWidth; private int screenHeight; private boolean isUseFinishAnimator, isShowShare, isSeeCode; private KProgressHUD loading; private String bigImageUrl; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_preview); loading = KProgressHUD.create(ImagePreviewActivity.this).setStyle(KProgressHUD.Style.SPIN_INDETERMINATE).setWindowColor(ImagePreviewActivity.this.getResources().getColor(R.color.color_trans)).setCancellable(false); ViewPager viewPager = findViewById(R.id.viewPager); final TextView tv_pager = findViewById(R.id.tv_pager); ImageView imgShare = findViewById(R.id.img_share); rootView = findViewById(R.id.rootView); DisplayMetrics metric = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metric); screenWidth = metric.widthPixels; screenHeight = metric.heightPixels; Intent intent = getIntent(); imageInfo = (List) intent.getSerializableExtra(IMAGE_INFO); currentItem = intent.getIntExtra(CURRENT_ITEM, 0); isUseFinishAnimator = intent.getBooleanExtra(FINISH_ANIMATION, true); isShowShare = intent.getBooleanExtra(IS_SHOW_SHARE, false);//是否有弹窗菜单(转发。保存) isSeeCode = intent.getBooleanExtra(IS_SEE_CODE, false);//是否有弹窗菜单(转发。保存) imgShare.setVisibility(isShowShare ? View.VISIBLE : View.GONE); imagePreviewAdapter = new ImagePreviewAdapter(this, imageInfo); imagePreviewAdapter.setIsShowOrginal(isShowShare); imagePreviewAdapter.setSeeCode(isSeeCode); viewPager.setAdapter(imagePreviewAdapter); viewPager.setCurrentItem(currentItem); viewPager.getViewTreeObserver().addOnPreDrawListener(this); viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { currentItem = position; tv_pager.setText(String.format(getString(R.string.select), currentItem + 1, imageInfo.size())); } }); tv_pager.setText(String.format(getString(R.string.select), currentItem + 1, imageInfo.size())); bigImageUrl = imageInfo.get(currentItem).thumbnailUrl; imgShare.setOnClickListener(v -> { if (bigImageUrl != null && !"".equals(bigImageUrl)) { menuPop(v, bigImageUrl); }// DialogUtils.umShare(ImagePreviewActivity.this,imgShare.getContext(),bigImageUrl,"分享到", loading);/* new Thread(() -> ImageUtil.url2Bitmap(ImagePreviewActivity.this, bigImageUrl, new ImageUtil.GetCallBackInterface() { @Override public void onSuccess(Bitmap bitmap) { //点击分享 if (bitmap != null) { runOnUiThread(() -> DialogUtils.shareWeChatDialog(ImagePreviewActivity.this, bitmap, "分享到").show()); } } @Override public void onFail(String s) { } })).start();*/ }); } private void menuPop(View v, String bigImageUrl) { if (isSeeCode) { showSeeCodeDialog(v); return; } new AlertView("操作", null, "取消", null, new String[]{"转发", "保存"}, v.getContext(), AlertView.Style.ActionSheet, new OnItemClickListener() { @Override public void onItemClick(Object o, int position) { if (position == -1) return; if (position == 0) { //转发 if (currentItem == -1) return; EventBusUtils.forwordImgMessage(currentItem); onBackPressed(); } else { if (bigImageUrl.contains("http")) { ImageUtil.downLoadImg(ImagePreviewActivity.this, bigImageUrl); } else { try { FileInputStream fis = new FileInputStream(bigImageUrl); Bitmap bitmap = BitmapFactory.decodeStream(fis); boolean succ = ImageUtil.saveImageToGallery(ImagePreviewActivity.this, bitmap); String tip = ""; if (succ) { tip = "已保存到相册"; } else { tip = "保存失败"; } ToastUtil.toastShortMessage(tip); } catch (FileNotFoundException e) { e.printStackTrace(); } } } } }).setCancelable(true).show(); } private void showSeeCodeDialog(View v) { new AlertView("操作", null, "取消", null, new String[]{"识别二维码", "保存"}, v.getContext(), AlertView.Style.ActionSheet, new OnItemClickListener() { @Override public void onItemClick(Object o, int position) { if (position == -1) return; if (position == 0) { // 识别二维码 Glide.with(v.getContext()).asBitmap().load(bigImageUrl) .into(new SimpleTarget() { @Override public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { CodeUtils.analyzeBitmap(resource, new CodeUtils.AnalyzeCallback() { @Override public void onAnalyzeSuccess(Bitmap mBitmap, String result) { WebActivity.Companion.start(v.getContext(),result,""); } @Override public void onAnalyzeFailed() { ToastUtils.showShortToast(v.getContext(), "未识别到二维码"); } }); } }); } else { if (bigImageUrl.contains("http")) { ImageUtil.downLoadImg(ImagePreviewActivity.this, bigImageUrl); } else { try { FileInputStream fis = new FileInputStream(bigImageUrl); Bitmap bitmap = BitmapFactory.decodeStream(fis); boolean succ = ImageUtil.saveImageToGallery(ImagePreviewActivity.this, bitmap); String tip = ""; if (succ) { tip = "已保存到相册"; } else { tip = "保存失败"; } ToastUtil.toastShortMessage(tip); } catch (FileNotFoundException e) { e.printStackTrace(); } } } } }).setCancelable(true).show(); } @Override public void onBackPressed() { finishActivityAnim(); } /** * 绘制前开始动画 */ @Override public boolean onPreDraw() { rootView.getViewTreeObserver().removeOnPreDrawListener(this); final View view = imagePreviewAdapter.getPrimaryItem(); final ImageView imageView = imagePreviewAdapter.getPrimaryImageView(); computeImageWidthAndHeight(imageView); final ImageInfo imageData = imageInfo.get(currentItem); final float vx = imageData.imageViewWidth * 1.0f / imageWidth; final float vy = imageData.imageViewHeight * 1.0f / imageHeight; ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1.0f); valueAnimator.addUpdateListener(animation -> { long duration = animation.getDuration(); long playTime = animation.getCurrentPlayTime(); float fraction = duration > 0 ? (float) playTime / duration : 1f; if (fraction > 1) { fraction = 1; } view.setTranslationX(evaluateInt(fraction, imageData.imageViewX + imageData.imageViewWidth / 2 - imageView.getWidth() / 2, 0)); view.setTranslationY(evaluateInt(fraction, imageData.imageViewY + imageData.imageViewHeight / 2 - imageView.getHeight() / 2, 0)); view.setScaleX(evaluateFloat(fraction, vx, 1)); view.setScaleY(evaluateFloat(fraction, vy, 1)); view.setAlpha(fraction); rootView.setBackgroundColor(evaluateArgb(fraction, Color.TRANSPARENT, Color.BLACK)); }); addIntoListener(valueAnimator); valueAnimator.setDuration(ANIMATE_DURATION); valueAnimator.start(); return true; } @Override protected void onResume() { super.onResume(); MobclickAgent.onPageStart(this.getClass().getSimpleName()); MobclickAgent.onResume(this); if (loading.isShowing()) { loading.dismiss(); } } @Override protected void onPause() { super.onPause(); MobclickAgent.onPageEnd(this.getClass().getSimpleName()); MobclickAgent.onPause(this); } public void longClick(View v) { if (!isShowShare) return;// if (bigImageUrl != null && !"".equals(bigImageUrl)) { menuPop(v, bigImageUrl); } } /** * activity的退场动画 */ public void finishActivityAnim() { if (!isUseFinishAnimator) { finish(); overridePendingTransition(0, 0); } else { final View view = imagePreviewAdapter.getPrimaryItem(); final ImageView imageView = imagePreviewAdapter.getPrimaryImageView(); computeImageWidthAndHeight(imageView); final ImageInfo imageData = imageInfo.get(currentItem); final float vx = imageData.imageViewWidth * 1.0f / imageWidth; final float vy = imageData.imageViewHeight * 1.0f / imageHeight; final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1.0f); valueAnimator.addUpdateListener(animation -> { long duration = animation.getDuration(); long playTime = animation.getCurrentPlayTime(); float fraction = duration > 0 ? (float) playTime / duration : 1f; if (fraction > 1) { fraction = 1; } view.setTranslationX(evaluateInt(fraction, 0, imageData.imageViewX + imageData.imageViewWidth / 2 - imageView.getWidth() / 2)); view.setTranslationY(evaluateInt(fraction, 0, imageData.imageViewY + imageData.imageViewHeight / 2 - imageView.getHeight() / 2)); view.setScaleX(evaluateFloat(fraction, 1, vx)); view.setScaleY(evaluateFloat(fraction, 1, vy)); view.setAlpha(1 - fraction); rootView.setBackgroundColor(evaluateArgb(fraction, Color.BLACK, Color.TRANSPARENT)); }); addOutListener(valueAnimator); valueAnimator.setDuration(ANIMATE_DURATION); valueAnimator.start(); } } /** * 计算图片的宽高 */ private void computeImageWidthAndHeight(ImageView imageView) { // 获取真实大小 Drawable drawable = imageView.getDrawable(); int intrinsicHeight = drawable.getIntrinsicHeight(); int intrinsicWidth = drawable.getIntrinsicWidth(); // 计算出与屏幕的比例,用于比较以宽的比例为准还是高的比例为准,因为很多时候不是高度没充满,就是宽度没充满 float h = screenHeight * 1.0f / intrinsicHeight; float w = screenWidth * 1.0f / intrinsicWidth; if (h > w) h = w; else w = h; // 得出当宽高至少有一个充满的时候图片对应的宽高 imageHeight = (int) (intrinsicHeight * h); imageWidth = (int) (intrinsicWidth * w); } /** * 进场动画过程监听 */ private void addIntoListener(ValueAnimator valueAnimator) { valueAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { rootView.setBackgroundColor(0x0); } @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); } /** * 退场动画过程监听 */ private void addOutListener(ValueAnimator valueAnimator) { valueAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { rootView.setBackgroundColor(0x0); } @Override public void onAnimationEnd(Animator animation) { finish(); overridePendingTransition(0, 0); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); } /** * Integer 估值器 */ public Integer evaluateInt(float fraction, Integer startValue, Integer endValue) { int startInt = startValue; return (int) (startInt + fraction * (endValue - startInt)); } /** * Float 估值器 */ public Float evaluateFloat(float fraction, Number startValue, Number endValue) { float startFloat = startValue.floatValue(); return startFloat + fraction * (endValue.floatValue() - startFloat); } /** * Argb 估值器 */ public int evaluateArgb(float fraction, int startValue, int endValue) { int startA = (startValue >> 24) & 0xff; int startR = (startValue >> 16) & 0xff; int startG = (startValue >> 8) & 0xff; int startB = startValue & 0xff; int endA = (endValue >> 24) & 0xff; int endR = (endValue >> 16) & 0xff; int endG = (endValue >> 8) & 0xff; int endB = endValue & 0xff; return (startA + (int) (fraction * (endA - startA))) << 24 | (startR + (int) (fraction * (endR - startR))) << 16 | (startG + (int) (fraction * (endG - startG))) << 8 | (startB + (int) (fraction * (endB - startB))); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); UMShareAPI.get(this).onActivityResult(requestCode, resultCode, data); }}
- 预览的xml文件activity_preview.xml
<?xml version="1.0" encoding="utf-8"?>
- 用到了一个自定义的HackyViewPager
import android.content.Context;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.MotionEvent;/** 修复图片在ViewPager控件中缩放报错的BUG */public class HackyViewPager extends ViewPager { public HackyViewPager(Context context) { super(context); } public HackyViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent ev) { try { return super.onTouchEvent(ev); } catch (IllegalArgumentException ex) { ex.printStackTrace(); } return false; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { try { return super.onInterceptTouchEvent(ev); } catch (IllegalArgumentException ex) { ex.printStackTrace(); } return false; }}
参考链接
- Android 实现WebView点击图片查看大图列表及图片保存
- webview 获取html中所有的图片资源并给图片添加点击事件
- android 获取webview中所有的图片
- Android-通过WebView获取html内容
更多相关文章
- Android中ConvenientBanner的使用
- Android(安卓)学习笔记(十五):Activity-GalleryView
- 6.22 android计算字符高度宽度,红蓝3D图片的制作原理及NDK生成实
- 学习笔记-android imageSwitcher使用
- 图片加载和处理的又一个神器 Fresco 的使用摘要记录
- android 拍照图片旋转问题
- Android(安卓)实现图片圆角
- Android简单模糊背景和圆形ImageView
- Android调用相机拍照获取原始照片