編輯:關於Android編程
SurfaceView是Android中極為重要的繪圖容器,SurfaceView的圖像繪制是放在主線程之外的另一個線程中完成的。除了繪圖,SurfaceView還能播放視頻。
實現Android的自定義SurfaceView,需要新建一個繼承於SurfaceView的類,並且重寫至少一種構造器,在構造器中,需要同過getHolder()方法得到一個SurfaceViewHolder類的對象holder,canvas畫布通過holder調用lockCanvas()方法鎖定並得到,用完畫布後需要holder調用unlockCanvasAndPost(canvas)方法解鎖畫布。在構造方法中,holder還必須通過addCallback()方法實現監聽器,監聽器中需要實現的方法有三個:surfaceCreated()、surfaceChanged()、surfaceDestroyed()。自定義SurfaceView的圖像需要在surfaceCreated()方法中繪制。
用SurfaceView繪制一個指北針的模型,並結合加速度傳感器和地磁傳感器讓它動起來
/**
* 自定義SurfaceView繪制一個指南針
* 繼承於SurfaceView,並實現它的構造器
* 實現SurfaceHolder.Callback接口,實現surfaceCreated、surfaceChanged、surfaceDestroyed方法
*/
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder holder;
private Canvas canvas;
private Path path;
private Paint mPaintCircle;
private Paint mPaintLine;
private Paint mPaintText;
private int width;
private int height;
private float degree;
private boolean isDrawing = true;
private SensorManager sensorManager;
private float lastDegree;
public float getDegree() {
return degree;
}
public void setDegree(float degree) {
this.degree = degree;
}
public MySurfaceView(Context context) {
super(context);
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
width = 1100;
height = 1500;
//首先得到一個SurfaceHolder對象
holder = getHolder();
//接著讓holder添加Callback監聽器
holder.addCallback(this);
//path用於畫指針
path = new Path();
//畫外環的畫筆
mPaintCircle = new Paint();
mPaintCircle.setColor(Color.BLACK);
mPaintCircle.setStyle(Paint.Style.FILL_AND_STROKE);
mPaintCircle.setStrokeWidth(30);
//畫刻度線的畫筆
mPaintLine = new Paint();
mPaintLine.setColor(Color.WHITE);
mPaintLine.setStyle(Paint.Style.FILL);
mPaintLine.setStrokeWidth(10);
//畫文本的畫筆
mPaintText = new Paint();
mPaintText.setTextSize(70);
mPaintLine.setTextAlign(Paint.Align.LEFT);
mPaintText.setColor(Color.WHITE);
//sensorManager用於管理傳感器
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
//地磁傳感器
Sensor magneticSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
//加速度傳感器
Sensor accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//分別給兩種傳感器注冊監聽器
sensorManager.registerListener(listener, magneticSensor, SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(listener, accelerometerSensor, SensorManager.SENSOR_DELAY_GAME);
}
@Override
public void surfaceCreated(final SurfaceHolder holder) {
/**
* 在一個線程中進行繪制
*/
new Thread(new Runnable() {
@Override
public void run() {
//用一個無限循環,便於隨時改變圖形
while(isDrawing) {
canvas = holder.lockCanvas();
canvas.drawColor(Color.BLUE);
canvas.drawCircle(width / 2, height / 2, 400, mPaintCircle);
for (int i = 0; i <= 35; i++) {
canvas.save();
canvas.rotate(10*i+degree,width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 - 400, width / 2, height / 2 - 400 + 50, mPaintLine);
if (i == 0) {
canvas.drawText(N, width / 2, height / 2 - 400 - 40, mPaintText);
}else if(i == 8){
canvas.drawText(E , width / 2, height / 2 -400 -40, mPaintText);
}else if(i == 17){
canvas.drawText(S , width / 2, height / 2 -400 -40, mPaintText);
}else if(i == 26){
canvas.drawText(W , width / 2, height / 2 -400 -40, mPaintText);
}
canvas.restore();
}
//每當degree發生改變,canvas畫布都會轉動相應的角度
canvas.rotate(degree,width / 2, height / 2);
//繪制指針
path.moveTo(width / 2 - 10, height / 2);
path.lineTo(width / 2, height / 2 - 150);
path.lineTo(width / 2 + 10, height / 2);
path.close();
canvas.drawPath(path, mPaintLine);
//每次用完canvas,都要調用unlockCanvasAndPost()解鎖一次
holder.unlockCanvasAndPost(canvas);
}
}
}).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
/**注銷
* 當調用surfaceDestroyed方法時,停止線程中的死循環,並且sensorManager的監聽器
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isDrawing = false;
if(sensorManager!=null){
sensorManager.unregisterListener(listener);
}
}
//監聽傳感器
private SensorEventListener listener = new SensorEventListener() {
float[] accelerometerValues = new float[3];
float[] magneticValues = new float[3];
@Override
public void onSensorChanged(SensorEvent event) {
if(event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
accelerometerValues = event.values.clone();
}else if(event.sensor.getType()==Sensor.TYPE_MAGNETIC_FIELD){
magneticValues = event.values.clone();
}
float[] R = new float[9];
float[] values = new float[3];
//得到包含旋轉矩陣的R數組
SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticValues);
//計算手機的旋轉數據,並將參數存入values數組
SensorManager.getOrientation(R, values);
//將弧度轉換為角度
degree = -(float) Math.toDegrees(values[0]);
if(Math.abs(degree-lastDegree)>10){
lastDegree = degree;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
}
在xml布局中定義這個自定義SurfaceView
主活動:
public class SouthArrowActivity extends Activity {
private MySurfaceView mySurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_source);
mySurfaceView = (MySurfaceView) findViewById(R.id.my_surfaceView);
}
}
結果演示(必須在真機上才能運行):
看到沒,我的指北針多麼簡約大氣。
一個簡單的例子:重寫自定義View的onDraw()代碼: oval.left=getMeasuredWidth()/2-radius;
效果圖如下所示:一、shape 樣式:(在drawable新建--》new--》Drawable resource file 在父級標簽selector添加Item )&
網站中為了防止惡意獲取驗證短信、驗證郵箱,都會在點擊獲取驗證碼的按鈕上做個倒計時的效果,如何實現這個效果,具體內容如下效果圖: 代碼:RegisterActiv
前言 用過微信的都知道,微信對話列表滑動刪除效果是很不錯的,這個效果我們也可以有。思路其實很簡單,弄個ListView,然後裡面的每個item做成一個可以滑動的