Android开发中TextView中图片点击以及图片缩放功能实现(总结)

本篇博客主要记录一下如何实现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

猜你喜欢

转载自blog.csdn.net/lpcrazyboy/article/details/80841459