关于SurfaceView的简单介绍

1.SurfaceView简介:

SurfaceView与普通的View的区别就是View视图必须在当前UI线程中进行,这也是在更新View组件时总要采用Handler处理的原因;但SurfeceView不会存在这个问题,它的绘图是由SurfaceHolder来完成的,SurfaceHolder会启动新的线程去更新SurfaceView的绘制,不会阻塞主UI线程。一般而言,如果程序中或游戏界面中的动画元素较多,而且很多动画元素都需要通过定时器来控制,就可以考虑使用SurfaceView而不是View。

2.SurfaceView的使用:

使用SurfaceView时,需要在新建线程去更新UI。其使用步骤如下:
1.用findViewById获取SurfaceView实例
2.用其getHolder方法取得holder实例
3.利用holder的holder.lockCanvas()封锁并获取Canvas实例
4.在Canvas上绘制相应图形
5.用holder.unlockCanvasAndPost(canvas)方法解锁并将Canvas显示到SurfaceView上面

使用场景:

设想一个在surface模拟下雪的场景

1. 在layout设定一个继承自SurfaceView的View.

2. 这个View起名SnowSurfaceView.

3. 模拟下雪实际是多个雪花图片, 从屏幕上方到下方的动态绘制, 而且本次绘制之前要清除上次的绘制内容(否则图片会连成一条竖线),

同时考虑超出屏幕范围的雪花要重置x和y坐标, 保证回到屏幕内(雪花飘到屏幕下方, 要重新回到上面去,接着飘落)

4.然后就根据使用流程开始写代码

<1> 获取holder. 在SnowSurfaceView的构造方法中  

mHolder = this.getHolder();
mHolder.setFormat(PixelFormat.TRANSLUCENT);
mHolder.addCallback(this);
<2 > 在OnMeasuer中获取SurfaceView宽高, 防止画出界.

int widthMode  = MeasureSpec.getMode(widthMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY) {
      mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
}
<3>初始化雪花的横纵坐标

<4>画雪花方法

private void drawView() {
        if (mHolder == null) {
            return;
        }
        Canvas canvas = mHolder.lockCanvas();
        if (canvas == null) {
            return;
        }
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        drawSnow(canvas);
        mHolder.unlockCanvasAndPost(canvas);
    }

<5>开启画雪花的线程
    public void start() {
        new Thread(){
            @Override
            public void run() {
                while (true) {
                    try {
                        updatePara();
                        drawView();
                        Thread.sleep(20);
                    }
                    catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }.start();
    }

3. 指引界面的实现,参考showtipsview


(1)透明圆圈实际是先绘制一层半透明灰, 然后设置画刷属性setXfermode  PorterDuff.Mode.CLEAR

绘制一个透明的圆圈即可.

	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		/*
		 * Draw circle and transparency background
		 */
		
		/* 
		 * Since bitmap needs the canva's size, it wont be load at init() 
		 * To prevent the DrawAllocation issue on low memory devices, the bitmap will be instantiate only when its null
		 */
		if (bitmap == null) {
			bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
			temp = new Canvas(bitmap);
		}
		
		if (background_color != 0)
			paint.setColor(background_color);
		else
			paint.setColor(Color.parseColor("#000000"));
		
		paint.setAlpha(background_alpha);
		temp.drawRect(0, 0, temp.getWidth(), temp.getHeight(), paint);

		transparentPaint.setColor(getResources().getColor(android.R.color.transparent));
		transparentPaint.setXfermode(porterDuffXfermode);

		int x = showhintPoints.x;
		int y = showhintPoints.y;
		temp.drawCircle(x, y, radius, transparentPaint);

		canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);

		circleline.setStyle(Paint.Style.STROKE);
		if (circleColor != 0)
			circleline.setColor(circleColor);
		else
			circleline.setColor(Color.RED);
		
		circleline.setAntiAlias(true);
		circleline.setStrokeWidth(3);
		canvas.drawCircle(x, y, radius, circleline);
	}

(2)如何确定圆圈的位置

<1>先传递进需要透明显示的button

	public void setTarget(View v) {
		targetView = v;
	}
<2>通过button的ViewTreeObserver addOnGlobalLayoutListener来获取button的坐标信息.

show就是调用的方法, 这个是在activity的主线程进行调用的.

public void show(final Activity activity) {
		if (isDisplayOneTime() && showTipsStore.hasShown(getDisplayOneTimeID())) {
			setVisibility(View.GONE);
			((ViewGroup) ((Activity) getContext()).getWindow().getDecorView()).removeView(ShowTipsView.this);
			return;
		} else {
			if (isDisplayOneTime())
				showTipsStore.storeShownId(getDisplayOneTimeID());
		}

		new Handler().postDelayed(new Runnable() {
			@Override
			public void run() {
				((ViewGroup) activity.getWindow().getDecorView()).addView(ShowTipsView.this);

				ShowTipsView.this.setVisibility(View.VISIBLE);
				Animation fadeInAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.fade_in);
				ShowTipsView.this.startAnimation(fadeInAnimation);
                                //视图测量之后就可以获取到button的坐标信息
				final ViewTreeObserver observer = targetView.getViewTreeObserver();
				observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
					@Override
					public void onGlobalLayout() {

						if (isMeasured)
							return;

						if (targetView.getHeight() > 0 && targetView.getWidth() > 0) {
							isMeasured = true;

						}

						if (custom == false) {
							int[] location = new int[2];
							targetView.getLocationInWindow(location);
							int x = location[0] + targetView.getWidth() / 2;
							int y = location[1] + targetView.getHeight() / 2;
							// Log.d("FRED", "X:" + x + " Y: " + y);

							Point p = new Point(x, y);

							showhintPoints = p;
							radius = targetView.getWidth() / 2;
						} else {
							int[] location = new int[2];
							targetView.getLocationInWindow(location);
							int x = location[0] + showhintPoints.x;
							int y = location[1] + showhintPoints.y;
							// Log.d("FRED", "X:" + x + " Y: " + y);

							Point p = new Point(x, y);

							showhintPoints = p;

						}

						invalidate();

						createViews();

					}
				});
			}
		}, getDelay());

(3)调用show方法

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btn_one = (Button) findViewById(R.id.button1);
        Button btn_two = (Button) findViewById(R.id.button2);

        // ShowTipsView
        ShowTipsView showtips = new ShowTipsBuilder(this)
                .setTarget(btn_one).setTitle("A magnific button")
                .setDescription("This button do nothing very well")
                .setDelay(1000)
                .setBackgroundAlpha(128)
                .setCloseButtonColor(Color.RED)
                .setCloseButtonTextColor(Color.GREEN)
                .build();

        showtips.show(this);


    }

(4)右下角红色button的实现, 以及Text的添加, 就是通过动态代码将控件添加到当前SurfaceView中

	private void createViews() {
		this.removeAllViews();

		RelativeLayout texts_layout = new RelativeLayout(getContext());

		LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
		/*
		 * Title
		 */
		TextView textTitle = new TextView(getContext());
		textTitle.setText(getTitle());
		if (getTitle_color() != 0)
			textTitle.setTextColor(getTitle_color());
		else
			textTitle.setTextColor(getResources().getColor(android.R.color.holo_blue_bright));
		textTitle.setId(123);
		textTitle.setTextSize(26);

		// Add title to this view
		texts_layout.addView(textTitle);

		/*
		 * Description
		 */
		TextView text = new TextView(getContext());
		text.setText(getDescription());
		if (getDescription_color() != 0)
			text.setTextColor(getDescription_color());
		else
			text.setTextColor(Color.WHITE);
		text.setTextSize(17);
		params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
		params.addRule(RelativeLayout.BELOW, 123);
		text.setLayoutParams(params);

		texts_layout.addView(text);

		params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
		LayoutParams paramsTexts = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);

		if (screenY / 2 > showhintPoints.y) {
			// textBlock under the highlight circle
			paramsTexts.height = (showhintPoints.y + radius) - screenY;
			paramsTexts.topMargin = (showhintPoints.y + radius);
			texts_layout.setGravity(Gravity.START | Gravity.TOP);

			texts_layout.setPadding(50, 50, 50, 50);
		} else {
			// textBlock above the highlight circle
			paramsTexts.height = showhintPoints.y - radius;

			texts_layout.setGravity(Gravity.START | Gravity.BOTTOM);

			texts_layout.setPadding(50, 100, 50, 50);
		}

		texts_layout.setLayoutParams(paramsTexts);
		this.addView(texts_layout);

		/*
		 * Close button
		 */
		Button btn_close = new Button(getContext());
		btn_close.setId(4375);
		btn_close.setText(getButtonText());
		btn_close.setTextColor(buttonTextColor == 0 ? Color.WHITE : buttonTextColor);

		if(closeButtonDrawableBG != null)
		{
			btn_close.setBackgroundDrawable(closeButtonDrawableBG);
		}

		if(buttonColor != 0){
			btn_close.getBackground().setColorFilter(buttonColor, PorterDuff.Mode.MULTIPLY);
		}

		btn_close.setTextSize(17);
		btn_close.setGravity(Gravity.CENTER);

		params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

		params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
		params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
		params.rightMargin = 50;
		params.bottomMargin = 100;

		btn_close.setLayoutParams(params);
		btn_close.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				if (getCallback() != null)
					getCallback().gotItClicked();

				setVisibility(View.GONE);
				((ViewGroup) ((Activity) getContext()).getWindow().getDecorView())
						.removeView(ShowTipsView.this);

			}
		});
		this.addView(btn_close);

	}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值