編輯:關於android開發
該系列教程概述與目錄:http://www.cnblogs.com/chengyujia/p/5787111.html
在上篇教程中我們實現了左邊的三角形按鈕效果,本篇教程我們將左、上、右、下四個三角形按鈕都一起實現了。
能做出一個來,另外三個應該不難了吧?但實際並非怎麼簡單哦。
首先我們來解決一下上節課遺留的一個問題,如何判斷當前手指點擊的是哪個三角形按鈕?
這個需要用解析幾何大法來解決。
假設我們的控件是邊長為1的正方形,建立平面直角坐標系(注意:計算機中坐標系原點在左上角哦),如下圖:
正方形的對角線將控件分成了4個三角形區域,也就是我們的4個方向鍵按鈕。
據上圖可知:
左上角到右下角對角線的方程為y=x;
y>x的區域包含左和下三角形
y<x的區域包含右和上三角形
右上角到左下角的對角線方程為y=-x+1;
y>1-x的區域包含右和下三角形
y<1-x的區域包含左和上三角形
綜上可得:
y>x 且 y<1-x 表示左三角
y<x 且 y<1-x 表示上三角
y<x 且 y>1-x 表示右三角
y>x 且 y>1-x 表示下三角
以上是按照邊長為1的正方形得到的結論,但實際中,我們的控件不一定是正方形,邊長也不是1,而是一個不確定的矩形,這該怎麼辦呢?
這就需要經過一定的轉換,將普通的矩形轉換為邊長為1的正方形。
這個轉變也簡單,如下:
設畫布上被觸摸到的點的坐標為(x,y),則:
float relativeX = x / width;//0<=relativeX<=1
float relativeY = y / height;//0<=relativeY<=1
我們將畫布上被觸摸的點的橫縱坐標分別除以畫布的寬和高,這樣就得到了一個相對坐標,而這個相對坐標的取值一定在0到1之間。這樣就相當於把一個不確定的矩形簡化成了一個邊長為1的正方形處理。
有了上面的了解,下面就可以寫代碼了。由於有4個三角形按鈕,而每個按鈕又有兩種狀態,代碼會稍微長點。但每個按鈕的邏輯都是一樣的,都是按哪個那個高亮,不按時都恢復正常狀態。代碼中的注釋比較詳細,相信大家如果看了前面的教程內容,看這個應該問題不大。唯一需要注意的是每次調用invalidate方法重繪界面時,是需要對整個畫布都重繪的,而不能只重繪一個三角形。
這裡我們需要先引入一個表示方向的枚舉:Direction
package net.chengyujia.happysnake;
/**
* 用來表示方向的枚舉
* Created by ChengYuJia on 2016/8/21.
*/
public enum Direction {
//none表示沒有方向鍵按下
none,
//左
left,
//上
up,
//右
right,
//下
down;
}
下面是當前DirectionKeys的完整代碼:
package net.chengyujia.happysnake;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* 屏幕上的虛擬方向鍵
* Created by ChengYuJia on 2016/8/19.
*/
public class DirectionKeys extends View {
//左三角形按壓時的顏色(較亮)
private int leftPressedColor = 0xFFFF0000;
//左三角形正常顯示的顏色(較暗)
private int leftNormalColor = 0xFFAA0000;
//上三角形按壓時的顏色(較亮)
private int upPressedColor = 0xFF00FF00;
//上三角形正常顯示的顏色(較暗)
private int upNormalColor = 0xFF00AA00;
//右三角形按壓時的顏色(較亮)
private int rightPressedColor = 0xFF0000FF;
//右三角形正常顯示的顏色(較暗)
private int rightNormalColor = 0xFF0000AA;
//下三角形按壓時的顏色(較亮)
private int downPressedColor = 0xFFFFFF00;
//下三角形正常顯示的顏色(較暗)
private int downNormalColor = 0xFFAAAA00;
//畫筆
private Paint paint = new Paint();
//畫左三角形的路徑
private Path pathLeft = new Path();
//畫上三角形的路徑
private Path pathUp = new Path();
//畫右三角形的路徑
private Path pathRight = new Path();
//畫下三角形的路徑
private Path pathDown = new Path();
//畫布的寬
private int width;
//畫布的高
private int height;
//初始化方法是否執行過,確保初始化方法只執行一次。
private boolean initDone = false;
//記錄當前哪個方向鍵被按下
private Direction currentDirection = Direction.none;
//只有一個參數的構造方法是我們在程序中通過“new”關鍵字創建實例時調用。
public DirectionKeys(Context context) {
super(context);
}
//有兩個參數的構造方法是系統在XML布局文件中創建實例時調用。
public DirectionKeys(Context context, AttributeSet attrs) {
super(context, attrs);
}
//初始化方法
private void init(Canvas canvas) {
/*獲取畫布的長和寬*/
width = canvas.getWidth();
height = canvas.getHeight();
/*
(小提示:在計算機中一般都是將左上角作為坐標原點的)
畫布上四個頂點和中心點的坐標如下:
左上點 0,0
左下點 0,height
右上點 width,0
右下點 width,height
中心點 width/2,height/2
*/
/*設置左三角形的路徑數據*/
//從畫布左上點開始
pathLeft.moveTo(0, 0);
//畫直線到畫布中心點
pathLeft.lineTo(width / 2, height / 2);
//再畫直線到畫布左下點
pathLeft.lineTo(0, height);
//自動閉合圖形。從最後一個點(左下點)畫直線到第一個點(左上點)。
pathLeft.close();
/*同理設置上三角形的路徑數據*/
pathUp.moveTo(0, 0);
pathUp.lineTo(width / 2, height / 2);
pathUp.lineTo(width, 0);
pathUp.close();
/*同理設置右三角形的路徑數據*/
pathRight.moveTo(width, 0);
pathRight.lineTo(width / 2, height / 2);
pathRight.lineTo(width, height);
pathRight.close();
/*同理設置下三角形的路徑數據*/
pathDown.moveTo(width, height);
pathDown.lineTo(width / 2, height / 2);
pathDown.lineTo(0, height);
pathDown.close();
}
//畫路徑的共用方法
private void drawPath(Path path, int color, Canvas canvas) {
//設置畫筆顏色
paint.setColor(color);
//用畫筆在畫布上按照路徑數據畫出圖形
canvas.drawPath(path, paint);
}
//畫左三角正常顏色
private void drawLeftNormal(Canvas canvas) {
drawPath(pathLeft, leftNormalColor, canvas);
}
//畫左三角按壓顏色(高亮)
private void drawLeftPressed(Canvas canvas) {
drawPath(pathLeft, leftPressedColor, canvas);
}
//畫上三角正常顏色
private void drawUpNormal(Canvas canvas) {
drawPath(pathUp, upNormalColor, canvas);
}
//畫上三角按壓顏色(高亮)
private void drawUpPressed(Canvas canvas) {
drawPath(pathUp, upPressedColor, canvas);
}
//畫右三角正常顏色
private void drawRightNormal(Canvas canvas) {
drawPath(pathRight, rightNormalColor, canvas);
}
//畫右三角按壓顏色(高亮)
private void drawRightPressed(Canvas canvas) {
drawPath(pathRight, rightPressedColor, canvas);
}
//畫下三角正常顏色
private void drawDownNormal(Canvas canvas) {
drawPath(pathDown, downNormalColor, canvas);
}
//畫下三角按壓顏色(高亮)
private void drawDownPressed(Canvas canvas) {
drawPath(pathDown, downPressedColor, canvas);
}
//所有按鈕恢復正常顏色
private void reset(Canvas canvas) {
drawLeftNormal(canvas);
drawUpNormal(canvas);
drawRightNormal(canvas);
drawDownNormal(canvas);
}
//當按左三角時,左三角高亮,其它正常。
private void drawWhenLeftPressed(Canvas canvas) {
drawLeftPressed(canvas);
drawUpNormal(canvas);
drawRightNormal(canvas);
drawDownNormal(canvas);
}
//當按上三角時,上三角高亮,其它正常。
private void drawWhenUpPressed(Canvas canvas) {
drawLeftNormal(canvas);
drawUpPressed(canvas);
drawRightNormal(canvas);
drawDownNormal(canvas);
}
//當按右三角時,右三角高亮,其它正常。
private void drawWhenRightPressed(Canvas canvas) {
drawLeftNormal(canvas);
drawUpNormal(canvas);
drawRightPressed(canvas);
drawDownNormal(canvas);
}
//當按下三角時,下三角高亮,其它正常。
private void drawWhenDownPressed(Canvas canvas) {
drawLeftNormal(canvas);
drawUpNormal(canvas);
drawRightNormal(canvas);
drawDownPressed(canvas);
}
/**
* 通過重寫父類的onDraw方法來繪制我們需要的圖形
* 該方法會在控件第一次顯示時被系統調用,並在之後每次調用invalidate方法後被系統調用。
*
* @param canvas 這裡的canvas是系統提供的一塊矩形畫布,我們要做的就是在這塊畫布上畫我們想要的東西。
*/
@Override
protected void onDraw(Canvas canvas) {
if (!initDone) {
init(canvas);
//確保初始化方法只執行一次
initDone = true;
}
//按下不同的方向鍵,繪制不同的界面效果。
switch (currentDirection) {
case left://按下左鍵時
drawWhenLeftPressed(canvas);
break;
case up://按下上鍵時
drawWhenUpPressed(canvas);
break;
case right://按下右鍵時
drawWhenRightPressed(canvas);
break;
case down://按下下鍵時
drawWhenDownPressed(canvas);
break;
default://其它情況
reset(canvas);
}
}
/**
* 當用戶觸摸到該控件時,系統通過該方法告訴控件“你被摸了,要不要有反應啊?有反應返回true,沒反應返回false。”
* 控件說“那要看是怎麼摸的了。如果是按下,我就將對應的三角形按鍵高亮顯示;如果是抬起,我就將所有的三角形按鍵恢復成正常的顏色。其它情況我就不反應了,摸就摸吧。”
*
* @param event 系統給我們傳遞的觸摸事件參數
* @return 如果該觸摸事件被我們處理了返回true,反之返回false。
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
//獲取當前的觸摸動作
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {//按下
//獲取觸摸點的坐標
float x = event.getX();
float y = event.getY();
currentDirection = getDirection(x, y);
invalidate();//重繪
return true;
} else if (action == MotionEvent.ACTION_UP) {//抬起
currentDirection = Direction.none;
invalidate();//重繪
return true;
} else {//其它不處理
return false;
}
}
//根據坐標判斷哪個三角形方向鍵被按下
private Direction getDirection(float x, float y) {
//經過坐標轉換,統一成邊長為1的正方形處理。對角線分割形成的4個區域,分別代表4個方向。
float relativeX = x / width;//0<=relativeX<=1
float relativeY = y / height;//0<=relativeY<=1
/*
注意:原點是左上角。
左上角到右下角對角線方程為y=x;
則:
y>x的區域包含左和下三角形
y<x的區域包含右和上三角形
左下角到右上角對角線方程為y=-x+1;
則:
y>1-x的區域包含右和下三角形
y<1-x的區域包含左和上三角形
綜上可得:
y>x 且 y<1-x 表示左三角
y<x 且 y<1-x 表示上三角
y<x 且 y>1-x 表示右三角
y>x 且 y>1-x 表示下三角
*/
if (relativeY > relativeX) {//左和下
if (relativeY < 1 - relativeX) {//左
return Direction.left;
} else {//下
return Direction.down;
}
} else {//上和右
if (relativeY < 1 - relativeX) {//上
return Direction.up;
} else {//右
return Direction.right;
}
}
}
}
沒有點擊時的效果:

點擊左鍵時的效果:

點擊上建時的效果:

點擊右鍵時的效果:

點擊下鍵時的效果:

到這裡,我們的自定義方向鍵的4個背景三角形已經做好了,而且實現了點擊變色的按鈕效果。
後面我們會在這4個三角形上都畫上相應的箭頭,同樣也有點擊變色的效果哦。敬請期待o(^▽^)o
Android Studio安裝與使用,androidstudio安裝
Android Studio安裝與使用,androidstudio安裝 2013年谷歌推出android studio後,單獨支持android開發,這是基於Java語
Android NDK開發初識,androidndk初識
Android NDK開發初識,androidndk初識 神秘的Android NDK開發往往眾多程序員感到興奮,但又不知它為何物,由於近期開發應用時,為了是開發的.a
手把手搭建自己的android環境,把手搭建android
手把手搭建自己的android環境,把手搭建android最近想學習安卓,不過國內實在被牆的厲害,真是萬裡安裝只被牆。安裝的過程中也出現了幾個問題。所以記錄下來,免得自己
淺談Android 通過ADB Wireless無線調試應用
淺談Android 通過ADB Wireless無線調試應用 使用數據線調試應用難免不方便,本篇博客介紹使用ADB Wireless工具,當手機和電腦處在同一網絡下,實現