Android实例——拼图游戏

news2024/11/23 21:32:19

拼图游戏

  • 项目简介
  • 权限
  • adapter
    • PictureListAdapter
    • PuzzleAdapter
  • bean
    • ItemBean
  • Presenter
    • IPuzzlePresenter
    • PuzzlePresenterImpl
  • ui
    • IGameCallback
  • utils
    • Constant
    • ImagesUtils
    • ScreenUtils
  • View
    • MainActivity
    • PuzzleActivity
  • 布局
    • activity_main.xml
    • activity_puzzle.xml

项目简介

选择图片,生成拼图,通过移动拼图还原图片通关游戏,选择界面如下

在这里插入图片描述

游戏界面如下

在这里插入图片描述

采用MVP架构,项目结构如下

在这里插入图片描述

权限

需要读取相册中的图片

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

adapter

PictureListAdapter

public class PictureListAdapter extends BaseAdapter {

    private Context mContext;
    private List<Bitmap> mBitmapList;

    public PictureListAdapter(Context context, List<Bitmap> bitmapList) {
        mContext = context;
        mBitmapList = bitmapList;
    }

    @Override
    public int getCount() {
        return mBitmapList.size();
    }

    @Override
    public Object getItem(int position) {
        return mBitmapList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView item = new ImageView(mContext);
        item.setImageBitmap(mBitmapList.get(position));
        return item;
    }
}

PuzzleAdapter

public class PuzzleAdapter extends BaseAdapter {

    private List<ItemBean> mItemBeanList;

    public PuzzleAdapter() {
        mItemBeanList = new ArrayList<>();
    }

    public void setData(List<ItemBean> itemBeanList) {
        mItemBeanList.clear();
        for (ItemBean itemBean : itemBeanList) {
            try {
                mItemBeanList.add((ItemBean) itemBean.clone());
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public int getCount() {
        return mItemBeanList.size();
    }

    @Override
    public Object getItem(int position) {
        return mItemBeanList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView item = new ImageView(parent.getContext());
        /*item.setLayoutParams(new GridView.LayoutParams(GridView.LayoutParams.MATCH_PARENT, GridView.LayoutParams.MATCH_PARENT));
        item.setScaleType(ImageView.ScaleType.FIT_XY);*/
        item.setImageBitmap(mItemBeanList.get(position).getBitmap());
        return item;
    }
}

bean

ItemBean

public class ItemBean implements Cloneable {
    private int mOriID;	//表示拼图原始顺序
    private int mPuzzleID;	//表示拼图打乱后的顺序
    private Bitmap mBitmap;

    public ItemBean() {

    }

    public ItemBean(int oriID, int puzzleID, Bitmap bitmap) {
        mOriID = oriID;
        mPuzzleID = puzzleID;
        mBitmap = bitmap;
    }

    public int getOriID() {
        return mOriID;
    }

    public void setOriID(int oriID) {
        mOriID = oriID;
    }

    public int getPuzzleID() {
        return mPuzzleID;
    }

    public void setPuzzleID(int puzzleID) {
        mPuzzleID = puzzleID;
    }

    public Bitmap getBitmap() {
        return mBitmap;
    }

    public void setBitmap(Bitmap bitmap) {
        mBitmap = bitmap;
    }

    @Override
    public String toString() {
        return "ItemBean{" +
                "mOriID=" + mOriID +
                ", mPuzzleID=" + mPuzzleID +
                ", mBitmap=" + mBitmap +
                '}';
    }

    @NonNull
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Presenter

IPuzzlePresenter

public interface IPuzzlePresenter {

    enum STATE {
        SUCCESS, FAILED_STEP, FAILED_TIME
    }

    void registerGameCallback(IGameCallback gameControl);

    void unRegisterGameCallback();

	//生成拼图数据
    void loadPuzzleData(Context context, Bitmap oriBitmap);
	
	//复位拼图
    void resetGame();

	//交换拼图
    void swapPuzzle(int position);

	//生成新的游戏
    void restartGame();

}

PuzzlePresenterImpl

public class PuzzlePresenterImpl implements IPuzzlePresenter {

    private static final String TAG = "PuzzlePresenterImpl";
    private IGameCallback mCallback;
    private ItemBean mLastBitmap;
    private Bitmap mOriBitmap;
    private List<ItemBean> mPuzzleList;
    private List<ItemBean> mResetList;
    private int mType;

    private Map<Integer, Integer> mCountDownMap;
    private Map<Integer, Integer> mStepCountMap;

    private int mCurrentStep;
    private int mCurrentTime;
    private Timer mTimer;
    private TimerTask mTimerTask;
    
    public PuzzlePresenterImpl(int type) {
        mPuzzleList = new ArrayList<>();
        mResetList = new ArrayList<>();
        mType = type;

        mCountDownMap = new HashMap<>();
        mCountDownMap.put(2, 180);
        mCountDownMap.put(3, 300);
        mCountDownMap.put(4, 600);

        mStepCountMap = new HashMap<>();
        mStepCountMap.put(2, 10);
        mStepCountMap.put(3, 150);
        mStepCountMap.put(4, 500);
    }

    @Override
    public void registerGameCallback(IGameCallback callback) {
        this.mCallback = callback;
    }

    @Override
    public void unRegisterGameCallback() {
        mTimer.cancel();
        /*mPuzzleList.clear();
        mResetList.clear();*/
        this.mCallback = null;
    }

    @Override
    public void loadPuzzleData(Context context, Bitmap oriBitmap) {
        Log.d(TAG, "loadPuzzleData: ");
        initPuzzle(context, oriBitmap);
        startGame();
    }

    private void startGame() {
        shufflePuzzle();
        cloneItemBeanList(mPuzzleList, mResetList);
        initCountDown();
        if (mCallback != null) {
            mCallback.onLoadPuzzleData(mOriBitmap, mPuzzleList);
        }
        startCountDown();
    }

    private void cloneItemBeanList(List<ItemBean> from, List<ItemBean> to) {
        if (to != null && to.size() != 0) {
            to.clear();
        }
        for (ItemBean itemBean : from) {
            try {
                to.add((ItemBean) itemBean.clone());
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
    }

    private void initCountDown() {
        mCurrentTime = mCountDownMap.get(mType);
        mCurrentStep = mStepCountMap.get(mType);
    }

    private void initPuzzle(Context context, Bitmap oriBitmap) {
        mOriBitmap = ImagesUtils.resizeBitmap(oriBitmap, ScreenUtils.getScreenWidthPixels(context), ScreenUtils.getScreenWidthPixels(context));
        int itemWidth = mOriBitmap.getWidth() / mType;
        int itemHeight = mOriBitmap.getHeight() / mType;
        for (int i = 1; i <= mType; i++) {
            for (int j = 1; j <= mType; j++) {
                Bitmap bitmap = Bitmap.createBitmap(
                        mOriBitmap,
                        (j - 1) * itemWidth,
                        (i - 1) * itemHeight,
                        itemWidth,
                        itemHeight);
                mPuzzleList.add(new ItemBean((i - 1) * mType + j, (i - 1) * mType + j, bitmap));
            }
        }
        //取出最后一个图片,当拼图完成时补充
        mLastBitmap = mPuzzleList.remove(mType * mType - 1);
        //将空的图片插入到最后
        mPuzzleList.add(new ItemBean(mType * mType, 0,
                ImagesUtils.createBitmap(
                        mOriBitmap.getWidth() / mType,
                        mOriBitmap.getHeight() / mType,
                        "空白格")));
    }

    private void startCountDown() {
        mTimer = new Timer(true);
        mTimerTask = new TimerTask() {
            @Override
            public void run() {
                Log.d(TAG, "run: Thread = " + Thread.currentThread().getId() + ", mCurrentTime = " + mCurrentTime);
                mCurrentTime--;
                if (mCallback != null) {
                    mCallback.onCountDown(mCurrentTime, mCurrentStep);
                    if (mCurrentTime == 0) {
                        finishGame(STATE.FAILED_TIME);
                    }
                }
            }
        };
        mTimer.schedule(mTimerTask, 0, 1000);
    }

    @Override
    public void resetGame() {
        for (ItemBean itemBean : mPuzzleList) {
            Log.d(TAG, "resetGame: mPuzzleList = " + itemBean);
        }
        for (ItemBean itemBean : mResetList) {
            Log.d(TAG, "resetGame: mResetList = " + itemBean);
        }
        Log.d(TAG, "resetGame: --------------");

        cloneItemBeanList(mResetList, mPuzzleList);
        initCountDown();
        if (mCallback != null) {
            mCallback.onResetGame(mPuzzleList);
        }

        for (ItemBean itemBean : mPuzzleList) {
            Log.d(TAG, "resetGame: mPuzzleList = " + itemBean);
        }
        for (ItemBean itemBean : mResetList) {
            Log.d(TAG, "resetGame: mResetList = " + itemBean);
        }
        Log.d(TAG, "resetGame: --------------");
    }

    @Override
    public void swapPuzzle(int position) {
        if (mCallback != null) {
            mCallback.onSwapPuzzle(isMovable(position), mPuzzleList);
            mCurrentStep--;
            mCallback.onCountDown(mCurrentTime, mCurrentStep);
            if (isSuccess()) {
                finishGame(STATE.SUCCESS);
            } else if (mCurrentStep == 0) {
                finishGame(STATE.FAILED_STEP);
            }
        }
    }

    private void finishGame(STATE state) {
        if (mTimer != null) {
            mTimer.cancel();
            mTimer = null;
            mTimerTask = null;
        }
        mCallback.onFinishGame(state);
    }

    @Override
    public void restartGame() {
        startGame();
    }

    private ItemBean getBlankBitmap() {
        for (ItemBean itemBean : mPuzzleList) {
            if (itemBean.getPuzzleID() == 0) {
                return itemBean;
            }
        }
        return null;
    }

    private boolean isMovable(int position) {
        int blankPosition = getBlankBitmap().getOriID() - 1;
        if ((Math.abs(blankPosition - position) == mType       //判断上下
                || ((blankPosition / mType == position / mType) && Math.abs(blankPosition - position) == 1))) { //判断左右
            swapItem(mPuzzleList.get(position), getBlankBitmap());
            return true;
        }
        return false;
    }

    private void swapItem(ItemBean from, ItemBean blankBitmap) {
        if (from == blankBitmap) {
            return;
        }
        ItemBean temp = new ItemBean();
        temp.setPuzzleID(from.getPuzzleID());
        temp.setBitmap(from.getBitmap());

        from.setPuzzleID(blankBitmap.getPuzzleID());
        from.setBitmap(blankBitmap.getBitmap());

        blankBitmap.setPuzzleID(temp.getPuzzleID());
        blankBitmap.setBitmap(temp.getBitmap());
    }


    private boolean isSuccess() {
        boolean isSuccess = true;
        for (ItemBean bean : mPuzzleList) {
            if (bean.getPuzzleID() != 0 && bean.getOriID() == bean.getPuzzleID()) { //非空白格,两个ID相等
                continue;
            } else if (bean.getPuzzleID() == 0 && bean.getOriID() == mType * mType) { //空白格,源ID等于最后一个
                continue;
            } else {
                isSuccess = false;
            }
        }
        return isSuccess;
    }

    private void shufflePuzzle() {
        for (int i = 0; i < mPuzzleList.size(); i++) {  //打乱顺序
            int index = (int) (Math.random() * mPuzzleList.size());
            swapItem(mPuzzleList.get(index), getBlankBitmap());
        }
        List<Integer> data = new ArrayList<>();
        for (int i = 0; i < mPuzzleList.size(); i++) {
            data.add(mPuzzleList.get(i).getPuzzleID());
        }
        if (!canSolve(data, getBlankBitmap().getOriID()) || isSuccess()) {
            shufflePuzzle();
        }
    }

    private boolean canSolve(List<Integer> data, int blankPosition) {
        // 个数为奇数时,倒置和为偶数才有解
        if (data.size() % 2 == 1) {
            return getInversions(data) % 2 == 0;
        } else {    //个数为偶数时
            if (((blankPosition - 1) / mType) % 2 == 1) {  //空格位于奇数行,倒置和为偶数才有解
                return getInversions(data) % 2 == 0;
            } else {    //空格位于偶数行,倒置和为奇数才有解
                return getInversions(data) % 2 == 1;
            }
        }
    }

    //计算比第i位元素小的元素个数的总和,如[3,2,1],倒置和为[2,1,0] = 3
    private int getInversions(List<Integer> data) {
        int inversions = 0;
        int inversionCount = 0;
        for (int i = 0; i < data.size(); i++) {
            for (int j = i + 1; j < data.size(); j++) {
                int index = data.get(i);
                if (data.get(j) != 0 && data.get(j) < index)
                    inversionCount++;
            }
            inversions += inversionCount;
            inversionCount = 0;
        }
        return inversions;
    }
}

ui

IGameCallback

public interface IGameCallback {

   //获取拼图数据
    void onLoadPuzzleData(Bitmap resizeOriBitmap, List<ItemBean> itemBeanList);

	//交换拼图
    void onSwapPuzzle(boolean isMovable, List<ItemBean> itemBeanList);

	//倒计时
    void onCountDown(int time, int step);

	//结束游戏
    void onFinishGame(IPuzzlePresenter.STATE state);

	//复位游戏
    void onResetGame(List<ItemBean> itemBeanList);
}

utils

Constant

public class Constant {
    public static final String ORIGINAL_BITMAP = "Original_Bitmap";
    public static final String PUZZLE_TYPE = "puzzle_type";
}

ImagesUtils

public class ImagesUtils {

	//生成带文字的图片
    public static Bitmap createBitmap(int bitmapWidth, int bitmapHeight, String text) {
        Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(Color.GRAY);

        if (!TextUtils.isEmpty(text)) {
            Paint textPaint = new Paint();
            textPaint.setColor(Color.BLACK);

            textPaint.setTextSize(bitmapWidth / text.length());
            float textWidth = textPaint.measureText(text, 0, text.length());   //用于水平居中
            Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
            float offset = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom; //用于垂直居中
            canvas.drawText(text, (bitmapWidth - textWidth) / 2f, bitmapWidth / 2f + offset, textPaint);
        }
        return bitmap;
    }

	//修改图片大小
    public static Bitmap resizeBitmap(Bitmap bitmap, float newWidth, float newHeight) {
        Matrix matrix = new Matrix();
        matrix.postScale(newWidth / bitmap.getWidth(), newHeight / bitmap.getHeight());
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }
}

ScreenUtils

public class ScreenUtils {

    public static DisplayMetrics getDisplayMetrics(Context context) {
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        display.getMetrics(metrics);
        return metrics;
    }

    public static int getScreenWidthPixels(Context context) {
        return getDisplayMetrics(context).widthPixels;
    }

    public static int getScreenHeightPixels(Context context) {
        return getDisplayMetrics(context).heightPixels;
    }
}

View

MainActivity

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private TextView mTypeSelector;
    private GridView mPicSelector;
    private static final int RESULT_IMAGE = 100;
    private static final int RESULT_CAMERA = 200;
    private int mCurrentType = 2;
    private String[] mPicStrings = new String[]{
            "赵", "钱", "孙", "李",
            "周", "吴", "郑", "王",
            "冯", "陈", "褚", "卫",
            "蒋", "沈", "韩", "选择图片"
    };
    private int mPicListColumns = (int) Math.sqrt(mPicStrings.length);
    private String mCameraTempPath;
    private List<Bitmap> mPicList;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
        initListener();
    }

    private void initListener() {
        mTypeSelector.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mCurrentType == 4) {
                    mCurrentType = 2;
                } else {
                    mCurrentType++;
                }
                mTypeSelector.setText(mCurrentType + " × " + mCurrentType);
            }
        });
        mPicSelector.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (position == mPicStrings.length - 1) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                    builder.setItems(new String[]{"从相册选择", "拍摄"}, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Log.d(TAG, "onClick: which = " + which);
                            if (which == 0) {
                                Intent intent = new Intent(Intent.ACTION_PICK, null);
                                intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
                                startActivityForResult(intent, RESULT_IMAGE);
                            } else {
                                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                                Uri photoUri = Uri.fromFile(new File(mCameraTempPath));
                                intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
                                startActivityForResult(intent, RESULT_CAMERA);
                            }
                        }
                    });
                    builder.show();
                } else {
                    PuzzleActivity.startPuzzleActivity(MainActivity.this, mPicList.get(position), mCurrentType);
                }
            }
        });
    }

    private void initView() {
        mTypeSelector = findViewById(R.id.tv_type_selector);
        mPicSelector = findViewById(R.id.gv_pic_list);
    }

    private void initData() {
        mCameraTempPath = getExternalFilesDir(Environment.DIRECTORY_PICTURES) + "/temp.png";
        Log.d(TAG, "onClick: mImagePath = " + mCameraTempPath);
        //解决上面路径报错问题
        StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
        StrictMode.setVmPolicy(builder.build());
        builder.detectFileUriExposure();

        mPicSelector.setNumColumns(mPicListColumns);
        mPicList = new ArrayList<>();
        for (String string : mPicStrings) {
            mPicList.add(ImagesUtils.createBitmap(
                    ScreenUtils.getScreenWidthPixels(this) / mPicListColumns,
                    ScreenUtils.getScreenWidthPixels(this) / mPicListColumns,
                    string));
        }
        mPicSelector.setAdapter(new PictureListAdapter(this, mPicList));
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.d(TAG, "onActivityResult: resultCode = " + resultCode);
        if (resultCode == RESULT_OK) {
            Bitmap oriBitmap = null;
            InputStream inputStream = null;
            Log.d(TAG, "onActivityResult: requestCode = " + requestCode);
            if (requestCode == RESULT_IMAGE && data != null) {
                try {
                    inputStream = getContentResolver().openInputStream(data.getData());
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }

            } else if (requestCode == RESULT_CAMERA) {
                try {
                    inputStream = new FileInputStream(mCameraTempPath);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            options.inSampleSize = 4;   //图片太大,缩放到1/4
            options.inJustDecodeBounds = false;
            oriBitmap = BitmapFactory.decodeStream(inputStream, null, options);
            Log.d(TAG, "onActivityResult: oriBitmap = " + oriBitmap);
            PuzzleActivity.startPuzzleActivity(MainActivity.this, oriBitmap, mCurrentType);
        }
    }
}

PuzzleActivity

public class PuzzleActivity extends AppCompatActivity implements View.OnClickListener, IGameCallback {

    private static final String TAG = "PuzzleActivity";
    private TextView mStep;
    private TextView mCountDown;
    private GridView mPuzzleGv;
    private ImageView mOriPic;
    private Button mShowPicBtn;
    private Button mResetBtn;
    private Button mBackBtn;

    private PuzzleAdapter mPuzzleAdapter;
    private IPuzzlePresenter mPuzzlePresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_puzzle);
        initView();
        initData();
        initListener();
    }

    private void initView() {
        mStep = findViewById(R.id.tv_step_count);
        mCountDown = findViewById(R.id.tv_countdown);
        mPuzzleGv = findViewById(R.id.gv_puzzle);
        mOriPic = findViewById(R.id.iv_ori_pic);
        mShowPicBtn = findViewById(R.id.btn_ori_pic);
        mResetBtn = findViewById(R.id.btn_reset);
        mBackBtn = findViewById(R.id.btn_back);
    }

    public static void startPuzzleActivity(Context context, Bitmap oriBitmap, int type) {
        Intent intent = new Intent(context, PuzzleActivity.class);
        intent.putExtra(Constant.ORIGINAL_BITMAP, oriBitmap);
        intent.putExtra(Constant.PUZZLE_TYPE, type);
        context.startActivity(intent);
    }

    private void initData() {
        Intent intent = getIntent();
        Bitmap oriBitmap = intent.getParcelableExtra(Constant.ORIGINAL_BITMAP);
        int type = intent.getIntExtra(Constant.PUZZLE_TYPE, 2);

        mPuzzleGv.setNumColumns(type);

        mPuzzlePresenter = new PuzzlePresenterImpl(type);
        mPuzzlePresenter.registerGameCallback(this);
        mPuzzlePresenter.loadPuzzleData(this, oriBitmap);

        /* print log start */
        Log.d(TAG, "initData: oriBitmap = " + oriBitmap);
        Log.d(TAG, "initData: type = " + type);
        /* print log end */
    }


    private void showFinishDialog(String msg) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(msg);
        builder.setCancelable(false);
        builder.setNegativeButton("再来一次", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                mPuzzlePresenter.restartGame();
                dialog.dismiss();
            }
        });
        builder.setPositiveButton("重选图片", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                finish();
            }
        });
        builder.show();
    }

    private void initListener() {
        mShowPicBtn.setOnClickListener(this);
        mResetBtn.setOnClickListener(this);
        mBackBtn.setOnClickListener(this);
        mPuzzleGv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Log.d(TAG, "onItemClick: position = " + position);
                mPuzzlePresenter.swapPuzzle(position);
            }
        });
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_ori_pic:
                Log.d(TAG, "onClick: btn_ori_pic");
                if (mOriPic.getVisibility() == View.INVISIBLE) {
                    mPuzzleGv.setVisibility(View.INVISIBLE);
                    mOriPic.setVisibility(View.VISIBLE);
                    mShowPicBtn.setText("隐藏原图");
                } else if (mOriPic.getVisibility() == View.VISIBLE) {
                    mPuzzleGv.setVisibility(View.VISIBLE);
                    mOriPic.setVisibility(View.INVISIBLE);
                    mShowPicBtn.setText("显示原图");
                }
                break;
            case R.id.btn_reset:
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage("是否将拼图还原到最开始的状态");
                builder.setCancelable(false);
                builder.setNegativeButton("还原", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        mPuzzlePresenter.resetGame();
                    }
                });
                builder.setPositiveButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
                builder.show();
                break;
            case R.id.btn_back:
                finish();
                break;
        }
    }

    @Override
    public void onLoadPuzzleData(Bitmap resizeOriBitmap, List<ItemBean> itemBeanList) {
        mOriPic.setImageBitmap(resizeOriBitmap);
        updateUI(itemBeanList);
    }

    private void updateUI(List<ItemBean> itemBeanList) {
        if (mPuzzleAdapter == null) {
            mPuzzleAdapter = new PuzzleAdapter();
            mPuzzleAdapter.setData(itemBeanList);
            mPuzzleGv.setAdapter(mPuzzleAdapter);
        } else {
            mPuzzleAdapter.setData(itemBeanList);
            mPuzzleAdapter.notifyDataSetChanged();
        }
    }

    @Override
    public void onSwapPuzzle(boolean isMovable, List<ItemBean> itemBeanList) {
        if (isMovable) {
            updateUI(itemBeanList);
        } else {
            Toast.makeText(this, "请点击空白格附近的图片进行交换", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onCountDown(int time, int step) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mCountDown.setText("剩余时间: " + time / 60 + "分" + time % 60 + "秒");
                mStep.setText("剩余步数: " + step);
            }
        });
    }

    @Override
    public void onFinishGame(IPuzzlePresenter.STATE state) {
        switch (state) {
            case SUCCESS:
                showFinishDialog("拼图成功");
                break;
            case FAILED_STEP:
                showFinishDialog("步数已用完");
                break;
            case FAILED_TIME:
                showFinishDialog("倒计时结束");
                break;
        }
    }

    @Override
    public void onResetGame(List<ItemBean> itemBeanList) {
        updateUI(itemBeanList);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPuzzlePresenter.unRegisterGameCallback();
    }

}

布局

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/ll_type_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_margin="10dp"
        android:padding="3dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="选择难度"
            android:textSize="30sp" />

        <TextView
            android:id="@+id/tv_type_selector"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:background="#33000000"
            android:padding="3dp"
            android:text="2 × 2"
            android:textSize="25sp" />
    </LinearLayout>

    <GridView
        android:id="@+id/gv_pic_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/ll_type_container"
        android:horizontalSpacing="1dp"
        android:verticalSpacing="1dp" />
</RelativeLayout>

activity_puzzle.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.PuzzleActivity">

    <LinearLayout
        android:id="@+id/ll_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center">

        <TextView
            android:id="@+id/tv_step_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="#33000000"
            android:padding="10dp"
            android:text="步数"
            android:textSize="25sp" />

        <TextView
            android:id="@+id/tv_countdown"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="#33000000"
            android:padding="10dp"
            android:text="时间"
            android:textSize="25sp" />
    </LinearLayout>

    <GridView
        android:id="@+id/gv_puzzle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/ll_btns"
        android:layout_below="@id/ll_title"
        android:horizontalSpacing="2dp"
        android:verticalSpacing="2dp" />

    <ImageView
        android:id="@+id/iv_ori_pic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/gv_puzzle"
        android:visibility="invisible" />

    <LinearLayout
        android:id="@+id/ll_btns"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:gravity="center">

        <Button
            android:id="@+id/btn_ori_pic"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="30dp"
            android:background="#33000000"
            android:text="显示原图"
            android:textSize="30sp" />

        <Button
            android:id="@+id/btn_reset"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="30dp"
            android:background="#33000000"
            android:text="复位"
            android:textSize="30sp" />

        <Button
            android:id="@+id/btn_back"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="30dp"
            android:background="#33000000"
            android:text="返回"
            android:textSize="30sp" />
    </LinearLayout>
</RelativeLayout>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/540516.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国内 无需科学上网 免费体验 ai 语言交互平台 chatpgt替代(汇总)

ChitGPT CSDN 基于chatgpt 3.5模型 ChitGPT AI EDU - Learn AI, Use AI https://ai.aigcfun.com/ 之前有web端的 现在只有app 和桌面端 通义千问 阿里 通义千问 还没通过审核 360 智脑 360 智脑 体验名额满了 sparkDesk 讯飞 sparkDesk 还没通过审核 文心一言 百度…

行业分析| 快对讲-融合会议的应用

全球经济一体化不断加快&#xff0c;企业也开始注重信息化和现代化建设&#xff0c;无论是企业内部还是外部的沟通与协作都变得非常重要。融合会议为企业提供一种“轻模式”的信息沟通和管理服务。支持语音、视频和数据多媒体通信&#xff0c;实现了语音与数据的无缝融合。用户…

直播预告 | 员工在公司体验感UP,原因竟然是这个......

而随着企业数字化进程的加速&#xff0c;企业账号管理面临着前所未有的挑战。安全性、便捷性和管理效率成为企业管理者关注的重点。 作为公司员工&#xff0c;“打工人”或多或少都面临着不同系统&#xff1a;开发工具、版本控制系统、文档管理系统、项目管理工具......“打工…

LeetCode 637. 二叉树的层平均值

637. 二叉树的层平均值 描述 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 1 0 − 5 10^-\\^5 10−5 以内的答案可以被接受。 示例 示例1 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,20],[15,7]…

大家都在用哪些研发协同、沟通协同、项目协同软件?

这里我们将根据需求将协同软件分为&#xff1a;项目管理协作沟通、研发管理协同、文档协同、会议协同、设计协同、沟通协同6个大类进行分别推荐。 随着企业对高效协同办公的需求日益增长&#xff0c;市场上出现了众多协同办公软件。这些软件通过提供各种实用的功能&#xff0c;…

ChatGPT访问互联网,不神秘了

我测试了一下&#xff0c;它其实调用了微软必应的api&#xff0c;搜索了关键词而已 比如我问它&#xff1a;https://twitter.com/elonmusk 马斯克最近在忙什么 它的回答是&#xff1a; 近期&#xff0c;马斯克在做的一些事情包括&#xff1a; 在2023年的特斯拉年度股东大会…

内网渗透(七十七)之域权限维持之ACL滥用(中)

ACL滥用(中) 3、msDS-AllowedToActOnBehalfOfOtherldentity 属性权限 如图所示是微软对于msDS-AllowedToActOnBehalfOfOtherldentity 属性的描述 jack是域中的一个普通用户。现在我们获得了域管理员的权限,并想进行权限维持,可以进行如下的操作:使用Empire下的powerview…

编译zlib

zlib被设计为一个免费的&#xff0c;通用的&#xff0c;法律上不受限制的-即不受任何专利保护的无损数据压缩库&#xff0c;几乎可以在任何计算机硬件和操作系统上使用。 官网&#xff1a;http://www.zlib.net/ 下载zlib源码:http://www.zlib.net/zlib1213.zip 备用地址&#x…

opencv图像拼接

opencv图像拼接是一种在一系列图片中选取部分区域&#xff0c;通过这些区域的重叠得到一个完整的图像&#xff0c;并将这些图片拼接起来的方法。它与传统的方法不同&#xff0c;可以看作是基于拼接技术的图像处理。 opencv是一款开源的图像处理软件&#xff0c;主要用于计算机视…

看模型、做技术交底、做项目汇报,图新说数字化汇报平台引领交互式汇报新模式

现场汇报效果不好&#xff0c;导致丢了一个项目&#xff01; 项目汇报平淡无奇&#xff0c;方案屡次被毙&#xff01; 面对专家质疑&#xff0c;回答苍白无力&#xff01; 估计大家都有过这种经历和感受。 详细分析一下&#xff0c;基本上有以下几个方面的原因&#xff1a; …

ASEMI代理Infineon英飞凌IPB60R099CP原厂MOS管

编辑-Z IPB60R099CP参数描述&#xff1a; 型号&#xff1a;IPB60R099CP 持续漏极电流&#xff1a;31A 脉冲漏极电流&#xff1a;93A 雪崩电流&#xff0c;重复&#xff1a;11A 栅极-源极电压&#xff1a;20V 功率耗散&#xff1a;255W 操作和储存温度&#xff1a;-55 t…

Springer期刊 latex投稿经验分享

Springer Nature期刊的latex模板下载: Download the journal article template package 以MTAP为例(修改之后对修订稿的投递过程) 第一步:将您的文章提交到适当的期刊轨道或特刊。 如有必要,从下拉菜单中更改您提交的文章类型。 然后点击Proceed 第二步: 与您提交的先前修…

Jmeter +Maven+jenkins 接口性能全自动化测试

背景&#xff1a; 首先用jmeter录制或者书写性能测试的脚本&#xff0c;用maven添加相关依赖&#xff0c;把性能测试的代码提交到github&#xff0c;在jenkins配置git下载性能测试的代码&#xff0c;配置运行脚本和测试报告&#xff0c;配置运行失败自动发邮件通知&#xff0c…

陪诊小程序开发|陪诊系统源码|陪诊系统开发

近年来&#xff0c;一个新兴的产业异军突起。 专业陪诊医生主要是陪一些孩子不在身边的老人&#xff0c;或者家人不在身边的孕妇&#xff0c;看病、检查等&#xff0c;其实这个小程序不只是看病而已 . &#xff0c;以及更多功能。 配套小程序功能展示&#xff1a; 1、预诊预约…

23种设计模式之桥接模式(Bridge Pattern)

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章将23种设计模式中的桥接模式&#xff0c;此篇文章为一天学习一个设计模式系列文章&#xff0c;后面会分享其他模式知识。 如果文章有什么需要改进的地方还请大佬不…

【Selenium下】——全栈开发——如桃花来

目录索引 获取元素信息&#xff1a;获取单个文本和属性&#xff1a;*获取文本&#xff1a;**获取属性&#xff1a;* 获取多个文本和属性值&#xff1a; 等待&#xff1a;显示等待&#xff1a;time等待&#xff1a; EC&#xff1a;常见方法&#xff1a; 前进后退:选项卡管理&…

同步管理1000个设备的VLAN数据,这都行?

大家好&#xff0c;我是老杨。 很多网工在工作中&#xff0c;经常会遇到企业网的交换机上需要保持VLAN信息同步的情况。 因为只有这样&#xff0c;才可以以保证所有交换机都能进行正确的数据转发。 小型企业网中&#xff0c;你可以直接登录到每台交换机上进行VLAN的配置和维…

使用Atmel Studio开发Arduino的ATmega328P单片机

摘要&#xff1a;我们知道Arduino开发板常用的芯片是Atmel公司生产的AVR微控制器系列。最常见的是ATmega328P&#xff0c;被广泛用于Arduino Uno开发板。其他常用的AVR芯片包括ATmega2560和ATmega32U4。使用Arduino平台开发AVR的单片机非常方便。Arduino IDE提供了一个非常简洁…

中睿天下成为国家信息安全漏洞库(CNNVD)一级技术支撑单位

近日&#xff0c;中国信息安全测评中心公布2023年度国家信息安全漏洞库技术支撑单位名单&#xff0c;中睿天下荣获中国信息安全测评中心颁发的“国家信息安全漏洞库&#xff08;CNNVD&#xff09;技术支撑单位等级&#xff08;一级&#xff09;证书”&#xff0c;成为该领域最高…

在tomcat中手动部署应用

以maven做为构建工具的web应用为例&#xff0c;如下图&#xff1a; 在tomcat中运行应用&#xff0c;运行的是应用的字节码文件&#xff0c;所以我先执行package生命周期&#xff0c;新增target文件夹&#xff0c;如下&#xff1a; 打开上面的war文件&#xff0c;跟第一个红框里…