`

Android双SurfaceView实现底部拍照,顶部绘图

 
阅读更多

 

当SurfaceHolder对象的类型设置为SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS时就只能拍照不能绘制了。
为了既能通过SurfaceView拍照又能在上面绘制图形,可以通过双SurfaceView层叠的变通方式如下:
用于绘制的SurfaceView,使其透明并位于顶部:

package com.test;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class SVDraw extends SurfaceView implements SurfaceHolder.Callback {

	private Bitmap bmp;
	private String imgPath = "";
	protected SurfaceHolder sh; // 专门用于控制surfaceView的
	private int width;
	private int height;

	// XML文件解析需要调用View的构造函数View(Context , AttributeSet)
	// 因此自定义SurfaceView中也需要该构造函数
	public SVDraw(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		sh = getHolder();
		sh.addCallback(this);
		sh.setFormat(PixelFormat.TRANSPARENT); // 设置为透明
		setZOrderOnTop(true);// 设置为顶端
	}

	@Override
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int w, int h) {
		// TODO Auto-generated method stub
		width = w;
		height = h;
	}

	@Override
	public void surfaceCreated(SurfaceHolder arg0) {
		// TODO Auto-generated method stub

	}

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

	}

	void clearDraw() {

		Canvas canvas = sh.lockCanvas();
		canvas.drawColor(Color.BLUE);// 清除画布
		sh.unlockCanvasAndPost(canvas);
	}

	/**
	 * 绘制
	 */
	public void doDraw() {
		if (bmp != null) {
			Canvas canvas = sh.lockCanvas();
			canvas.drawColor(Color.TRANSPARENT);// 这里是绘制背景
			Paint p = new Paint(); // 笔触
			p.setAntiAlias(true); // 反锯齿
			p.setColor(Color.RED);
			p.setStyle(Style.STROKE);
			canvas.drawBitmap(bmp, 0, 0, p);
			canvas.drawLine(width / 2 - 100, 0, width / 2 - 100, height, p);
			canvas.drawLine(width / 2 + 100, 0, width / 2 + 100, height, p);
			// ------------------------ 画边框---------------------
			Rect rec = canvas.getClipBounds();
			rec.bottom--;
			rec.right--;
			p.setColor(Color.GRAY); // 颜色
			p.setStrokeWidth(5);
			canvas.drawRect(rec, p);
			// 提交绘制
			sh.unlockCanvasAndPost(canvas);
		}

	}

	public void drawLine() {

		Canvas canvas = sh.lockCanvas();

		canvas.drawColor(Color.TRANSPARENT);// 这里是绘制背景
		Paint p = new Paint(); // 笔触
		p.setAntiAlias(true); // 反锯齿
		p.setColor(Color.RED);
		p.setStyle(Style.STROKE);
		canvas.drawLine(width / 2 - 100, 0, width / 2 - 100, height, p);
		canvas.drawLine(width / 2 + 100, 0, width / 2 + 100, height, p);

		// 提交绘制
		sh.unlockCanvasAndPost(canvas);
	}

	public String getImgPath() {
		return imgPath;
	}

	public void setImgPath(String imgPath) {
		this.imgPath = imgPath;
		// 根据路径载入目标图像
		bmp = BitmapFactory.decodeFile(imgPath);
	}

}

用于在SurfaceView(使其位于绘制SurfaceView底部)上拍照及预览的Activity:

package com.test;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import android.app.Activity;
import android.content.ContentValues;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;

import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.hardware.Camera.Size;

import android.media.AudioManager;
import android.media.ToneGenerator;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.SyncStateContract.Constants;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;

public class SurfaceViewDraw extends Activity implements
		SurfaceHolder.Callback, Camera.PictureCallback {
	/** Called when the activity is first created. */
	private SVDraw svDraw = null;
	private SurfaceView svCamera = null;
	protected SurfaceHolder mSurfaceHolder;

	private Button btnClear;
	private Button btnOpen;
	private Button btnClose;
	private Button btnTakePic;
	private Button btnDraw;

	private Camera mCamera; // 这个是hardware的Camera对象
	private boolean isOpen = false;// 相机是否打开
	private ToneGenerator tone;
	private String imgPath;

	private int width;
	private int height;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		hideStatusBar();
		setContentView(R.layout.main);
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);// 强制为横屏

		svDraw = (com.test.SVDraw) findViewById(R.id.svDraw);
		svCamera = (SurfaceView) findViewById(R.id.svCamera);

		btnClear = (Button) findViewById(R.id.btnClear);
		btnOpen = (Button) findViewById(R.id.btnOpen);
		btnClose = (Button) findViewById(R.id.btnClose);
		btnTakePic = (Button) findViewById(R.id.btnTakePic);
		btnDraw = (Button) findViewById(R.id.btnDraw);

		btnClear.setOnClickListener(new ClickEvent());
		btnOpen.setOnClickListener(new ClickEvent());
		btnClose.setOnClickListener(new ClickEvent());
		btnTakePic.setOnClickListener(new ClickEvent());
		btnDraw.setOnClickListener(new ClickEvent());

		mSurfaceHolder = svCamera.getHolder();
		mSurfaceHolder.addCallback(this);
		// 当设置为SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS后就不能绘图了
		mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

	}

	class ClickEvent implements View.OnClickListener {

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			if (v == btnClear) {

				stopPreview(); // 停止预览后清屏速度会快一点
				svDraw.setVisibility(View.INVISIBLE);
				startPreview();// 清屏后启动预览

			} else if (v == btnOpen) {

				initCamera();

			} else if (v == btnClose) {

				closeCamera();

			} else if (v == btnTakePic) {
				if (isOpen) {
					startPreview();// 防止异常
					mCamera.takePicture(mShutterCallback, null, null,
							mjpegCallback);
					svDraw.setVisibility(View.VISIBLE);
					svDraw.drawLine();// 拍照后绘制测线
				}
			} else if (v == btnDraw) {

				svDraw.setVisibility(View.VISIBLE);
				svDraw.doDraw();
			}
		}

	}

	ShutterCallback mShutterCallback = new ShutterCallback() {
		@Override
		public void onShutter() {
			// TODO Auto-generated method stub
			if (tone == null)
				// 发出提示用户的声音
				tone = new ToneGenerator(AudioManager.STREAM_MUSIC,
						ToneGenerator.MAX_VOLUME);
			tone.startTone(ToneGenerator.TONE_PROP_BEEP);

		}
	};
	/**
	 * Jpeg格式压缩
	 */
	PictureCallback mjpegCallback = new PictureCallback() {
		@Override
		// 取得拍照图片
		public void onPictureTaken(byte[] data, Camera camera) {
			// TODO Auto-generated method stub
			// 拍照前关闭预览
			mCamera.stopPreview();
			// 取得图像路径
			imgPath = saveFile2(data);
			svDraw.setImgPath(imgPath);

		}

	};

	/**
	 * draw information on the picture
	 * 
	 * @param imgPath
	 */
	public void drawInfo(String imgPath) {

		Bitmap bmp = BitmapFactory.decodeFile(imgPath);

		if (bmp != null) {
			Bitmap drawBmp = Bitmap.createBitmap(640, 480, Config.ARGB_8888);
			Canvas c = new Canvas(drawBmp);
			Paint p = new Paint();
			c.drawBitmap(bmp, 0, 0, p);
			String familyName = "Arial";
			Typeface font = Typeface.create(familyName, Typeface.NORMAL);
			p.setColor(Color.RED);
			p.setTypeface(font);
			p.setTextSize(20);
			p.setStyle(Paint.Style.STROKE);
			SimpleDateFormat dateFormat = new SimpleDateFormat(
					"yyyy-MM-dd hh:mm:ss");
			String strDate = dateFormat.format(new Date());
			c.drawText(strDate, 10, 30, p);

			try {
				saveBmp(drawBmp, imgPath);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	/**
	 * save bmp as jpg by path
	 * 
	 * @param bmpPath
	 * @param bmp
	 * @throws IOException
	 */
	public void saveBmp(Bitmap bmp, String fileName) throws IOException {

		File f = new File(fileName);
		f.createNewFile();
		FileOutputStream fOut = null;
		try {
			fOut = new FileOutputStream(f);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		bmp.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
		try {
			fOut.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			fOut.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * return imgFilePath
	 * 
	 * @param data
	 * @return
	 */
	private String saveFile2(byte[] data) {
		File imgFileDir = getDir();
		if (!imgFileDir.exists() && !imgFileDir.mkdirs()) {
			Log.v("directory", "Can't create directory to save image.");
			return null;
		}
		// 图像名称
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
		String strDate = dateFormat.format(new Date());
		String imgFileName = "img_" + strDate + ".jpg";
		// 图像路径
		String imgFilePath = imgFileDir.getPath() + File.separator
				+ imgFileName;
		File imgFile = new File(imgFilePath);
		try {
			FileOutputStream fos = new FileOutputStream(imgFile);
			fos.write(data);
			fos.close();
			Log.v("directory", "New Image saved:" + imgFile);

		} catch (Exception error) {
			Log.d(Constants.ACCOUNT_NAME,
					imgFileName + " not saved: " + error.getMessage());

		}
		//绘制拍照日期等
		drawInfo(imgFilePath);
        return imgFilePath;
	}

	/**
	 * 
	 * @return
	 */
	private File getDir() {
		File sdDir = Environment
				.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
		// 创建图像需要保存的文件夹
		return new File(sdDir, "Photo");

	}

	@Override
	public void onPictureTaken(byte[] data, Camera camera) {
		// TODO Auto-generated method stub
		// data是一个原始的JPEG图像数据,
		// 在这里我们可以存储图片,很显然可以采用MediaStore
		// 注意保存图片后,再次调用stopPreview()停止预览,等待测量
		Uri imageUri = this.getContentResolver().insert(
				MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
				new ContentValues());
		try {
			OutputStream os = this.getContentResolver().openOutputStream(
					imageUri);
			os.write(data);
			os.flush();
			os.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		// 拍照后停止预览
		mCamera.stopPreview();
	}

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

	}

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

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

	}

	/**
	 * 关闭相机
	 */
	public void closeCamera() {
		if (isOpen) {
			mCamera.stopPreview();
			mCamera.release();
			mCamera = null;
			isOpen = false;
		}
	}

	/**
	 * 停止拍照预览
	 */
	public void stopPreview() {
		if (isOpen) {
			mCamera.stopPreview();
		}
	}

	/**
	 * 启动拍照预览
	 */
	public void startPreview() {
		if (isOpen) {
			mCamera.startPreview();
		}
	}

	/**
	 * 初始化相机
	 */
	public void initCamera() {
		if (!isOpen) {
			mCamera = Camera.open();
		}
		if (mCamera != null && !isOpen) {
			try {
				Camera.Parameters mParameters = mCamera.getParameters();
				mParameters.setPictureFormat(PixelFormat.JPEG); // 设置照片格式
				List<Size> sizes = mParameters.getSupportedPreviewSizes();
				Size optimalSize = getOptimalPreviewSize(sizes, width, height);
				mParameters.setPreviewSize(optimalSize.width,
						optimalSize.height); // 大小
				mParameters.setPictureSize(optimalSize.width,
						optimalSize.height);

				mParameters.set("jpeg-quality", 100);// 照片质量
				// 首先获取系统设备支持的所有颜色特效,有复合我们的,则设置;否则不设置
				List<String> colorEffects = mParameters
						.getSupportedColorEffects();
				Iterator<String> colorItor = colorEffects.iterator();
				while (colorItor.hasNext()) {
					String currColor = colorItor.next();
					if (currColor.equals(Camera.Parameters.EFFECT_SOLARIZE)) {
						mParameters
								.setColorEffect(Camera.Parameters.EFFECT_SOLARIZE);
						break;
					}
				}
				mCamera.setParameters(mParameters);
				mCamera.setPreviewDisplay(mSurfaceHolder);
				mCamera.startPreview();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			isOpen = true;
		}
	}

	private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
		final double ASPECT_TOLERANCE = 0.05;
		double targetRatio = (double) w / h;
		if (sizes == null)
			return null;

		Size optimalSize = null;
		double minDiff = Double.MAX_VALUE;

		int targetHeight = h;

		// Try to find an size match aspect ratio and size
		for (Size size : sizes) {
			double ratio = (double) size.width / size.height;
			if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
				continue;
			if (Math.abs(size.height - targetHeight) < minDiff) {
				optimalSize = size;
				minDiff = Math.abs(size.height - targetHeight);
			}
		}

		// Cannot find the one match the aspect ratio, ignore the requirement
		if (optimalSize == null) {
			minDiff = Double.MAX_VALUE;
			for (Size size : sizes) {
				if (Math.abs(size.height - targetHeight) < minDiff) {
					optimalSize = size;
					minDiff = Math.abs(size.height - targetHeight);
				}
			}
		}
		return optimalSize;
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		if (isOpen) {
			closeCamera();
		}
	}

	// 在 Activity.setCurrentView()之前调用
	public void hideStatusBar() {
		// 隐藏标题
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		// 定义全屏参数
		int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
		// 获得窗口对象
		Window curWindow = this.getWindow();
		// 设置Flag标示
		curWindow.setFlags(flag, flag);
	}
}

主界面main.xml:

<?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="horizontal" >
   <!-- 对于自定义控件要指明的控件的包名与空间名,系统自带的控件不需要指定包名 -->
   <FrameLayout
       android:layout_width="640dip" 
       android:layout_height="480dip" 
       android:orientation="vertical" >
    <SurfaceView
      android:id="@+id/svCamera"
      android:layout_width="fill_parent" 
      android:layout_height="fill_parent"/>
    
    <com.test.SVDraw
     android:id="@+id/svDraw"
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent"/>
    
   </FrameLayout>
    
    <LinearLayout 
      android:id="@+id/LinearLayout01"
      android:layout_width="158dip" 
      android:layout_height="fill_parent"
      android:layout_marginLeft="1dip"
      android:layout_marginRight="1dip"
      android:orientation="vertical"
      android:background="@drawable/main_right_bg">
	    <Button 
		  android:id="@+id/btnOpen" 
		  android:layout_width="fill_parent"
		  android:layout_height="wrap_content" 
		  android:layout_marginTop="10dip"
		  android:text="打开相机"/>
	     <Button 
		  android:id="@+id/btnClose" 
		  android:layout_width="fill_parent"
		  android:layout_height="wrap_content" 
		  android:text="关闭相机"/>
	     <Button 
	        android:id="@+id/btnTakePic" 
		 android:layout_width="fill_parent"
		 android:layout_height="wrap_content" 
		 android:text="拍照"   />
	    <Button 
		 android:id="@+id/btnClear" 
		 android:layout_width="fill_parent"
		 android:layout_height="wrap_content" 
		 android:text="预览"/>	  
	    <Button 
		 android:id="@+id/btnDraw" 
		 android:layout_width="fill_parent"
		 android:layout_height="wrap_content" 
		 android:text="绘制"/>	     
	 
    </LinearLayout>
</LinearLayout>

在res下新建文件夹drawable,并在其下面新建面板背景main_right_bg.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
  <gradient
      android:startColor = "#666666"
      android:centerColor="#000FFF"
      android:endColor = "#666666"  
      android:angle = "270"/> 
  <corners 
      android:radius="4dip"/>
  
</shape>

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />
    
<!-- 照相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".SurfaceViewDraw"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


开发环境:XP3+Eclipse+Android2.2+JDK6.0
测试环境:Android2.2,5寸屏,分辨率640X480
源代码:http://download.csdn.net/detail/xinzheng_wang/4409755

 

 

 

 

分享到:
评论

相关推荐

    Android双SurfaceView底部拍照,顶部绘图

    Android双SurfaceView底部拍照,顶部绘图,当SurfaceHolder对象的类型设置为SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS时就只能拍照不能绘制了。为了既能通过SurfaceView拍照又能在上面绘制图形,可以通过双...

    Android SurfaceView 实现图片缩放 滑动

    在Android开发中,SurfaceView是一种特殊的视图,它允许开发者创建高性能的图形界面,尤其适合处理视频播放或游戏等需要连续刷新的场景。本话题主要探讨如何利用SurfaceView实现图片的缩放和滑动功能。 首先,理解...

    Android中SurfaceView截屏

    本文将详细介绍如何在Android中实现`SurfaceView`的截屏功能。 首先,了解`SurfaceView`的基本原理。`SurfaceView`创建了一个独立的窗口,并在自己的Surface上绘制内容。这使得它可以在后台线程进行高效的绘制,但...

    Android SurfaceView 实现实时显示摄像头视频

    `SurfaceView`是Android提供的一种用于高效显示多媒体数据的视图组件,尤其适合处理像视频流这样的实时数据。本篇文章将深入探讨如何利用`SurfaceView`实现实时显示摄像头视频。 首先,我们需要了解`SurfaceView`的...

    Android开发摄像头SurfaceView预览 背景画图(矩形和圆形) 实现(双surfaceview,顶层画矩形框,底层预览视频)

    Android开发摄像头SurfaceView预览 背景画图(矩形和圆形) 实现(双surfaceview,顶层画矩形框,底层预览视频); UI:三个按钮 预览 摄像 图片保存,预览界面 可以显示(矩形和圆形等图画)

    Android 通过SurfaceView 实现实时显示摄像头视频

    总之,通过SurfaceView实现实时显示摄像头视频是Android开发中的一个基础任务,涉及到对Android系统相机API的理解和使用,以及对SurfaceView生命周期的掌握。随着技术的发展,开发者可以选择更高级的API,如Camera2...

    Android使用SurfaceView实现墨迹天气的风车效果-IT计算机-毕业设计.zip

    本示例“Android使用SurfaceView实现墨迹天气的风车效果”是一个很好的学习资源,适用于毕业设计或论文研究。这个项目主要展示了如何利用Android的SurfaceView组件来创建类似墨迹天气应用中的风车动画效果。下面将...

    android SurfaceView实现人物动画

    在这个“android SurfaceView实现人物动画”的示例程序中,我们将深入探讨如何利用SurfaceView来创建流畅的人物动画。 1. **SurfaceView基本概念** SurfaceView是一个可以独立于应用程序主线程更新的视图,它有...

    Android使用SurfaceView实现墨迹天气的风车效果

    "Android使用SurfaceView实现墨迹天气的风车效果"是一个典型的案例,它展示了如何利用Android的SurfaceView组件来创建动态、流畅的动画效果,以模拟类似墨迹天气App中的风车转动。SurfaceView是Android系统提供的一...

    android surfaceview自定义拍照 绘制头像轮廓

    这个项目"android surfaceview自定义拍照 绘制头像轮廓"是基于网上现有的示例代码进行了修改,用于实现一个自定义的拍照功能,并且在拍摄的照片上能够绘制出人像的轮廓。下面我们将深入探讨`SurfaceView`以及如何...

    Android圆形相机预览窗口,圆形SurfaceView

    总结起来,实现Android圆形相机预览窗口需要对SurfaceView有深入的理解,包括如何自定义视图、绘制路径以及与相机的交互。通过这个过程,开发者不仅可以创建独特的用户界面,还能提升应用程序的创新性和用户体验。在...

    android surfaceView 双缓冲

    android使用双缓冲辨析及surfaceview使用例子

    Android应用源码之Android使用SurfaceView实现墨迹天气的风车效果.zip

    在Android应用开发中,SurfaceView是一个非常重要的组件,它提供了在主线程之外进行绘图的能力,使得复杂的动画和游戏能够流畅运行。本压缩包“Android应用源码之Android使用SurfaceView实现墨迹天气的风车效果.zip...

    Android SurfaceView实现动画效果

    在Android开发中,SurfaceView是一种特殊的视图,它允许开发者在单独的线程中进行高性能的图形绘制,常用于游戏或者视频播放等需要连续更新显示内容的场景。本篇文章将详细探讨如何利用SurfaceView实现动画效果,...

    android之surfaceview学习示例

    在Android开发中,SurfaceView是一个非常重要的视图组件,它为开发者提供了在应用程序中实现高性能图形渲染的能力。SurfaceView的设计初衷是为了处理那些需要频繁更新且对性能要求较高的场景,如视频播放、游戏画面...

    Android自定义SurfaceView——实现画板功能

    本示例中的“Android自定义SurfaceView——实现画板功能”旨在教你如何利用`SurfaceView`创建一个可以画画的应用。`SurfaceView`是Android系统提供的一种用于高效显示动态图像的视图组件,它拥有自己的渲染线程,...

    安卓Android源码——安卓Android使用SurfaceView实现墨迹天气的风车效果.zip

    在安卓应用开发中,SurfaceView 是一个非常重要的组件,它为开发者提供了在应用程序中实现高性能图形渲染的能力。这个源码示例是关于如何利用SurfaceView来实现类似墨迹天气应用中的风车动态效果。让我们深入探讨...

    android surfaceview 悬浮窗圆角 windowmanager

    在Android开发中,`SurfaceView`是一个特殊类型的`View`,它允许开发者在应用程序中创建一个独立于应用程序主线程的渲染表面。`SurfaceView`通常用于处理高性能的图形或者视频播放,因为它可以在单独的线程中进行...

    Android双重SurfaceView实现弹幕效果

    Android 双重 SurfaceView 实现弹幕效果 Android 双重 SurfaceView 实现弹幕效果是指在 Android 平台上使用双重 SurfaceView 来实现弹幕效果的技术。弹幕是一种常见的视频播放效果,能让用户在视频播放时发送弹幕...

    Android SurfaceView实现人物动画

    在Android开发中,SurfaceView是一种特殊的视图,它允许开发者在应用程序中创建高性能的图形界面,特别是用于实现动画效果,如游戏或者视频播放等。SurfaceView拥有自己的绘图表面,与主线程分离,因此在处理复杂的...

Global site tag (gtag.js) - Google Analytics