自定义控件(SurfaceView与view结合)
作者:Legend
QQ:158067568
上一节小试牛刀,介绍了一个简单的SurfaceView的例子,如果用于实际开发,那还差得远呢。本节介绍SurfaceView与View结合使用的例子,SurfaceView部分与球类稍作改动,这里就不在赘述。主要介绍一下如何在View中成功的把SurfaceView添加进来,并且通过widget中默认的控件来操作自定义的SurfaceView。
View中添加SurfaceView
还记得我上一节中的SurfaceView类BallSurfaceView的构造方法么?BallSurfaceView(Context context)没错就是这个,但是如果我们要在view中添加,还是用这个构造方法就会报错。感谢mars老师的Android群,里面的大虾们帮我解决了这个问题。
其实只要使用如下构造方法,然后注意几点就ok了。
public BallSurfaceView(Context context, AttributeSet attrs) {
super(context,attrs);
…..
就是上面的构造方法,是符合view的。AttributeSet是提供一些设置的类,可以参考API。
但是值得注意的是,不要再SurfaceView中去绑定View,这样会带来意想不到的错误。
实现
我将把代码全部贴出,供大家参考。
package cn.edu.heut.zcl;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class BallSurfaceView extends SurfaceView
implements SurfaceHolder.Callback{
// SportActivity sportActivity ;//调用该SurfaceView的上下文引用
private Ball ball ;//小球
public static final int initX = 100;
public static final int initY = 100;
SurfaceHolder holder ;
public int screenWidth ;
public int screenHeight ;
public BallSurfaceView(Context context, AttributeSet attrs) {
super(context,attrs);
ball = new Ball(initX, initY, this);
holder = this.getHolder();
holder.addCallback(this);
//获得屏幕尺寸
DisplayMetrics dm = new DisplayMetrics();
dm = context.getApplicationContext().getResources().getDisplayMetrics();
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(canvas == null) canvas = holder.lockCanvas();//锁定画布
Paint p = new Paint();
int c = p.getColor();
p.setColor(Color.WHITE);//设置背景白色
if(canvas != null)
canvas.drawRect(0, 0, screenWidth, screenHeight, p);
p.setColor(c);
ball.onDraw(canvas);
holder.unlockCanvasAndPost(canvas);//释放锁
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
new RefreshThread().start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void setStop(){
ball.setStop(true);
}
public void setStart(){
ball.setStop(false);
}
public void setRestart(){
ball.setPosition(initX, initY);
ball.setMaxHeight(initY);
}
private class RefreshThread extends Thread{
@Override
public void run() {
while(true){
Canvas canvas = null;
try{
onDraw(canvas);
}catch(Exception e){
e.printStackTrace();
}
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
package cn.edu.heut.zcl;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.DisplayMetrics;
/**
* 球类
* @author zcl
*
*/
public class Ball {
/**
* 球的高
*/
public static final int HEIGHT = 93;
/**
* 球的宽
*/
public static final int WIDTH = 93;
private static final int STEPLENGTH = 10;//每次运动的间距
private static final float REDUCEPERCENTAGE = 0.35F;//递减系数
private int stepReduce ;//每次反向运动的缩短的距离
private boolean stop = false;
public void setStop(boolean stop) {
this.stop = stop;
}
private float runX ;//球的位置
private float runY ;//球的位置
private BallSurfaceView bsv ;
private boolean upDirection = false;//if true,up direction,or is down direction
private float maxHeight ;//当前运动最高的高度
private Paint paint ;
Bitmap ballBitmap ;//球的图片
public Ball(float initX , float initY , BallSurfaceView bsv){
this.runX = initX;
this.runY = initY ;
maxHeight = initY;
this.bsv = bsv;
ballBitmap = BitmapFactory.decodeResource(bsv.getResources(), R.drawable.ball);//加载图片
paint = new Paint();
}
public void onDraw(Canvas canvas) {
int c = paint.getColor();//保存颜色,之后还原为之前颜色
if( !stop ) boundaryTest();
if(canvas != null) canvas.drawBitmap(ballBitmap,runX,runY,paint);
paint.setColor(c);
if( !stop ) move();
}
/**
* 运动
*/
private void move() {
if(maxHeight >= (bsv.screenHeight - HEIGHT)) {
return;
}
if(upDirection){//向上
runY = runY + STEPLENGTH ;
}else{
runY = runY - STEPLENGTH ;
}
}
/**
* 边界检测,使球不会飞出边界
*/
private void boundaryTest(){
if(runY > bsv.screenHeight - HEIGHT){//向下运动到头
upDirection = !upDirection;//方向置反
runY = bsv.screenHeight - HEIGHT;
stepReduce = (int) (maxHeight * REDUCEPERCENTAGE);
maxHeight = maxHeight + stepReduce ;//最大高度递减
}
if(runY < maxHeight ){//向上运动到头
upDirection = !upDirection;//方向置反
if(maxHeight >= (bsv.screenHeight - HEIGHT)) return;
runY = maxHeight ;
}
}
public void setPosition(float x,float y){
this.runX = x;
this.runY = y;
}
public void setMaxHeight(float y){
this.maxHeight = y;
}
}
package cn.edu.heut.zcl;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
public class SportActivity extends Activity {
Button butStop;
Button butStart;
Button butRestart;
BallSurfaceView bsv ;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// bsv = new BallSurfaceView(this);
//下两句为设置全屏
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN ,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
butStop =(Button)findViewById(R.id.butStop);
butStop.setOnClickListener(new listener());
butStart =(Button)findViewById(R.id.butStart);
butStart.setOnClickListener(new listener());
butRestart =(Button)findViewById(R.id.butRestart);
butRestart.setOnClickListener(new listener());
bsv = (BallSurfaceView) findViewById(R.id.ballSurfaceView);
}
class listener implements View.OnClickListener{
@Override
public void onClick(View v) {
Button but = (Button)v;
switch(but.getId()){
case R.id.butStop:
bsv.setStop();
break;
case R.id.butStart:
bsv.setStart();
break;
case R.id.butRestart:
bsv.setRestart();
break;
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<Button android:id="@+id/butStop"
android:text="stop"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
>
</Button>
<Button android:id="@+id/butStart"
android:text="Start"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
>
</Button>
<Button android:id="@+id/butRestart"
android:text="ReStart"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
>
</Button>
</LinearLayout>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<cn.edu.heut.zcl.BallSurfaceView
android:id="@+id/ballSurfaceView"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</cn.edu.heut.zcl.BallSurfaceView>
</FrameLayout>
</LinearLayout>
有问题的留言,篮球运动是直接修改的上一节的例子,需要代码的留下邮箱。