手记

Android 自定义拼接图片,点击小图位置时,绘制在上层


类似的需求是:将几张图片,拼在一个View中进行显示,点击某张图片,这张图完整显示在最上层。本文将五张图以图中的方位进行拼接,并在点击时判断触摸点在哪一个图形的矩形范围,最后在绘制时,配合paint.setXfermode,将点击的图绘制在上层。

package com.stone.guaguaka.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * author : stone
 * email  : aa86799@163.com
 * time   : 16/5/3 20 27
 */
public class OverlayImageView extends View {

    private List<Bitmap> mBitmaps;
    private List<Point> mPoints;
    private int mWidth;
    private int mHeight;
    private int mPosition;

    public OverlayImageView(Context context) {
        this(context, null);
    }

    public OverlayImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public OverlayImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        this.mBitmaps = new ArrayList<>();
        this.mPoints = new ArrayList<>();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mBitmaps.isEmpty()) {
            return;
        }
        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (mBitmaps.isEmpty()) {
            return;
        }
        Bitmap outBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.RGB_565);
        Canvas outCanvas = new Canvas(outBitmap);
        outCanvas.drawColor(Color.parseColor("#abc777"));

        Point point;
        for (int i = 0, len = mBitmaps.size(); i < len; ++i) {

            point = mPoints.get(i);

            if (mPosition != i) {
                outCanvas.drawBitmap(mBitmaps.get(i), point.x, point.y, null);
            }
        }

        /*
            如果不使用paint,那么默认情况下,后绘制的在上层
            这里有意将postion上的放在前面绘制,配合paint.setXfermode 绘制层次

            这里要注意一点的就是:
            如果paint 被new Canvas(bitmap)操作,这个canvas默认就是一个图层
            如果paint 被外部的canvas操作,需要给它指定图层,指定后设置的xfermode才有需要的效果,否则效果达不到期望,让人难以琢磨
         */

        Paint paint = new Paint();
        int saveLayerCount = canvas.saveLayer(0, 0, mWidth, mHeight, paint, Canvas.ALL_SAVE_FLAG);//存为新图层
        canvas.drawBitmap(mBitmaps.get(mPosition), mPoints.get(mPosition).x, mPoints.get(mPosition).y, paint); //dst
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
        canvas.drawBitmap(outBitmap, 0, 0, paint); //src
        paint.setXfermode(null);
        canvas.restoreToCount(saveLayerCount); //恢复保存的图层

    }

    public void setImages(int... resId) {
        InputStream is;
        Bitmap bitmap;
        for (int i = 0; i < resId.length; i++) {
            is = getResources().openRawResource(resId[i]);
            bitmap = BitmapFactory.decodeStream(is);
            mBitmaps.add(bitmap);
        }

        mWidth = mBitmaps.get(0).getWidth() * 2;
        mHeight = mBitmaps.get(0).getHeight() * 2;

        for (int i = 0, len = mBitmaps.size(); i < len; ++i) {
            int x, y;
            if (i == 4) {
                x = mWidth / 4;
                y = mHeight / 4;
            } else {
                if (i % 2 == 0) {
                    x = 0;
                } else {
                    x = mWidth / 2;
                }

                if (i <= 1) {
                    y = 0;
                } else {
                    y = mHeight / 2;
                }
            }
            mPoints.add(new Point(x, y));

        }

        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                int x = (int) event.getX();
                int y = (int) event.getY();
                if (mPosition != getTouchPosition(x, y)) {
                    mPosition = getTouchPosition(x, y);
                }
                invalidate();
                break;

            case MotionEvent.ACTION_MOVE:
                break;

            case MotionEvent.ACTION_UP:
                break;

        }
        return super.onTouchEvent(event);
    }

    private int getTouchPosition(int x, int y) {
        int position = 0;
        Point p;
        for (int i = 0, len = mPoints.size(); i < len; i++) {
            p = mPoints.get(i);
            if (isCollision(x, y, p.x, p.y, mWidth / 2, mHeight / 2)) {
                position = i;
            }
        }
        return position;
    }

    /**
     * @param x1 点
     * @param y1 点
     * @param x2 矩形view x
     * @param y2 矩形view y
     * @param w  矩形view 宽
     * @param h  矩形view 高
     * @return
     */
    private boolean isCollision(int x1, int y1, int x2, int y2, int w, int h) {
        if (x1 >= x2 && x1 <= x2 + w && y1 >= y2 && y1 <= y2 + h) {
            return true;
        }
        return false;
    }
}
9人推荐
随时随地看视频
慕课网APP