zoukankan      html  css  js  c++  java
  • 解决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;
    	}
    
    }
    


    显示效果如下图所示:

    看效果图明显:

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

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

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

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

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

  • 相关阅读:
    HDU 2192 MagicBuilding
    HDU 2148 Score
    HDU 1847 Good Luck in CET4 Everybody!
    往CImageList中加图标列表
    LoadIcon
    OnInitialUpdate 详解
    设备坐标(DP)、客户坐标(Client)、逻辑坐标(LP)
    Web及网络基础学习(一)
    Qt 下QMessageBox下中文乱码问题
    vs2005菜单:选项项目和解决方案
  • 原文地址:https://www.cnblogs.com/aukle/p/3217906.html
Copyright © 2011-2022 走看看