您的位置:首页 > 移动开发 > Android开发

Android开发-自定义View-AndroidStudio(二十六)数独(3)Dialog监听

2017-01-09 16:25 429 查看
转载请注明出处:http://blog.csdn.net/iwanghang/article/details/54290001
觉得博文有用,请点赞,请评论,请关注,谢谢!~

项目下载:http://download.csdn.net/detail/iwanghang/9739493

老规矩,先上GIF动态图,看个效果,如果符合你的项目或者确定你要了解的内容,再往下看吧:

看一下代码里面的K1,K2,K3,K4,K5,K6,就可以了解函数运行的顺序,最后在看一下setTileIfValid方法就可以了。



KeyDialog.java:
package com.iwanghang.newview;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;

// 该类用于实现Dialog,实现自定义的对话框功能
public class KeyDialog extends Dialog {
// 用来存放代表对话框当中按钮的对象
private final View keys [] = new View[9];
private final int used[];
private NewView newView;

// 构造函数的第二个参数当中保存着当前单元格已经使用过的数字
public KeyDialog(Context context, int [] used){
super(context);
this.used = used;
}

// 构造函数的第二个参数当中保存着当前单元格已经使用过的数字
public KeyDialog(Context context,int [] used,NewView newView){
super(context);
this.used = used;
this.newView = newView;
}

// 当一个Dialog第一次显示的时候,会调用其onCreate方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置对话框的标题
setTitle("KeyDialog");
// 用于为该Dialog设置布局文件
setContentView(R.layout.keypad);
//
findViews();
// 遍历整个used数组
for (int i = 0; i <used.length; i++) {
if(used[i] != 0){
System.out.println(used[i]);
keys[used[i] - 1].setVisibility(View.INVISIBLE);
}
}
// 为对话框当中所有的按钮设置监听器
setListeners();
}

private void findViews() {
keys[0] = findViewById(R.id.keypad_1);
keys[1] = findViewById(R.id.keypad_2);
keys[2] = findViewById(R.id.keypad_3);
keys[3] = findViewById(R.id.keypad_4);
keys[4] = findViewById(R.id.keypad_5);
keys[5] = findViewById(R.id.keypad_6);
keys[6] = findViewById(R.id.keypad_7);
keys[7] = findViewById(R.id.keypad_8);
keys[8] = findViewById(R.id.keypad_9);
}

// KeyDialog初始化的时候,设置数字按键监听,K1
private void setListeners() {
// 遍历整个keys数组
for (int i = 0; i < keys.length; i++) {
final int keyPress = i + 1;
keys[i].setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
returnResult(keyPress); // 返回点击的数字,K2
}
});
}
}
// 通知NewView对象,刷新整个九宫格显示的数据
private void returnResult(int tile) {
newView.setSelectedTile(tile); // 调用NewView中的方法,K3
// 取消对话框的显示
dismiss();
}

}
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.os.Handler;
import android.os.Message;
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 MainActivity mainActivity = (MainActivity) getContext();

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

private int selectedX;
private int selectedY;

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) {
System.out.println("AAA onDraw -----------------");
// 画背景
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);
//                mainActivity.playSound();
//                handler.sendEmptyMessageDelayed(0, 200); // 每次重绘后,等待200毫秒,给handler发消息
//            }
//        }

/**
* 绘制一个刷新文字
*/
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);
//        canvas.drawText(number.getTileString(numberX,numberY), numberX*width+x, numberY*height+y, numberPaint);
//        System.out.println("numberY = " + numberY);
//        if (numberY < 9){
//            if (number.getTileString(numberX,numberY) != ""){
//                mainActivity.playSound();
//                handler.sendEmptyMessageDelayed(0, 200); // 每次重绘后,等待200毫秒,给handler发消息
//            }else {
//                handler.sendEmptyMessageDelayed(0, 0); // 每次重绘后,等待500毫秒,给handler发消息
//            }
//        }

/**
* 优先绘制上一次绘制过的数字
*/
int numberIndexOld = 0;
int ii = 0;
int jj = 0;
if (numberIndex != 0){ // 首次绘制,没有上一次绘制过的数字,所以不进入这个方法
System.out.println("AAA 优先绘制上一次绘制过的数字 numberIndex = " + numberIndex);
outterLoop1:
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);
System.out.println("AAA 优先绘制上一次绘制过的数字 number = " + number.getTileString(i,j) + " | i = " + i
+ " | j = " + j + " | numberIndexOld = " + numberIndexOld);
if (numberIndexOld == (numberIndex-1)){
ii = i;
jj = j;
break outterLoop1;
}
numberIndexOld = numberIndexOld + 1 ;
}
}
jj = jj + 1;
if (jj == 9){
jj = 0;
ii = ii + 1;
}
}

int getOld = 0;
/**
* 根据Number类中的数组,绘制数字
*/
System.out.println("AAA0 绘制数字 jj = " + jj + " | ii = " + ii);
outterLoop2:
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (getOld == 0){ // 继续上一次绘制的数字的i和j,继续绘制
i = ii;
j = jj;
getOld = 1;
}
canvas.drawText(number.getTileString(i,j), i*width+x, j*height+y, numberPaint);
numberIndex = numberIndex + 1 ;
System.out.println("AAA0 绘制数字 number = " + number.getTileString(i,j) + " | i = " + i
+ " | j = " + j);
// 绘制过程中 遇到 不为空的数字 , 播放音效 并 延迟300毫秒
System.out.println();
if (number.getTileString(i,j) != "" && numberIndex<81){
mainActivity.playSound(); // 调用MainActivity里的方法,播放音效
handler.sendEmptyMessageDelayed(0, 1); // 等待300毫秒,给handler发消息
break outterLoop2;
}
}
}

}

/**
* 获取按下的数字
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_DOWN){
selectedX = (int)(event.getX() / width);
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();
KeyDialog keyDialog = new KeyDialog(getContext(), used, this);
keyDialog.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);
numberIndex = 0;
invalidate(); // onDraw()
}
}

}
return true;
}

private int numberIndex = 0; // 绘制完成的数字,下标81
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
invalidate(); // onDraw();
}
};

// KeyDialog当按下一个数字,隐藏KeyDialog后,会调用下面这个方法,K4
public void setSelectedTile(int tile) {
System.out.println("BBB = selectedX = " + selectedX + " | selectedY = " + selectedY + " | tile = " + tile);
if (number.setTileIfValid(selectedX, selectedY, tile)) { // 设置按下的数字到数组中,并判断是否为真,K5
invalidate(); // onDraw(),K6
}
}
}
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;
}

protected boolean setTileIfValid(int x, int y, int value) {
System.out.println("Number BBB = x = " + x + " | y = " + y + " | value = " + value);
int tiles[] = getUsedTiles(x, y);
if (value != 0) {
for (int tile : tiles) {
if (tile == value)
return false;
}
}
setTile(x, y, value);
calculateAllUsedTiles();
return true;
}

protected int[] getUsedTiles(int x, int y) {
return used[x][y];
}

private void setTile(int x, int y, int value) {
number[y * 9 + x] = value;
}
}
MainActivity.java:
package com.iwanghang.newview;

import android.media.AudioManager;
import android.media.SoundPool;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

private SoundPool soundPool;
private static int soundId;
int resId = R.raw.doo;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
//setContentView(R.layout.activity_main);

NewView newView = new NewView(this);

setContentView(newView);
initSoundPool(resId);
}

public void initSoundPool(int resId) { // 初始化声音池
soundPool = new SoundPool(
3, // maxStreams参数,该参数为设置同时能够播放多少音效
AudioManager.STREAM_MUSIC, // streamType参数,该参数设置音频类型,在游戏中通常设置为:STREAM_MUSIC
1 // srcQuality参数,该参数设置音频文件的质量,目前还没有效果,设置为0为默认值。
);
soundId = soundPool.load(this, resId, 1);
}

public void playSound() { // 播放声音,参数sound是播放音效的id,参数number是播放音效的次数
soundPool.play(
soundId, // 播放的音乐id
1, // 左声道音量
1, // 右声道音量
1, // 优先级,0为最低
0, // 循环次数,0无不循环,-1无永远循环
1 // 回放速度 ,该值在0.5-2.0之间,1为正常速度
);
}

public void stopSound() { // 播放声音,参数sound是播放音效的id,参数number是播放音效的次数
if (soundPool != null && soundId > 0) {
soundPool.stop(soundId);
soundPool.release();
}
}

}
keypad.xml:
<?xml version="1.0" encoding="utf-8"?>
<!--
! Excerpted from "Hello, Android!",
! published by The Pragmatic Bookshelf.
! Copyrights apply to this code. It may not be used to create training material,
! courses, books, articles, and the like. Contact us if you are in doubt.
! We make no guarantees that this code is fit for any purpose.
! Visit http://www.pragmaticprogrammer.com/titles/eband for more book information.
-->
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keypad"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="*">
<TableRow>
<Button android:id="@+id/keypad_1"
android:text="1">
</Button>
<Button android:id="@+id/keypad_2"
android:text="2">
</Button>
<Button android:id="@+id/keypad_3"
android:text="3">
</Button>
</TableRow>
<TableRow>
<Button android:id="@+id/keypad_4"
android:text="4">
</Button>
<Button android:id="@+id/keypad_5"
android:text="5">
</Button>
<Button android:id="@+id/keypad_6"
android:text="6">
</Button>
</TableRow>
<TableRow>
<Button android:id="@+id/keypad_7"
android:text="7">
</Button>
<Button android:id="@+id/keypad_8"
android:text="8">
</Button>
<Button android:id="@+id/keypad_9"
android:text="9">
</Button>
</TableRow>
</TableLayout>


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

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



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



觉得博文有用,请点赞,请评论,请关注,谢谢!~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: