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