解决SurfaceView设置透明造成覆盖其他组件的替代方案

之前在项目里面绘制摇杆圆盘使用SurfaceView来实现,同时设置SurfaceView透明,但是这样会造成SurfaceView的组件会覆盖其他的组件,一般情况没有关系,而不一般的情况就是有类似上拉和下拉功能,需要拉出的布局位于最顶部,覆盖其他的组件,而由于之前设置SurfaceView透明使用是:

setZOrderOnTop(true);

mHolder.setFormat(PixelFormat.TRANSPARENT);//设置背景透明

这样会使SurfaceView位于布局的最顶部,即使你设置了bringToTop也没有用,解决这类问题有两种方案:

第一种:使用PopupWindow或者类似浮动小窗体的功能,我测试过他们不会被SurfaceView覆盖,但是这种方案只适用于点击实现组件的弹出,不能实现上拉拖动来显示组建(这里的上拉布局是指有一部分在可见窗体之外),不幸的是项目里面需求指定要上拉,而不是点击来实现组件的弹出功能,所以这种方案不适用于我的情况。所以我就找到了第二种情况。

第二种:

自己写一个类来继承View,然后利用onTouchEvent和OnDraw这两个方法来实现绘制图像,具体的见代码:

Jockey_Left类:继承View

package com.example.test;



import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;

import android.graphics.Paint;

import android.graphics.Point;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;



public class Jockey_Left extends View{



	private Bitmap bitmap;

	public Point mRockerPosition;

	public Point mCtrlPoint;

	private int mRudderRadius = 25;

	public int mWheelRadius = 80;

	private float scale;

	public int isHide = 0;

	private Paint mPaint;

	public Jockey_Left(Context context) {

		super(context);

	}



	public Jockey_Left(Context context, AttributeSet attrs) {

		super(context, attrs);

	}



	public void init(float scale){

		this.scale = scale;

		mRudderRadius = dip2px(15);

		mWheelRadius = dip2px(45);

		bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.print2);

        bitmap = Bitmap.createScaledBitmap(bitmap, mRudderRadius*2, mRudderRadius*2, false);

        mCtrlPoint = new Point((mRudderRadius + mWheelRadius), (mRudderRadius + mWheelRadius));

        mPaint = new Paint();

        mPaint.setAntiAlias(true);

        mRockerPosition = new Point(mCtrlPoint);

	}

	public int dip2px(float dpValue) {  

        return (int)(dpValue * scale + 0.5f);

    }

	public Canvas canvas;

	@Override

	protected void onDraw(Canvas canvas) {

		if (bitmap != null) {

			//canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);//�����Ļ

			this.canvas = canvas;

			canvas.drawBitmap(bitmap, mRockerPosition.x - mRudderRadius, mRockerPosition.y - mRudderRadius, mPaint);

		}

		super.onDraw(canvas);

	}



	int len;

	@Override

	public boolean onTouchEvent(MotionEvent event) {

		try {

			if (isHide == 0) {

				switch (event.getAction()) {

				case MotionEvent.ACTION_DOWN:

					len = MathUtils.getLength(mCtrlPoint.x, mCtrlPoint.y, event.getX(), event.getY());

					 //如果屏幕接触点不在摇杆挥动范围内,则不处理

		            if(len > mWheelRadius) {

		                return true;

		            }

					break;

				case MotionEvent.ACTION_MOVE:

					len = MathUtils.getLength(mCtrlPoint.x, mCtrlPoint.y, event.getX(), event.getY());

					if(len <= mWheelRadius) {

		                //如果手指在摇杆活动范围内,则摇杆处于手指触摸位置

		                mRockerPosition.set((int)event.getX(), (int)event.getY());

		            }else{

		                //设置摇杆位置,使其处于手指触摸方向的 摇杆活动范围边缘

		                mRockerPosition = MathUtils.getBorderPoint(mCtrlPoint, new Point((int)event.getX(), (int)event.getY()), mWheelRadius);

		            }

					break;

				case MotionEvent.ACTION_UP:

					 mRockerPosition = new Point(mCtrlPoint);

					break;

				}

				Thread.sleep(40);

			}else {

				Thread.sleep(200);

			}

		} catch (Exception e) {



		}

		invalidate();//更新布局

		return true;

	}

	

	



}

使用Touch来检测手的触摸点,然后更新中心圆点的位置,再调用invalidate();来更新VIew的背景,实现OnDraw方法,来绘制图像

AppSingleRocker类:作为对比我用一个类继承SurfaceView然后实现背景透明

package com.example.test;



import android.annotation.SuppressLint;

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.Point;

import android.graphics.PorterDuff.Mode;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.SurfaceHolder;

import android.view.SurfaceView;

import android.view.SurfaceHolder.Callback;



@SuppressLint("ViewConstructor")

public class AppSingleRocker extends SurfaceView implements Callback{

	private SurfaceHolder mHolder;

	private Paint mPaint;

	public Point mRockerPosition; // 摇杆位置

	private Point mCtrlPoint;// 摇杆起始位置

	private int mRudderRadius = 25;// 摇杆半径

	private int mWheelRadius = 80;// 摇杆活动范围半径

	private int batmapHW = 160;

	private int batmap2HW = 40;

	int isHide = 0;

	Bitmap bitmap,bitmap2;

	float scale;

	private SingleRudderListener listener = null; //事件回调接口

	public static final int ACTION_RUDDER = 1, ACTION_ATTACK_DEVICEMOVE = 2, ACTION_STOP = 3,  ACTION_ATTACK_CAMERAMOVE = 4;

	public AppSingleRocker(Context context, AttributeSet attrs) {

		super(context, attrs);

		this.setKeepScreenOn(true);

		scale = context.getResources().getDisplayMetrics().density;

		mRudderRadius = dip2px(15);// 摇杆半径

		mWheelRadius = dip2px(45);// 摇杆活动范围半径

		mCtrlPoint = new Point((mRudderRadius + mWheelRadius), (mRudderRadius + mWheelRadius));// 摇杆起始位置

		batmapHW = (mWheelRadius+mRudderRadius) * 2;

		batmap2HW = mRudderRadius * 2;

        mHolder = getHolder();

        mHolder.addCallback(this);

        mPaint = new Paint();

        mPaint.setAntiAlias(true);

        setFocusable(true);

        setFocusableInTouchMode(true);

        mRockerPosition = new Point(mCtrlPoint);

        setZOrderOnTop(true);

        mHolder.setFormat(PixelFormat.TRANSPARENT);//设置背景透明

        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.joystick_l_pad);

        bitmap = Bitmap.createScaledBitmap(bitmap, batmapHW, batmapHW, false);

        bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.print2);

        bitmap2 = Bitmap.createScaledBitmap(bitmap2,batmap2HW,batmap2HW, false);

	}

	

	//获取屏幕的宽度,高度和密度以及dp / px

	 public void getDisplayMetrics() {

 		

	}

	public int dip2px(float dpValue) {  

        return (int)(dpValue * scale + 0.5f);

    }

	//回调接口

    public interface SingleRudderListener {

        void onSteeringWheelChanged(int action,int angle);

    }

    

	//设置回调接口

    public void setSingleRudderListener(SingleRudderListener rockerListener) {

        listener = rockerListener;

    }

    

    int len;

	@Override

	public boolean onTouchEvent(MotionEvent event) {

		try {

			if (isHide == 0) {

				switch (event.getAction()) {

				case MotionEvent.ACTION_DOWN:

					len = MathUtils.getLength(mCtrlPoint.x, mCtrlPoint.y, event.getX(), event.getY());

					 //如果屏幕接触点不在摇杆挥动范围内,则不处理

		            if(len > mWheelRadius) {

		                return true;

		            }

					break;

				case MotionEvent.ACTION_MOVE:

					len = MathUtils.getLength(mCtrlPoint.x, mCtrlPoint.y, event.getX(), event.getY());

					if(len <= mWheelRadius) {

		                //如果手指在摇杆活动范围内,则摇杆处于手指触摸位置

		                mRockerPosition.set((int)event.getX(), (int)event.getY());

		            }else{

		                //设置摇杆位置,使其处于手指触摸方向的 摇杆活动范围边缘

		                mRockerPosition = MathUtils.getBorderPoint(mCtrlPoint, new Point((int)event.getX(), (int)event.getY()), mWheelRadius);

		            }

		            if(listener != null) {

		                float radian = MathUtils.getRadian(mCtrlPoint, new Point((int)event.getX(), (int)event.getY()));

		                listener.onSteeringWheelChanged(ACTION_RUDDER, getAngleCouvert(radian));

		            }

					break;

				case MotionEvent.ACTION_UP:

					 mRockerPosition = new Point(mCtrlPoint);

					 if (listener != null) {

						 listener.onSteeringWheelChanged(ACTION_STOP, 0);

					}

					break;

				}

				Canvas_OK();

				Thread.sleep(60);

			}else {

				Thread.sleep(200);

			}

		} catch (Exception e) {



		}

		return true;

	}



	public void singleRockerUp(){

		 mRockerPosition = new Point(mCtrlPoint);

		 listener.onSteeringWheelChanged(ACTION_STOP, 0);

	}

	//获取摇杆偏移角度 0-360°

    private int getAngleCouvert(float radian) {

        int tmp = (int)Math.round(radian/Math.PI * 180);

        if(tmp < 0) {

            return -tmp;

        }else{

            return 180 + (180 - tmp);

        }

    }



	public void surfaceCreated(SurfaceHolder holder) {

		Canvas_OK();

	}



	public void surfaceChanged(SurfaceHolder holder, int format, int width,

			int height) {

		

	}



	public void surfaceDestroyed(SurfaceHolder holder) {

		

	}

	// 设置是否隐藏

	public void Hided(int opt)

	{

		isHide = opt;

		Canvas_OK();

	}

	

	public void setHided(int opt){

		isHide = opt;

	}

	/**

	 * 返回圆盘是否隐藏

	 * @return

	 */

	public int getIsHided(){

		return isHide;

	}

	//绘制图像

	public void Canvas_OK(){

		 Canvas canvas = null;

		 try {

			 if (isHide == 0) {

				 canvas = mHolder.lockCanvas();

	             canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);//清除屏幕

	             canvas.drawBitmap(bitmap, mCtrlPoint.x - mWheelRadius - mRudderRadius, mCtrlPoint.y - mWheelRadius - mRudderRadius, mPaint);

	             canvas.drawBitmap(bitmap2, mRockerPosition.x - mRudderRadius, mRockerPosition.y - mRudderRadius, mPaint);

			}else {

				 canvas = mHolder.lockCanvas();

	             canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);//清除屏幕

			}

         } catch (Exception e) {

             e.printStackTrace();

         } finally {

             if(canvas != null) {

                 mHolder.unlockCanvasAndPost(canvas);

             }

         }

	 }

}


activity_main这个是我的布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context=".MainActivity" >



    <com.example.test.Jockey_Left

        android:layout_width="120dp"

        android:layout_height="120dp"

        android:id="@+id/left_jockey"

        android:background="@drawable/joystick_l_pad"

        ></com.example.test.Jockey_Left>

	

    <Button 

        android:layout_width="60dp"

        android:layout_height="60dp"

        />

    

    

    <com.example.test.AppSingleRocker

        android:layout_width="120dp"

        android:layout_height="120dp"

        android:layout_alignParentRight="true"

        android:layout_alignParentBottom="true"

        ></com.example.test.AppSingleRocker>

    <Button 

        android:layout_width="60dp"

        android:layout_height="60dp"

         android:layout_alignParentRight="true"

        android:layout_alignParentBottom="true"

        />

</RelativeLayout>


MainActivity这个是显示的Activity

package com.example.test;



import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;



public class MainActivity extends Activity {



	

	Jockey_Left jockey_left;

	

	@Override

	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);

		jockey_left = (Jockey_Left)findViewById(R.id.left_jockey);

		jockey_left.init(getResources().getDisplayMetrics().density);

	}



	@Override

	public boolean onCreateOptionsMenu(Menu menu) {

		getMenuInflater().inflate(R.menu.main, menu);

		return true;

	}



}


显示效果如下图所示:

解决SurfaceView设置透明造成覆盖其他组件的替代方案

 

 

看效果图明显:

1.左上角的Button没有被覆盖,而右下角的Button被覆盖掉

2.这两个圆盘都是使用相同的图片,但是右下角有明显的锯齿,而左上角的没有

3.唯一不足的就是左上角流畅度不如右下角的

 

所以如果绘图区域要求矩形最好选用SurfaceVIew,因为这样提高程序流畅度,如果 要求圆盘而且不能覆盖其他的组件,选用继承View,重新实现。

 

源码下载地址:http://download.csdn.net/detail/jwzhangjie/5816135 这里同时实现了圆盘的功能

 

你可能感兴趣的:(SurfaceView)