安卓---拼图---慕课网视频复原

  有一段时间没写安卓的代码,慢慢的有点忘了,这个按照视频一步一步来的复原

主要步骤:

1.把一张大图分成多个方块图,GridLayout实现

2.设置某个方块为缺口(拼图是总有一个空白的方块)

3.点击交换缺口与相邻方块的数据

4.获取手势,手势交换缺口与相邻方块的数据

5.打乱顺序

6.判断结束

按钮背景,放在drawable文件夹下,命名bg_btn

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <!-- 定义当button 处于pressed 状态时的形态。-->
        <shape>
            <gradient android:startColor="#8600ff" />
            <stroke android:width="2dp" android:color="#000000" />
            <corners android:radius="5dp" />
            <padding android:left="10dp" android:top="10dp"
                android:bottom="10dp" android:right="10dp" />
        </shape>
    </item>
    
    <item android:state_pressed="false">
        <!-- 定义当button 处于pressed 状态时的形态。-->
        <shape>
            <gradient android:startColor="#aeaeae" android:endColor="#b0b0b0" />
            <stroke android:width="2dp" android:color="#333333" />
            <corners android:radius="5dp" />
            <padding android:left="10dp" android:top="10dp"
                android:bottom="10dp" android:right="10dp" />
        </shape>
    </item>
    
</selector>
View Code

布局文件activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <GridLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/gl_main_game"
        android:columnCount="4"
        android:rowCount="5"
        android:fillViewport="true"
        >

    </GridLayout>
    
    <Button
        android:id="@+id/btn_start"
        android:layout_width="120px"
        android:layout_height="60px"
        android:layout_marginRight="5px"
        android:layout_marginLeft="5px"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20px"
        android:background="@drawable/bg_btn"
        android:text="Start" />
    
    <Button
        android:id="@+id/btn_back"
           android:layout_width="120px"
        android:layout_height="60px"
        android:layout_toLeftOf="@+id/btn_start"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20px"
        android:background="@drawable/bg_btn"
        android:text="Back" />
        
    <Button
        android:id="@+id/btn_select"
           android:layout_width="120px"
        android:layout_height="60px"
        android:layout_toRightOf="@+id/btn_start"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20px"
        android:background="@drawable/bg_btn"
        android:text="Select" />

</RelativeLayout>
View Code

主函数实现逻辑

package com.example.jigsaw;

import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.view.GestureDetector.OnGestureListener;//手势监听包,不提示导入??

public class MainActivity extends Activity {

    /**当前移动动画是否正在执行*/
    private boolean isAnimRun = false;
    /** 利用二维数组创建若干小方块 **/
    private ImageView[][] iv_game_arr = new ImageView[5][4];
    /** 游戏主界面 **/
    private GridLayout gl_main_game;
    /** 当前空方块的实例保存 **/
    private ImageView iv_null_ImageView;
    /** 当前手势 */
    private GestureDetector mDetector;
    /**判断游戏是否开始,默认没开始*/
    private boolean isGameStart = false;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        return mDetector.onTouchEvent(event);// 把界面监听换成手势监听
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        mDetector.onTouchEvent(ev);
        return super.dispatchTouchEvent(ev);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mDetector = new GestureDetector(MainActivity.this,
                new OnGestureListener() {

                    @Override
                    public boolean onSingleTapUp(MotionEvent arg0) {
                        // TODO Auto-generated method stub
                        return false;
                    }

                    @Override
                    public void onShowPress(MotionEvent arg0) {
                        // TODO Auto-generated method stub

                    }

                    @Override
                    public boolean onScroll(MotionEvent arg0, MotionEvent arg1,
                            float arg2, float arg3) {
                        // TODO Auto-generated method stub
                        return false;
                    }

                    @Override
                    public void onLongPress(MotionEvent arg0) {
                        // TODO Auto-generated method stub

                    }

                    @Override
                    public boolean onFling(MotionEvent arg0, MotionEvent arg1,
                            float arg2, float arg3) {
                        int type = getDirByGes(arg0.getX(), arg0.getY(),
                                arg1.getX(), arg1.getY());// 判断手势返回int类型
                        // Toast.makeText(MainActivity.this, "" +
                        // type,Toast.LENGTH_SHORT).show();
                        changeByDir(type);// 移动换图
                        return false;
                    }

                    @Override
                    public boolean onDown(MotionEvent arg0) {
                        // TODO Auto-generated method stub
                        return false;
                    }
                });
        setContentView(R.layout.activity_main);
        /** 初始化游戏的若干小方块 */
        // 获取一张大图片
        Bitmap bigBm = ((BitmapDrawable) getResources().getDrawable(
                R.drawable.kenan1)).getBitmap();
        int tuWandW = bigBm.getWidth() / (iv_game_arr.length);// 每个游戏块的宽和高
        int tvWandH= this.getWindowManager().getDefaultDisplay().getWidth()/ (iv_game_arr.length-1);//小方块的宽度应为屏幕的平均值
        for (int i = 0; i < iv_game_arr.length; i++) {
            for (int j = 0; j < iv_game_arr[i].length; j++) {
                Bitmap bm = Bitmap.createBitmap(bigBm, j * tuWandW,
                        i * tuWandW, tuWandW, tuWandW);// 根据行和列切成若干个游戏小图片

                iv_game_arr[i][j] = new ImageView(this);
                iv_game_arr[i][j].setImageBitmap(bm);// 设置每一个小方块的图片
                iv_game_arr[i][j].setLayoutParams(new RelativeLayout.LayoutParams(tvWandH, tvWandH));//设置宽高
                iv_game_arr[i][j].setPadding(2, 2, 2, 2);// 设置方块的间距

                iv_game_arr[i][j].setTag(new GameData(i, j, bm));// 绑定自定义数据
                // 设置点击监听,判断位置关系
                iv_game_arr[i][j].setOnClickListener(new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        boolean flag = isHasByNullImageView((ImageView) v);
                        // Toast.makeText(MainActivity.this, "位置关系是否存在:"+flag,
                        // Toast.LENGTH_SHORT).show();
                        if (flag) {
                            changeDataByImageView((ImageView) v);
                        }
                    }
                });
            }
        }

        // 初始化游戏界面,并添加若干小方块
        gl_main_game = (GridLayout) findViewById(R.id.gl_main_game);
        for (int i = 0; i < iv_game_arr.length; i++) {
            for (int j = 0; j < iv_game_arr[i].length; j++) {
                gl_main_game.addView(iv_game_arr[i][j]);
            }
        }
        /** 设置第一个方块为空 */
        setNullIamgeView(iv_game_arr[0][0]);
        
        Button btnStart=(Button) findViewById(R.id.btn_start);//button点击之后打乱
        btnStart.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                /** 初始化随机打乱顺序方块 */
                randomMove();
                isGameStart = true;//开始状态
            }
        });

    }

    /**
     * 根据手势的方向,获取空方块相应的相邻位置如果存在方块,那么进行数据交换
     * 
     * @param type
     *            1:上,2:下,3:左,4:右
     */
    public void changeByDir(int type) {
        changeByDir(type, true);
    }

    /**
     * 根据手势的方向,获取空方块相应的相邻位置如果存在方块,那么进行数据交换
     * 
     * @param type
     *            1:上,2:下,3:左,4:右
     * @param isAnim
     *            ture:有动画,false:无动画
     */
    public void changeByDir(int type, boolean isAnim) {
        // 获取当前空方块的位置
        GameData mNullGameData = (GameData) iv_null_ImageView.getTag();
        // 根据方向,设置相应的相邻的位置坐标
        int new_x = mNullGameData.x;
        int new_y = mNullGameData.y;
        if (type == 1) {
            new_x++;
        } else if (type == 2) {
            new_x--;
        } else if (type == 3) {
            new_y++;
        } else if (type == 4) {
            new_y--;
        }
        // 判断这个新坐标,是否存在
        if (new_x >= 0 && new_x < iv_game_arr.length && new_y >= 0
                && new_y < iv_game_arr[0].length) {
            // 存在的话,开始移动
            if (isAnim) {// 有动画
                changeDataByImageView(iv_game_arr[new_x][new_y]);
            } else {// 无动画
                changeDataByImageView(iv_game_arr[new_x][new_y], isAnim);
            }

        } else {
            // 什么也不做
        }
    }

    /**
     * 判断游戏结束的方法
     */
    public void isGameOver(){
        boolean isGameOver = true;
        //要遍历每个游戏小方块
        for (int i = 0; i < iv_game_arr.length; i++) {
            for (int j = 0; j < iv_game_arr[0].length; j++) {
                //为空的方块数据不判断
                if(iv_game_arr[i][j]==iv_null_ImageView){
                    continue;
                }
                GameData mGameData = (GameData) iv_game_arr[i][j].getTag();
                if (!mGameData.isTrue()) {
                    isGameOver=false;
                    break;
                }
            }
        }
            
        //根据一个开关变量决定游戏是否结束,结束时给提
        if (isGameOver) {
            Toast.makeText(MainActivity.this, "游戏结束", Toast.LENGTH_SHORT).show();    
        }
    }

    /**
     * 手势判断,是向左,还是右
     * 
     * @param start_x
     *            手势的起始点x
     * @param start_y
     *            手势的起始点y
     * @param end_x
     *            手势的终止点x
     * @param end_y
     *            手势的终止点y
     * @return 1:上,2:下,3:左,4:右
     */
    public int getDirByGes(float start_x, float start_y, float end_x,
            float end_y) {
        boolean isLeftOrRight = (Math.abs(start_x - end_x) > Math.abs(start_y
                - end_y)) ? true : false;// 是否是左右
        if (isLeftOrRight) {// 左右
            boolean isLeft = start_x - end_x > 0 ? true : false;// 判断左右
            if (isLeft) {
                return 3;
            } else {
                return 4;
            }
        } else {// 上下
            boolean isUp = start_y - end_y > 0 ? true : false;//
            if (isUp) {
                return 1;
            } else {
                return 2;
            }
        }
    }

    // 随机打乱顺序
    public void randomMove() {
        // 打乱的次数
        for (int i = 0; i < 100; i++) {
            // 根据手势开始交换,无动画
            int type = (int) (Math.random() * 4) + 1;// 随机数得到[0,4)之间的数,加上一就是移动的顺序
            changeByDir(type, false);
        }
    }

    /**
     * 利用动画结束之后,交换两个方块的数据
     * 
     * @param mImageView
     *            点击的方块
     */
    public void changeDataByImageView(final ImageView mImageView) {
        changeDataByImageView(mImageView, true);
    }

    /**
     * 利用动画结束之后,交换两个方块的数据
     * 
     * @param mImageView
     *            点击的方块
     * @param isAnim
     *            true 有动画,false 无动画
     */
    public void changeDataByImageView(final ImageView mImageView, boolean isAnim) {    
        if (isAnimRun) {//如果动画正在执行,不进行操作
            return;
        }
        if (!isAnim) {//判断是否有动画
            GameData mGameData = (GameData) mImageView.getTag();
            iv_null_ImageView.setImageBitmap(mGameData.bm);// 设置空方块为交换的图片
            GameData mNullGameData = (GameData) iv_null_ImageView.getTag();
            mNullGameData.bm = mGameData.bm;
            mNullGameData.p_x = mGameData.p_x;
            mNullGameData.p_y = mGameData.p_y;
            setNullIamgeView(mImageView);// 设置当前点击的为空模块
            if (isGameStart) {//开始后每一次移动都要判断是否结束
                isGameOver();// 成功时会弹一个toast
            }    
            return;
        }
        // 创建一个动画,设置好方向,移动距离
        TranslateAnimation translateAnimation = null;
        if (mImageView.getX() > iv_null_ImageView.getX()) {// 当前点击的方块在空方块的下面
            // 往上移
            translateAnimation = new TranslateAnimation(0.1f,
                    -mImageView.getWidth(), 0.1f, 0.1f);
        } else if (mImageView.getX() < iv_null_ImageView.getX()) {
            // 往下移
            translateAnimation = new TranslateAnimation(0.1f,
                    mImageView.getWidth(), 0.1f, 0.1f);
        } else if (mImageView.getY() > iv_null_ImageView.getY()) {
            // 往左移
            translateAnimation = new TranslateAnimation(0.1f, 0.1f, 0.1f,
                    -mImageView.getWidth());
        } else if (mImageView.getY() < iv_null_ImageView.getY()) {
            // 往右移
            translateAnimation = new TranslateAnimation(0.1f, 0.1f, 0.1f,
                    mImageView.getWidth());
        }
        // 设置动画的的时长
        translateAnimation.setDuration(70);
        // 设置动画结束之后时候是否停留
        translateAnimation.setFillAfter(true);
        // 设置动画结束之后要真正的把数据交换了
        translateAnimation.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation arg0) {
                // TODO Auto-generated method stub
                isAnimRun = true;
            }

            @Override
            public void onAnimationRepeat(Animation arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation arg0) {
                // TODO Auto-generated method stub
                isAnimRun = false;
                mImageView.clearAnimation();
                GameData mGameData = (GameData) mImageView.getTag();
                iv_null_ImageView.setImageBitmap(mGameData.bm);// 设置空方块为交换的图片
                GameData mNullGameData = (GameData) iv_null_ImageView.getTag();
                mNullGameData.bm = mGameData.bm;
                mNullGameData.p_x = mGameData.p_x;
                mNullGameData.p_y = mGameData.p_y;
                setNullIamgeView(mImageView);// 设置当前点击的为空模块
                if (isGameStart) {//开始后每一次移动都要判断是否结束
                    isGameOver();// 成功时会弹一个toast
                }
            }
        });
        // 执行动画
        mImageView.startAnimation(translateAnimation);
    }

    /**
     * 设置某个方块为空
     * 
     * @param mImageView
     *            当前要设置为空的方块实例
     */
    public void setNullIamgeView(ImageView mImageView) {
        mImageView.setImageBitmap(null);
        // mImageView.setBackgroundColor(10);//设置空的背景色
        iv_null_ImageView = mImageView;
    }

    /**
     * 判断当前点击的方块,是否与空方块的位置关系是否相邻
     * 
     * @param mImageView
     *            点击的方块实例
     * @return true:相邻,false:不相邻
     */
    public boolean isHasByNullImageView(ImageView mImageView) {
        // 分别获取当前空方块的位置与点击方块的位置,通过x,y两边都差一的方式判断
        GameData mNullGameData = (GameData) iv_null_ImageView.getTag();
        GameData mGameData = (GameData) mImageView.getTag();
        if (mNullGameData.y == mGameData.y
                && mGameData.x + 1 == mNullGameData.x) {// 当前点击的方块在空方块的上边
            return true;
        } else if (mNullGameData.y == mGameData.y
                && mGameData.x - 1 == mNullGameData.x) {// 当前点击的方块在空方块的下边
            return true;
        } else if (mNullGameData.y == mGameData.y + 1
                && mGameData.x == mNullGameData.x) {// 当前点击的方块在空方块的左边
            return true;
        } else if (mNullGameData.y == mGameData.y - 1
                && mGameData.x == mNullGameData.x) {// 当前点击的方块在空方块的右边
            return true;
        }
        return false;
    }

    /**
     * 每个游戏小方块上要绑定的数据
     */
    class GameData {        
        /** 每个小方块的实际位置x */
        public int x = 0;
        /** 每个小方块的实际位置y */
        public int y = 0;
        /** 每个小方块的图片 */
        public Bitmap bm;
        /** 每个小方块的图片的位置x */
        public int p_x = 0;
        /** 每个小方块的图片的位置y */
        public int p_y = 0;

        public GameData(int x, int y, Bitmap bm) {
            super();
            this.x = x;
            this.y = y;
            this.bm = bm;
            this.p_x = x;
            this.p_y = y;
        }
        /**
         * 每个小方块的位置是否正确
         * @return true:正确,false:不正确
         */
        public boolean isTrue(){
            if (x==p_x && y==p_y) {
                return true;
            }
            return false;
        }

    }
}
View Code

效果如下:

 

posted @ 2016-08-01 15:42  下雨天rain  阅读(250)  评论(0编辑  收藏  举报