我做了一个益智游戏,一切顺利,直到我使用API 28或更高版本,实际上只有一部装有Android 9的手机,并且需要将其用于项目演示。如果有人可以帮助我,我会很高兴。 这些是我用于拼图的Java文件
拼图活动
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.bermeoapp.R;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import static java.lang.Math.abs;
public class PuzzleActivity extends AppCompatActivity {
ArrayList<PuzzlePiece> pieces;
String mCurrentPhotoPath;
String mCurrentPhotoUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_puzzle);
final RelativeLayout layout = findViewById(R.id.layout);
final ImageView imageView = findViewById(R.id.imageView);
Intent intent = getIntent();
final String assetName = intent.getStringExtra("assetName");
mCurrentPhotoPath = intent.getStringExtra("mCurrentPhotoPath");
mCurrentPhotoUri = intent.getStringExtra("mCurrentPhotoUri");
// run image related code after the view was laid out
// to have all dimensions calculated
imageView.post(new Runnable() {
@Override
public void run() {
if (assetName != null) {
setPicFromAsset(assetName, imageView);
} else if (mCurrentPhotoPath != null) {
setPicFromPath(mCurrentPhotoPath, imageView);
} else if (mCurrentPhotoUri != null) {
imageView.setImageURI(Uri.parse(mCurrentPhotoUri));
}
pieces = splitImage();
TouchListener touchListener = new TouchListener(PuzzleActivity.this);
// shuffle pieces order
Collections.shuffle(pieces);
for (PuzzlePiece piece : pieces) {
piece.setOnTouchListener(touchListener);
layout.addView(piece);
// randomize position, on the bottom of the screen
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) piece.getLayoutParams();
lParams.leftMargin = new Random().nextInt(layout.getWidth() - piece.pieceWidth);
lParams.topMargin = layout.getHeight() - piece.pieceHeight;
piece.setLayoutParams(lParams);
}
}
});
}
private void setPicFromAsset(String assetName, ImageView imageView) {
// Get the dimensions of the View
int targetW = imageView.getWidth();
int targetH = imageView.getHeight();
AssetManager am = getAssets();
try {
InputStream is = am.open("img/" + assetName);
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, new Rect(-1, -1, -1, -1), bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
is.reset();
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeStream(is, new Rect(-1, -1, -1, -1), bmOptions);
imageView.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}
}
private ArrayList<PuzzlePiece> splitImage() {
int piecesNumber = 12;
int rows = 4;
int cols = 3;
ImageView imageView = findViewById(R.id.imageView);
ArrayList<PuzzlePiece> pieces = new ArrayList<>(piecesNumber);
// Get the scaled bitmap of the source image
BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
Bitmap bitmap = drawable.getBitmap();
int[] dimensions = getBitmapPositionInsideImageView(imageView);
int scaledBitmapLeft = dimensions[0];
int scaledBitmapTop = dimensions[1];
int scaledBitmapWidth = dimensions[2];
int scaledBitmapHeight = dimensions[3];
int croppedImageWidth = scaledBitmapWidth - 2 * abs(scaledBitmapLeft);
int croppedImageHeight = scaledBitmapHeight - 2 * abs(scaledBitmapTop);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, scaledBitmapWidth, scaledBitmapHeight, true);
Bitmap croppedBitmap = Bitmap.createBitmap(scaledBitmap, abs(scaledBitmapLeft), abs(scaledBitmapTop), croppedImageWidth, croppedImageHeight);
// Calculate the with and height of the pieces
int pieceWidth = croppedImageWidth/cols;
int pieceHeight = croppedImageHeight/rows;
// Create each bitmap piece and add it to the resulting array
int yCoord = 0;
for (int row = 0; row < rows; row++) {
int xCoord = 0;
for (int col = 0; col < cols; col++) {
// calculate offset for each piece
int offsetX = 0;
int offsetY = 0;
if (col > 0) {
offsetX = pieceWidth / 3;
}
if (row > 0) {
offsetY = pieceHeight / 3;
}
// apply the offset to each piece
Bitmap pieceBitmap = Bitmap.createBitmap(croppedBitmap, xCoord - offsetX, yCoord - offsetY, pieceWidth + offsetX, pieceHeight + offsetY);
PuzzlePiece piece = new PuzzlePiece(getApplicationContext());
piece.setImageBitmap(pieceBitmap);
piece.xCoord = xCoord - offsetX + imageView.getLeft();
piece.yCoord = yCoord - offsetY + imageView.getTop();
piece.pieceWidth = pieceWidth + offsetX;
piece.pieceHeight = pieceHeight + offsetY;
// this bitmap will hold our final puzzle piece image
Bitmap puzzlePiece = Bitmap.createBitmap(pieceWidth + offsetX, pieceHeight + offsetY, Bitmap.Config.ARGB_8888);
// draw path
int bumpSize = pieceHeight / 4;
Canvas canvas = new Canvas(puzzlePiece);
Path path = new Path();
path.moveTo(offsetX, offsetY);
if (row == 0) {
// top side piece
path.lineTo(pieceBitmap.getWidth(), offsetY);
} else {
// top bump
path.lineTo(offsetX + (pieceBitmap.getWidth() - offsetX) / 3, offsetY);
path.cubicTo(offsetX + (pieceBitmap.getWidth() - offsetX) / 6, offsetY - bumpSize, offsetX + (pieceBitmap.getWidth() - offsetX) / 6 * 5, offsetY - bumpSize, offsetX + (pieceBitmap.getWidth() - offsetX) / 3 * 2, offsetY);
path.lineTo(pieceBitmap.getWidth(), offsetY);
}
if (col == cols - 1) {
// right side piece
path.lineTo(pieceBitmap.getWidth(), pieceBitmap.getHeight());
} else {
// right bump
path.lineTo(pieceBitmap.getWidth(), offsetY + (pieceBitmap.getHeight() - offsetY) / 3);
path.cubicTo(pieceBitmap.getWidth() - bumpSize,offsetY + (pieceBitmap.getHeight() - offsetY) / 6, pieceBitmap.getWidth() - bumpSize, offsetY + (pieceBitmap.getHeight() - offsetY) / 6 * 5, pieceBitmap.getWidth(), offsetY + (pieceBitmap.getHeight() - offsetY) / 3 * 2);
path.lineTo(pieceBitmap.getWidth(), pieceBitmap.getHeight());
}
if (row == rows - 1) {
// bottom side piece
path.lineTo(offsetX, pieceBitmap.getHeight());
} else {
// bottom bump
path.lineTo(offsetX + (pieceBitmap.getWidth() - offsetX) / 3 * 2, pieceBitmap.getHeight());
path.cubicTo(offsetX + (pieceBitmap.getWidth() - offsetX) / 6 * 5,pieceBitmap.getHeight() - bumpSize, offsetX + (pieceBitmap.getWidth() - offsetX) / 6, pieceBitmap.getHeight() - bumpSize, offsetX + (pieceBitmap.getWidth() - offsetX) / 3, pieceBitmap.getHeight());
path.lineTo(offsetX, pieceBitmap.getHeight());
}
if (col == 0) {
// left side piece
path.close();
} else {
// left bump
path.lineTo(offsetX, offsetY + (pieceBitmap.getHeight() - offsetY) / 3 * 2);
path.cubicTo(offsetX - bumpSize, offsetY + (pieceBitmap.getHeight() - offsetY) / 6 * 5, offsetX - bumpSize, offsetY + (pieceBitmap.getHeight() - offsetY) / 6, offsetX, offsetY + (pieceBitmap.getHeight() - offsetY) / 3);
path.close();
}
// mask the piece
Paint paint = new Paint();
paint.setColor(0XFF000000);
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(pieceBitmap, 0, 0, paint);
// draw a white border
Paint border = new Paint();
border.setColor(0X80FFFFFF);
border.setStyle(Paint.Style.STROKE);
border.setStrokeWidth(8.0f);
canvas.drawPath(path, border);
// draw a black border
border = new Paint();
border.setColor(0X80000000);
border.setStyle(Paint.Style.STROKE);
border.setStrokeWidth(3.0f);
canvas.drawPath(path, border);
// set the resulting bitmap to the piece
piece.setImageBitmap(puzzlePiece);
pieces.add(piece);
xCoord += pieceWidth;
}
yCoord += pieceHeight;
}
return pieces;
}
private int[] getBitmapPositionInsideImageView(ImageView imageView) {
int[] ret = new int[4];
if (imageView == null || imageView.getDrawable() == null)
return ret;
// Get image dimensions
// Get image matrix values and place them in an array
float[] f = new float[9];
imageView.getImageMatrix().getValues(f);
// Extract the scale values using the constants (if aspect ratio maintained, scaleX == scaleY)
final float scaleX = f[Matrix.MSCALE_X];
final float scaleY = f[Matrix.MSCALE_Y];
// Get the drawable (could also get the bitmap behind the drawable and getWidth/getHeight)
final Drawable d = imageView.getDrawable();
final int origW = d.getIntrinsicWidth();
final int origH = d.getIntrinsicHeight();
// Calculate the actual dimensions
final int actW = Math.round(origW * scaleX);
final int actH = Math.round(origH * scaleY);
ret[2] = actW;
ret[3] = actH;
// Get image position
// We assume that the image is centered into ImageView
int imgViewW = imageView.getWidth();
int imgViewH = imageView.getHeight();
int top = (int) (imgViewH - actH)/2;
int left = (int) (imgViewW - actW)/2;
ret[0] = left;
ret[1] = top;
return ret;
}
public void checkGameOver() {
if (isGameOver()) {
finish();
}
}
private boolean isGameOver() {
for (PuzzlePiece piece : pieces) {
if (piece.canMove) {
return false;
}
}
return true;
}
private void setPicFromPath(String mCurrentPhotoPath, ImageView imageView) {
// Get the dimensions of the View
int targetW = imageView.getWidth();
int targetH = imageView.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
Bitmap rotatedBitmap = bitmap;
// rotate bitmap if needed
try {
ExifInterface ei = new ExifInterface(mCurrentPhotoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotatedBitmap = rotateImage(bitmap, 90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotatedBitmap = rotateImage(bitmap, 180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotatedBitmap = rotateImage(bitmap, 270);
break;
}
} catch (IOException e) {
Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}
imageView.setImageBitmap(rotatedBitmap);
}
public static Bitmap rotateImage(Bitmap source, float angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
matrix, true);
}
}
拼图块
import android.content.Context;
import androidx.appcompat.widget.AppCompatImageView;
public class PuzzlePiece extends AppCompatImageView {
public int xCoord;
public int yCoord;
public int pieceWidth;
public int pieceHeight;
public boolean canMove = true;
public PuzzlePiece(Context context) {
super(context);
}
}
触摸监听器
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
import static java.lang.StrictMath.abs;
public class TouchListener implements View.OnTouchListener {
private float xDelta;
private float yDelta;
private PuzzleActivity activity;
public TouchListener(PuzzleActivity activity) {
this.activity = activity;
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
float x = motionEvent.getRawX();
float y = motionEvent.getRawY();
final double tolerance = sqrt(pow(view.getWidth(), 2) + pow(view.getHeight(), 2)) / 10;
PuzzlePiece piece = (PuzzlePiece) view;
if (!piece.canMove) {
return true;
}
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
xDelta = x - lParams.leftMargin;
yDelta = y - lParams.topMargin;
piece.bringToFront();
break;
case MotionEvent.ACTION_MOVE:
lParams.leftMargin = (int) (x - xDelta);
lParams.topMargin = (int) (y - yDelta);
view.setLayoutParams(lParams);
break;
case MotionEvent.ACTION_UP:
int xDiff = abs(piece.xCoord - lParams.leftMargin);
int yDiff = abs(piece.yCoord - lParams.topMargin);
if (xDiff <= tolerance && yDiff <= tolerance) {
lParams.leftMargin = piece.xCoord;
lParams.topMargin = piece.yCoord;
piece.setLayoutParams(lParams);
piece.canMove = false;
sendViewToBack(piece);
activity.checkGameOver();
}
break;
}
return true;
}
public void sendViewToBack(final View child) {
final ViewGroup parent = (ViewGroup)child.getParent();
if (null != parent) {
parent.removeView(child);
parent.addView(child, 0);
}
}
}
如果有人帮助我,那就太好了。