本篇博客主要记录一下如何实现TextView中图文混排时,里面的图片点击功能以及图片大小缩放功能。(根据手势缩放大小)
效果图如下:
思路步骤:
1、实现TextView的图文混排。(不会的话,参考之前的博文:https://blog.csdn.net/lpcrazyboy/article/details/80390903)
2、如何实现TextView中的图片的点击事件的监听?
解决方法:
tvQuestionTitle.setText(Html.fromHtml(sText2, imageGetterFromLocal, null));
上面的解析HTML标签的字符串的方法。Html.fromHtml()的最后一个参数是:tagHandler对象。自定义一个tagHandler类,然后传入参数即可。如下所示:
MyTagHandler tagHandler = new MyTagHandler(this);
//设置这个图片才能点击
tvQuestionTitle.setMovementMethod(LinkMovementMethod.getInstance());
tvQuestionTitle.setText(strTitle);
try {
tvQuestionTitle.setText(Html.fromHtml(formatTextUrlString(strTitle)
, imageGetterFromLocal, tagHandler));
} catch (Exception e){
}
MyTagHandler.java的代码如下:
package com.deepreality.textviewshowlocalimage;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupWindow;
import com.davemorrissey.labs.subscaleview.ImageSource;
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
import org.xml.sax.XMLReader;
import java.util.Locale;
public class MyTagHandler implements Html.TagHandler {
private Context mContext;
private PopupWindow popupWindow;
//需要放大的图片
private SubsamplingScaleImageView tecent_chat_image;
public MyTagHandler() {
super();
}
public MyTagHandler(Context context) {
mContext = context;
/*mContext = context.getApplicationContext();
View popView = LayoutInflater.from(context).inflate(R.layout.image_scale, null);
tecent_chat_image = (SubsamplingScaleImageView) popView.findViewById(R.id.image_scale_image);
popView.findViewById(R.id.image_scale_rll).setOnClickListener(onClickListener);
popupWindow = new PopupWindow(popView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
popupWindow.setFocusable(true);
popupWindow.setOutsideTouchable(true);// 设置允许在外点击消失
ColorDrawable dw = new ColorDrawable(0x50000000);
popupWindow.setBackgroundDrawable(dw);*/
}
public View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if(popupWindow!=null && popupWindow.isShowing()){
popupWindow.dismiss();
}
}
};
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
// 处理标签<img>
if (tag.toLowerCase(Locale.getDefault()).equals("img")) {
// 获取长度
int len = output.length();
// 获取图片地址
ImageSpan[] images = output.getSpans(len - 1, len, ImageSpan.class);
String imgURL = images[0].getSource();
// 使图片可点击并监听点击事件
output.setSpan(new ClickableImage(mContext, imgURL), len - 1, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
private class ClickableImage extends ClickableSpan {
private String url;
private Context context;
public ClickableImage(Context context, String url) {
this.context = context;
this.url = url;
}
@Override
public void onClick(View widget) {
Log.e("点击图片的路径地址", url);
Bundle bundle = new Bundle();
bundle.putString("filePath", url);
Intent intent = new Intent(context, ImageZoomActivity.class);
intent.putExtras(bundle);
context.startActivity(intent);
/*// 进行图片点击之后的处理
Log.e("ytp", "点击了图片:url:" + url);
popupWindow.showAtLocation(widget, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
//Bitmap bitmap = BitmapFactory.decodeFile(url);
//tecent_chat_image.setImageBitmap(bitmap);
tecent_chat_image.setImage(ImageSource.uri(url));
tecent_chat_image.setBackground(mContext.getResources().getDrawable(R.color.colorAccent));*/
}
}
}
3、现在已经能获取到相应的图片URL地址,那么我们应该怎么实现图片的缩放功能呢?
方法:(1)先把图片显示在另一个Activity的布局文件中。
ImageZoomActivity.java的代码如下:
package com.deepreality.textviewshowlocalimage;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
public class ImageZoomActivity extends AppCompatActivity{
public static ImageZoomActivity imageZoomActivity = null;
private ImageView ivZooming, ivClose;
private Bitmap mBitmap;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//隐藏标题栏和任务栏
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_imagezoom);
imageZoomActivity = this;
//获取设备的宽高
getActivityWidthAndHeight(getWindowManager());
ivZooming = findViewById(R.id.imgzoom_imgZooming);
ivClose = findViewById(R.id.imagezoom_imgClose);
ivClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
final String filePath = bundle.getString("filePath");
mBitmap = BitmapFactory.decodeFile(filePath);
ivZooming.setImageBitmap(mBitmap);
ivZooming.setScaleType(ImageView.ScaleType.FIT_CENTER);
ivZooming.setOnTouchListener(new MyImageZoomOnTouchListener(ImageZoomActivity.this, ivZooming, mBitmap));
}
public void imageZoomSceneClose() {
imageZoomActivity.finish();
}
//获取设备的宽度和高度
public void getActivityWidthAndHeight(WindowManager windowManager){
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
DeviceBaseInfo.DEVICE_WIDTH = displayMetrics.widthPixels;
Log.e("width", String.valueOf(DeviceBaseInfo.DEVICE_WIDTH));
DeviceBaseInfo.DEVICE_HEIGHT = displayMetrics.heightPixels;
Log.e("height", String.valueOf(DeviceBaseInfo.DEVICE_HEIGHT));
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
其中,图片根据手势缩放的话,那么图片肯定是监听OnTouchListener的,接下来自定义一个MyImageZoomOnTouchListener类来实现OnTouchListener接口。代码如下:
MyImageZoomOnTouchListener.java的代码如下:
package com.deepreality.textviewshowlocalimage;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
public class MyImageZoomOnTouchListener implements View.OnTouchListener {
private ImageView ivZooming;
private Bitmap mBitmap;
private Context mContext;
// 縮放控制
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
// 不同状态的表示:
//空模式
private static final int MODE_NONE = 0;
//拖动模式
private static final int MODE_DRAG = 1;
//缩放模式
private static final int MODE_ZOOM = 2;
//当前模式为:空模式
private int currentMode = MODE_NONE;
// 定义第一个按下的点,两只接触点的重点,以及出事的两指按下的距离:
//记录开始时候的坐标位置
private PointF startPoint = new PointF();
private PointF midPoint = new PointF();
private float oriDis = 1f;
//拖放的最小间距
private static float MINI_DISTANCE = 50f;
//最大放大比例
private static float MAX_SCALE = 20f;
//最小缩放比例
private static float MINI_SCALE = 1f;
public MyImageZoomOnTouchListener(Context mContext, ImageView ivZooming, Bitmap mBitmap) {
this.mContext = mContext;
this.ivZooming = ivZooming;
this.mBitmap = mBitmap;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
// 单指
case MotionEvent.ACTION_DOWN:
matrix.set(view.getImageMatrix());
savedMatrix.set(matrix);
startPoint.set(event.getX(), event.getY());
currentMode = MODE_DRAG;
break;
// 双指
case MotionEvent.ACTION_POINTER_DOWN:
oriDis = distance(event);
if (oriDis > MINI_DISTANCE) {
savedMatrix.set(matrix);
midPoint = middle(event);
currentMode = MODE_ZOOM;
}
break;
// 手指放开
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (isOnClick(event.getX(), startPoint.x) && isOnClick(event.getY(), startPoint.y)) {
ImageZoomActivity.imageZoomActivity.imageZoomSceneClose();
} else {
Log.e("Action_up", "两个位置不一致!");
}
currentMode = MODE_NONE;
break;
// 单指滑动事件
case MotionEvent.ACTION_MOVE:
if (currentMode == MODE_DRAG) {
// 是一个手指拖动
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - startPoint.x, event.getY() - startPoint.y);
} else if (currentMode == MODE_ZOOM) {
// 两个手指滑动
float newDist = distance(event);
if (newDist > MINI_DISTANCE) {
matrix.set(savedMatrix);
float scale = newDist / oriDis;
matrix.postScale(scale, scale, midPoint.x, midPoint.y);
}
}
break;
}
// 设置ImageView的Matrix
view.setImageMatrix(matrix);
//检查当前缩放比例并做出相应处理
checkView();
return true;
}
// 计算两个触摸点之间的距离
private float distance(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return Float.valueOf(String.valueOf(Math.sqrt(x * x + y * y))) ;
}
// 计算两个触摸点的中点
private PointF middle(MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
return new PointF(x / 2, y / 2);
}
//判断是否为点击事件(按下和抬起的坐标是否一致,在误差范围内)
private boolean isOnClick(float pointOne, float pointTwo) {
//误差范围为10f
float maxError = 10f;
float result = pointOne - pointTwo;
if (result >= 0 && result <= maxError) {
return true;
} else if (result <= 0 && result >= maxError) {
return true;
}
return false;
}
//检查当前缩放比例并做出相应处理
private void checkView() {
float[] p = new float[9];
matrix.getValues(p);
float p1 = p[0];
if (currentMode == MODE_ZOOM) {
if (p1 < MINI_SCALE) {
matrix.setScale(MINI_SCALE, MINI_SCALE);
//最小缩放比例时,居中显示
this.setCenter(true, true);
}
if (p1 > MAX_SCALE) {
matrix.set(savedMatrix);
}
}
}
//居中显示
private void setCenter(boolean horizontal, boolean vertical) {
Matrix mMatrix = new Matrix();
mMatrix.set(matrix);
RectF mRectF = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
mMatrix.mapRect(mRectF);
float height = mRectF.height();
float width = mRectF.width();
float deltaX = 0, deltaY = 0;
if (vertical) {
// 图片小于屏幕大小,则居中显示。大于屏幕,上方留空则往上移,下方留空则往下移
int screenHeight = DeviceBaseInfo.DEVICE_HEIGHT;
if (height < screenHeight) {
deltaY = (screenHeight - height) / 2 - mRectF.top;
} else if (mRectF.top > 0) {
deltaY = -mRectF.top;
} else if (mRectF.bottom < screenHeight) {
deltaY = ivZooming.getHeight() - mRectF.bottom;
}
}
if (horizontal) {
int screenWidth = DeviceBaseInfo.DEVICE_WIDTH;
if (width < screenWidth) {
deltaX = (screenWidth - width) / 2 - mRectF.left;
} else if (mRectF.left > 0) {
deltaX = -mRectF.left;
} else if (mRectF.right < screenWidth) {
deltaX = screenWidth - mRectF.right;
}
}
matrix.postTranslate(deltaX, deltaY);
}
}
至此,功能完成。
如果有小伙伴哪里不太明白的,可以看一下完整Demo:https://download.csdn.net/download/lpcrazyboy/10505244