Android开发-自定义View-AndroidStudio(二十四)数独(1)

Android 同时被 3 个专栏收录
170 篇文章 0 订阅
转载请注明出处: http://blog.csdn.net/iwanghang/article/details/54094519
觉得博文有用,请点赞,请评论,请关注,谢谢!~


老规矩,先上GIF动态图,看个效果,如果符合你的项目或者确定你要了解的内容,再往下看吧:
这篇博文是接着前面3篇博文写的,目的是继续练习自定义View,没有新的知识点。


Number.java:
package com.iwanghang.newview;

public class Number {
    // 定义81个数字
    // str1、str2 各代表一个关卡
    private final String str1 = "600040800084005032000090700563180400009027000708604391" +
            "392476518150900200047512063";
    private final String str2 = "102004007000080000006000000050000380000000000000902000" +
            "000000070000000102089030000";

    // 实例化一个下标81的数组
    private int number[] = new int[9*9];

    // 存储不可用数据
    private int used[][][] = new int[9][9][];

    public Number(){
        number = fromPuzzleString(str1);
    }

    public Number(int str){
        if (str == 1){
            number = fromPuzzleString(str1);
        }else if (str == 2){
            number = fromPuzzleString(str2);
        }
        calculateAllUsedTiles(); // 获取当前关卡不可用数字数组
    }

    // 把81个数字设置到数组中,为0的设置为空
    private int[] fromPuzzleString(String str) {
        int[] number = new int[str.length()];
        for (int i = 0; i < number.length; i++) {
            number[i] = str.charAt(i) - '0';
        }
        return number;
    }

    // 根据数字在第几行第几个,获取其在数组中的下表
    private int getTile(int x, int y){
        //return number[y * 9 + x];
        if (y * 9 + x < 81){
            return number[y * 9 + x];
        }else {
            return 0;
        }
    }

    // 获取数字的字符串类型
    public String getTileString(int x, int y){
        int v = getTile(x,y);
        if (v == 0){
            return "";
        }else
            return String.valueOf(v);
    }






    public int[] getUsedTilesByCoor(int x,int y){
        return used[x][y];
    }

    public void calculateAllUsedTiles() {
        for (int x = 0; x < 9; x++) {
            for (int y = 0; y < 9; y++) {
                used[x][y] = calculateUsedTiles(x, y);
            }
        }
    }

    /**
     * 获取当前关卡不可用数字数组
     */
    public int[] calculateUsedTiles(int x, int y) {
        int c[] = new int[9];

        for (int i = 0; i < 9; i++) {
            if (i == y)
                continue;
            int t = getTile(x, i);
            if (t != 0)
                c[t - 1] = t;
        }

        for (int i = 0; i < 9; i++) {
            if (i == x)
                continue;
            int t = getTile(i, y);
            if (t != 0)
                c[t - 1] = t;
        }

        int startx = (x / 3) * 3;
        int starty = (y / 3) * 3;
        for (int i = startx; i < startx + 3; i++) {
            for (int j = starty; j < starty + 3; j++) {
                if (i == x && j == y)
                    continue;
                int t = getTile(i, j);
                if (t != 0)
                    c[t - 1] = t;
            }
        }
        // compress
        int nused = 0;
        for (int t : c) {
            if (t != 0)
                nused++;
        }
        int c1[] = new int[nused];
        nused = 0;
        for (int t : c) {
            if (t != 0)
                c1[nused++] = t;
        }
        return c1;
    }

}
NewView.java:
package com.iwanghang.newview;

import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

public class NewView extends View{
    // 单元格的宽度和高度
    private float width;
    private float height;

    private int checkPoint = 1; // 当前关卡

    //private Number number = new Number();
    private Number number = new Number(checkPoint);


    public NewView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public NewView(MainActivity mainActivity) {
        super(mainActivity);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        this.width = w / 9f;
        this.height = h / 10f;
        super.onSizeChanged(w, h, oldw, oldh);
    }

    // 当Android系统需要绘制一个View对象时,就会调用该对象的onDraw
    @Override
    protected void onDraw(Canvas canvas) {
        // 画背景
        Paint backgroundPaint = new Paint();
        backgroundPaint.setColor(getResources().getColor(R.color.colorBackground));
        canvas.drawRect(0,0,getWidth(),getHeight(),backgroundPaint);

        Paint darkPaint = new Paint();
        darkPaint.setColor(getResources().getColor(R.color.colorDark));

        Paint hilitePaint = new Paint();
        hilitePaint.setColor(getResources().getColor(R.color.colorHilite));

        Paint lightPaint = new Paint();
        lightPaint.setColor(getResources().getColor(R.color.colorLight));

        // 绘制9X9的网络格
        // 两条距离为1的直线,视觉上会有割裂的效果
        for (int i = 0; i < 9; i++) {
            canvas.drawLine(0, i*height, getWidth(), i*height, lightPaint);
            canvas.drawLine(0, i*height+1, getWidth(), i*height+1, hilitePaint);
            canvas.drawLine(i*width, 0, i*width, getHeight(), lightPaint);
            canvas.drawLine(i*width+1, 0, i*width+1, getHeight(), hilitePaint);
        }

        // 绘制3X3的网络格
        for (int i = 0; i < 10; i++) {
            if (i % 3 != 0) {
                continue;
            }
            canvas.drawLine(0, i*height, getWidth(), i*height, darkPaint);
            canvas.drawLine(0, i*height+1, getWidth(), i*height+1, hilitePaint);
            canvas.drawLine(i*width, 0, i*width, getHeight(), darkPaint);
            //canvas.drawLine(i*width+1, 0, i*width+1, getHeight(), hilitePaint);
            canvas.drawLine(i*width, 1, i*width, getHeight(), hilitePaint);
        }

        // 绘制数字
        Paint numberPaint = new Paint();
        numberPaint.setColor(Color.BLACK);
        numberPaint.setStyle(Paint.Style.STROKE);
        numberPaint.setTextSize(height*0.75f);
        numberPaint.setTextAlign(Paint.Align.CENTER);
        numberPaint.setAntiAlias(true); // 抗锯齿

        /**
         * 数字居中位置
         * x轴居中比较容易计算
         * y轴居中的计算,依赖于FontMetrics,大家很容易百度到相关的知识
         */
        Paint.FontMetrics fm = numberPaint.getFontMetrics();
        float x = width / 2;
        float y = height / 2 - (fm.ascent + fm.descent) / 2;

//        canvas.drawText("1", 0 * width + x, 0 * height + y, numberPaint);
//        canvas.drawText("2", 1 * width + x, 1 * height + y, numberPaint);
//        canvas.drawText("3", 2 * width + x, 2 * height + y, numberPaint);
//        canvas.drawText("4", 3 * width + x, 3 * height + y, numberPaint);
//        canvas.drawText("5", 4 * width + x, 4 * height + y, numberPaint);

        /**
         * 根据Number类中的数组,绘制数字
         */
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                canvas.drawText(number.getTileString(i,j), i*width+x, j*height+y, numberPaint);
            }
        }

        /**
         * 绘制一个刷新文字
         */
        canvas.drawText("刷新",4*width+x,9*height+y,numberPaint);

        /**
         * 绘制关卡文字
         */
        Paint strPaint = new Paint();
        strPaint.setTextSize(height*0.5f);
        strPaint.setAntiAlias(true); // 抗锯齿
        canvas.drawText("第" + checkPoint + "关",6*width+x,9*height+y,strPaint);

        super.onDraw(canvas);
    }

    /**
     * 获取按下的数字
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        if (event.getAction() == MotionEvent.ACTION_DOWN){
            int selectedX = (int)(event.getX() / width);
            int selectedY = (int)(event.getY() / height);

            StringBuffer sb = new StringBuffer();

            if (selectedY < 9){
                int used[] = number.getUsedTilesByCoor(selectedX,selectedY);
                for (int i = 0; i < used.length; i++) {
                    sb.append(used[i]);
                }
                LayoutInflater layoutInflater = LayoutInflater.from(this.getContext());
                View layoutView = layoutInflater.inflate(R.layout.dialog,null);
                TextView textView = (TextView) layoutView.findViewById(R.id.usedTextId);
                textView.setText("该位置不可用数字 = " + sb.toString());
                AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
                builder.setView(layoutView);
                AlertDialog dialog = builder.create();
                dialog.show();
            }

            //Toast.makeText(getContext(), "ACTION_DOWN = " + used, Toast.LENGTH_SHORT).show();
            if (selectedY == 9){
                if (selectedX>=3 && selectedX<=5){
                    //Toast.makeText(getContext(), "ACTION_DOWN = 刷新",Toast.LENGTH_SHORT).show();
                    if (checkPoint == 1){
                        checkPoint = 2;
                    } else if (checkPoint == 2){
                        checkPoint = 1;
                    }
                    //Toast.makeText(getContext(), "checkPoint = " + checkPoint, Toast.LENGTH_SHORT).show();
                    number = new Number(checkPoint);
                    invalidate(); // onDraw()
                }
            }

        }
        return true;
    }


}
MainActivity.java:
package com.iwanghang.newview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().hide();
        //setContentView(R.layout.activity_main);
        NewView newView = new NewView(this);
        setContentView(newView);
    }
}
dialog.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/usedTextId"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>


转载请注明出处: http://blog.csdn.net/iwanghang/article/details/54094519



欢迎移动开发爱好者交流
沈阳或周边城市公司有意开发Android,请与我联系
联系方式

微信:iwanghang
QQ:413711276
邮箱:iwanghang@qq.com



觉得博文有用,请点赞,请评论,请关注,谢谢!~

  • 1
    点赞
  • 0
    评论
  • 11
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值