Android開發-自定義View-AndroidStudio(二十六)數獨(3)Dialog監聽
覺得博文有用,請點贊,請評論,請關注,謝謝!~
老規矩,先上GIF動態圖,看個效果,如果符合你的專案或者確定你要了解的內容,再往下看吧:
看一下程式碼裡面的K1,K2,K3,K4,K5,K6,就可以瞭解函式執行的順序,最後在看一下setTileIfValid方法就可以了。
KeyDialog.java:
NewView.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(); } }
Number.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 } } }
MainActivity.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; } }
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
郵箱:[email protected]
覺得博文有用,請點贊,請評論,請關注,謝謝!~
相關推薦
Android開發-自定義View-AndroidStudio(二十六)數獨(3)Dialog監聽
轉載請註明出處:http://blog.csdn.net/iwanghang/article/details/54290001覺得博文有用,請點贊,請評論,請關注,謝謝!~老規矩,先上GIF動態圖,看個效果,如果符合你的專案或者確定你要了解的內容,再往下看吧:看一下程式碼裡面
Android開發-自定義View-AndroidStudio(六)ViewPager再體驗
轉載請註明出處:http://blog.csdn.net/iwanghang/article/details/53742814覺得博文有用,請點贊,請留言,請關注,謝謝!~直接看GIF效果和程式碼(相對於ViewPager初體驗,添加了當前頁面的點點選中變色效果,以及對應文字
Android開發-自定義View-AndroidStudio(五)ViewPager初體驗
轉載請註明出處:http://blog.csdn.net/iwanghang/絕對博文有用,請點贊,請留言,謝謝!~直接看GIF效果和程式碼:MainActivity.java:package com.iwanghang.viewpager; import android.
Android開發-自定義View-AndroidStudio(八)自定義View初體驗
轉載請註明出處:http://blog.csdn.net/iwanghang/article/details/53783417覺得博文有用,請點贊,請評論,請關注,謝謝!~老規矩,先上效果圖,看個效果,如果符合你的專案或者確定你要了解的內容,再往下看吧:MainActivit
[Android開發]自定義View之TextView區域性操作View-SpanTextView
一、功能效果圖 Android TextView的區域性操作Span封裝View,支援縮略顯示、區域性點選、區域性格式設定、圖片插入替換等等 二、簡單使用 TextView需要區域性操作:點選某些區域性文字的事件、顏色、大小、下劃線、指定位置插入圖片、
[Android開發] 自定義View之重寫View非常簡單實現開關按鈕SwitchView
一、 效果圖 二、 實現原理 一個View,畫一個圓角矩形,再畫一個圓點就可以了,100行程式碼左右就可以了,不需要圖片。 三、 實現程式碼 為了程式碼不臃腫,只添加了一個設定預設開關的方法,就沒新增設定顏色的方法,如果需要的話自己根據專案在
Android自定義View(二、深入解析自定義屬性)
目錄: 繼承View,覆蓋構造方法 自定義屬性 重寫onMeasure方法測量寬高 重寫onDraw方法繪製控制元件 接下來幾篇部落格分別深入學習每一個步驟的知識點,第一步就不用多講了,這篇部落格我們看一
Android 自定義View(二),點,線的繪製
public class PointLine extends View { Paint mLinePaint; Paint mPointPaint; float width; float height; float pointAddress
Android開發-自定義Dialog
下面是效果圖 定義一個MyDialog.java工具類繼承Dialog類 具體程式碼如下: /** * Created by WW on 2018/9/12. */ public abstract class MyDialog extends Dialog{ pr
Android之自定義View
在Android開發中,系統本身為我們提供了許多可供選擇的UI控制元件,但是在有些情況下也是需要自定義一些控制元件的。比如UI中的柱狀圖、餅圖等。而自定義View就需要明白它的原理了。 大體上分為三步onMeasure、onLayout、onDraw。大部分情況下我們只需要重寫兩個函式:onMe
移動開發-----自定義View(圓環)
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.grap
自定義View(二)View的事件分發機制原始碼解析
View的事件分發機制是Android中的一個難點,也是非常重要的知識點,充分理解和掌握事件分發機制有助於我們在自定義view的過程中更好地設計和解決事件相關問題。下面我們通過原始碼的角度去分析一下Android是怎麼處理view事件的。 一個事件(比如手指按下螢幕的down事件)首先傳遞到
android基礎--自定義View
1.自定義view繪製字串 import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graph
Android應用自定義View繪製方法手冊
背景 這篇遲遲難產的文章算是對2015前半年的一個交代吧,那時候有一哥們要求來一發Android Canvas相關總結,這哥們還打賞了,實在不好意思,可是這事一放就給放忘了,最近群裡小夥伴催著說沒更新部落格,坐等更新啥的,隨先有這麼一篇Android應用開發超
從零開始學Android自定義View之動畫系列——屬性動畫(3)
屬性動畫對補間動畫進行了很大幅度的改進,之前補間動畫可以做到的屬性動畫也能做到,補間動畫做不到的現在屬性動畫也可以做到了。因此,今天我們就來學習一下屬性動畫的高階用法,看看如何實現一些補間動畫所無法實現的功能。 ValueAnimator的高階用法 補間
android藍芽4.0BLE及2.0 2.1 apk 串列埠助手帶16個自定義按鍵和自定義指令 字元接收 十六進位制或字元傳送
android藍芽4.0BLE apk 帶16個自定義按鍵和自定義指令 字元接收 https://pan.baidu.com/s/1eRSfprO android藍芽2.0 2.1 apk 帶16個自定義按鍵和自定義指令 字元接收 帶自動連線 https://pan.b
自定義View(二)
前面說過了,自定義View主要有下面三種: 1.對現有控制元件進行擴充套件 2.通過組合實現新的控制元件 3.重寫View實現全新控制元件 對現有控制元件進行擴充套件 擴充套件了一個TextView,有內外兩個矩形組成。程式碼如下: publ
android給自定義view新增XML屬性
1.在value下新建檔案(檔名隨便),把需要的名稱和型別放進去 <?xml version="1.0" encoding="utf-8"?> <resources>
Android:自定義View實現水波進度效果
首先上效果圖: 簡介: 1.自動適應螢幕大小; 2.水波自動橫向滾動; 3.各種繪製引數可通過修改常量進行控制。 程式碼不多,註釋也比較詳細,全部貼上: (一)自定義元件: /** * 水波進度效果. */ public class WaterWaveView e
Android中自定義View的研究 -- 在XML中引用自定義View
如果在一直使用SetContentView(new HellwView(this)覺得總是少了一點東西,少了什麼了,失去了Android中使用XML定義元件的便攜性,這種感覺讓人很不爽,呵呵,在這節裡我們會看到一個自定義View報錯的解決方法,讓我們來看看在XML中定義Vi