android_SurfaceView 画图

有这样一种view类,可以让人在其上面画动画,画图片,它的全名叫做surfaceview。名称就包含两层意思,一层是surface,一层是view。前一层提供一个面可以让人画画,后一层是个view,可以将画画显示出来。

一般view类也有个draw方法,但是不能用来画画。上网找了很多资料,说的啰嗦,都没有说明白。我总结了下,其实网上说的意思是,主线程,也就是跑activity活动的线程,它要先在界面把几个view显示出来(也就是绘出来),而且是后,然后与用户交互。如果在几个普通view画画的话,如果画画时间很长的话,你想,activity就一直在画画,都不理用户的,谁吃得消,所以就出现surfaceView。这个玩意儿就是activity用一个holder来控制,activity一边与用户交互,一边用holder在上面画画,两者都不耽误。

引用网上一句话:

SurfaceView它用于显示,SurfaceHolder就是用于用来管理这个显示的SurfaceView对象的,但在SurfaceHolder是怎么样去管理这个对象的呢?这就用到了SurfceHolder.addCallback()方法添加一个SurfaceHolder接口的内部接口的三个抽象方法用于管理或者说是用于监听SurfaceView。这样就达到了管理SurfaceView的目的。

主文件

package cn.com.sxp;

import android.app.Activity;
import android.os.Bundle;

public class SurfaceViewActivity extends Activity {
private sxpView sv= null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

sv =(cn.com.sxp.sxpView)findViewById(R.id.sxpView);
}
}

以前用自带的控件用多了,都习惯写上(Button)find....其实也可以自己定义控件,将xml文件布局控件与程序控件联系起来,只是要写上自定义控件的全路径。

surfaceView文件

package cn.com.sxp;

import java.util.Vector;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class sxpView extends SurfaceView implements SurfaceHolder.Callback {
// 实现SurfaceHolder.Callback接口,到时候surfaceView被创建、销毁什么的,都会调用这个接口的回调方法.
// A client may implement this interface to receive information about changes to the surface. When used with a SurfaceView, the Surface being held is only
// available between calls to surfaceCreated(SurfaceHolder) and surfaceDestroyed(SurfaceHolder). The Callback is set with SurfaceHolder.addCallback method.
// 每个surfaceView都要有surfaceHolder这么个组件,这个组件用来控制和访问surfaceView
private SurfaceHolder sh = null; // 专门用于控制surfaceView的
private Vector<Float> xAxis = new Vector<Float>();
private Vector<Float> yAxis = new Vector<Float>();

// XML文件解析需要调用View的构造函数View(Context , AttributeSet)因此自定义SurfaceView中也需要该构造函数
public sxpView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
// 是surfaceView的一个方法. Return the SurfaceHolder providing access and control over this SurfaceView's underlying surface.
sh = getHolder();
// Add a Callback interface for this holder. There can several Callback interfaces associated with a holder.
// addCallback方法就是指定了surfaceChanged等方法称为回调函数; 而所谓的实现SurfaceHolder.Callback接口就是让你实现surfaceChanged等接口
sh.addCallback(this);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
new Thread(new sxpLoop()).start();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub

}

public void doDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.drawColor(Color.GRAY);// 这里是绘制背景
Paint p = new Paint(); // 笔触
p.setAntiAlias(true); // 反锯齿
p.setColor(Color.BLUE);
p.setStyle(Style.STROKE);
for (int i = 0; i < xAxis.size(); i++)
canvas.drawCircle(xAxis.elementAt(i), yAxis.elementAt(i), 10, p);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
// Implement this method to handle touch screen motion events.
if (event.getAction() == MotionEvent.ACTION_DOWN) {
xAxis.add(event.getX());
yAxis.add(event.getY());
}
return true;
}

class sxpLoop implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
// 在绘图时,必须首先用Canvas c=holder.lockCanvas();锁定并获得画布,随后进行绘制,再调用holder.unlockCanvasAndPost(c);将绘制内容进行呈现
Canvas c = sh.lockCanvas();
doDraw(c);
sh.unlockCanvasAndPost(c);
Thread.sleep(20);
} catch (Exception e) {

}
}
}
}

}

自定义的控件必须要继承surfaceView类,同时实现surfaceHolder.Callback接口。surfaceView就是通过这个接口来控制的,什么接口,就是类似于onCreated...等。代码中还有个addCallback(this),就是增加这个自定义类作为参数,学术上叫做添加接口,个人呢理解就是onCreated...几个接口在自定义类中实现,所以就添加这个类作为参数了。

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width
="fill_parent"
android:layout_height
="fill_parent"
android:orientation
="vertical" >
<!-- 这种用法应该学习,布局中摆放的是控件,也可以摆放我自定义的控件. 但是我要指明我的控件的包名与空间名. 系统自带的控件不需要指定包名 -->
<cn.com.sxp.sxpView
android:id="@+id/sxpView"
android:layout_width
="fill_parent"
android:layout_height
="fill_parent"
/>

</LinearLayout>

布局文件中不但可以用自带控件,还可以使用自定义控件,那叫一个爽~~~

运行结果




原文地址:https://www.cnblogs.com/itblog/p/2313645.html