Android realize searchlight functions

I. Introduction

Due to recent project required an urgent need to develop a searchlight functions, defining completed within three days, found on the Internet all day, try a variety of methods to achieve, in fact, nothing less than the use BitmapShader and ShapeDrawable drawn on the canvas source picture, there are some other languages ​​methods, such as canavas method of clip-related, but I can not meet the needs of the project. The first method, although the effect can be achieved searchlight, the disadvantage is that there must be a source image, and I have project requirements no matter where you are in the interface, it must be able to shine directly probe the background (the equivalent of being a searchlight part become transparent directly see the back). Finally, I can only think of ways to achieve their own, so the next day come up with a viable solution, as follows:

Second, the idea

According to requirements, are summarized as follows:

- searchlight function
- movable searchlight
- partially transparent searchlight of
- still used in other application interface

Third, to achieve

Ado, directly on the code:

-1 achieve transparent Activity
<style name="TranspantTheme">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:colorBackgroundCacheHint">@null</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowAnimationStyle">@android:style/Animation</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowContentOverlay">@null</item>
    </style>

Add to the above theme Activity in the configuration file, the upcoming

android:theme="@style/theApp"

Read:

android:theme="@style/TranspantTheme"

Activity like this start up is a transparent.

-2. Quit the application is still available (application interface is still available in the other)

使用 windowmanager:

 private WindowManager windowManager;
 private WindowManager.LayoutParams wmParams,wm;
 private int wmType;
 private void initView() {
      
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            wmType = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            wmType = WindowManager.LayoutParams.TYPE_PHONE;
        }

        windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);

        wmParams = new WindowManager.LayoutParams();
        wmParams.type = wmType;
        wmParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
        wmParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        wmParams.gravity = Gravity.LEFT | Gravity.TOP;
        wmParams.x = 0;
        wmParams.y = 0;
        wmParams.width = WindowManager.LayoutParams.MATCH_PARENT;
        wmParams.height = WindowManager.LayoutParams.MATCH_PARENT;
        wmParams.format = PixelFormat.RGBA_8888;

        wm = new WindowManager.LayoutParams();
        wm.type = wmType;
        wm.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
        wm.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        wm.gravity = Gravity.RIGHT | Gravity.TOP;
        wm.x = 0;
        wm.y = 0;
        wm.width = 100;
        wm.height = 100;
        wm.format = PixelFormat.RGBA_8888;
    }

Initialized good windowManager, do not forget to set horizontal screen display (subject to windowManager impact) Activity in the configuration file

-3. Searchlight achieve defined function View

Directly on the code:

public class MyImageView extends android.support.v7.widget.AppCompatImageView{
    private Paint paint1,paint2;//两只笔
    private float x=200,y=200;
    private int screenWidth,screenHeight;

    public MyImageView(Context context) {
        super(context);
        initData();
    }

    private synchronized void initData() {
        //获取屏幕宽高
        DisplayMetrics metrics = getResources().getDisplayMetrics();
        screenWidth = metrics.widthPixels;
        screenHeight = metrics.heightPixels;
        setMyEraseSize(40);
        setColor(Color.GRAY);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBackground(canvas);
        drawMyCircle(canvas);
    }

    //画圆
    private void drawMyCircle(Canvas canvas) {
        canvas.drawCircle(x,y,100,paint1);
    }

    //画背景颜色
    private void drawBackground(Canvas canvas) {
        Rect rect=new Rect(0,0,screenWidth,screenHeight);
        canvas.drawRect(rect,paint2);
    }

    public boolean onTouchEvent(MotionEvent event){
        final int x = (int) event.getX();// 获取当前触摸点的X轴坐标
        final int y = (int) event.getY(); // 获取当前触摸点的Y轴坐标
        this.x=x;this.y=y;
        invalidate(); // 重绘画布
        return true;
    }

    //设置橡皮擦大小
    public void setMyEraseSize(int size){
        paint1= new Paint();
        paint1.reset();
        paint1.setAntiAlias(true);//抗锯齿
        paint1.setDither(true);//防抖动
        paint1.setColor(Color.WHITE);
        paint1.setStrokeWidth(size);
        paint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        BlurMaskFilter bmf=new BlurMaskFilter((0.5f), BlurMaskFilter.Blur.SOLID);
        paint1.setMaskFilter(bmf);
        paint1.setStyle(Paint.Style.FILL);
        paint1.setStrokeJoin(Paint.Join.ROUND);
        paint1.setStrokeCap(Paint.Cap.ROUND);
        paint1.setSubpixelText(true);
        paint1.setTextSize(50);
    }

    //设置比颜色
    public void setColor(int color){
        paint2=new Paint();
        paint2.reset();
        paint2.setAntiAlias(true);//抗锯齿
        paint2.setDither(true);//防抖动
        paint2.setStrokeWidth(5);
        paint2.setTextSize(50);
        paint2.setSubpixelText(true);
        BlurMaskFilter bmf=new BlurMaskFilter((0.5f), BlurMaskFilter.Blur.SOLID);
        paint2.setMaskFilter(bmf);
        paint2.setPathEffect(new CornerPathEffect(20));
        paint2.setStyle(Paint.Style.FILL);
        paint2.setStrokeJoin(Paint.Join.ROUND);
        paint2.setStrokeCap(Paint.Cap.ROUND);
        paint2.setColor(color);
    }
}

Analysis:
In simple terms, in fact, the idea is to use:
with two pens, one responsible for painting the background (black cloth), a responsible eraser function (circle), this time due to the Activity is transparent, so you can directly see the next layer, and then updates the location eraser (circles) when the finger moves, it redraw. Code is very simple, I believe you can understand! !
how about it? Is not it simple?
In order to allow everyone to see the effect, and then combined with other methods of this demo here:

public class MainActivity extends Activity {
    private WindowManager windowManager;
    private WindowManager.LayoutParams wmParams,wm;
    private int wmType;
    private MyImageView myImageView;
    private ImageView view;
    private final int OVERLAY_PERMISSION_REQ_CODE = 1234;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (checkBallPermission()) startProgram();
    }

   //检查是否有悬浮窗权限
    private boolean checkBallPermission()
    {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        {
            if(!Settings.canDrawOverlays(this)) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent,OVERLAY_PERMISSION_REQ_CODE);
                return false;
            }
        }
        return true;
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.e("SearchPrint","onActivityResult");
        if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
            if(android.os.Build.VERSION.SDK_INT>=Build.VERSION_CODES.M) {
                if (!Settings.canDrawOverlays(this))
                {
                    Toast.makeText(MainActivity.this, this.getResources().getString(R.string.ballfail), Toast.LENGTH_SHORT).show();
                    this.finish();
                }
                else {
                    startProgram();
                }
            }
        }
    }

    private void startProgram() {
        initView();
        show();
        addListener();
    }

    private void addListener() {
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                hide();
                finish();
            }
        });
    }

    private void hide(){
        try{
            windowManager.removeView(myImageView);
            windowManager.removeView(view);
        }catch (Exception e){
            e.printStackTrace();
            Log.e("SearchPrint","removeView:"+e.getMessage());
        }
    }

    private void show() {
        try{
            windowManager.addView(myImageView,wmParams);
            windowManager.addView(view,wm);
        }catch (Exception e){
            e.printStackTrace();
            Log.e("SearchPrint","addView:"+e.getMessage());
        }
    }

    private void initView() {
        myImageView=new MyImageView(this);
        view=new ImageView(this);
        view.setBackgroundResource(R.drawable.exit);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            wmType = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            wmType = WindowManager.LayoutParams.TYPE_PHONE;
        }

        windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);

        wmParams = new WindowManager.LayoutParams();
        wmParams.type = wmType;
        wmParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
        wmParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        wmParams.gravity = Gravity.LEFT | Gravity.TOP;
        wmParams.x = 0;
        wmParams.y = 0;
        wmParams.width = WindowManager.LayoutParams.MATCH_PARENT;
        wmParams.height = WindowManager.LayoutParams.MATCH_PARENT;
        wmParams.format = PixelFormat.RGBA_8888;

        wm = new WindowManager.LayoutParams();
        wm.type = wmType;
        wm.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
        wm.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        wm.gravity = Gravity.RIGHT | Gravity.TOP;
        wm.x = 0;
        wm.y = 0;
        wm.width = 100;
        wm.height = 100;
        wm.format = PixelFormat.RGBA_8888;
    }
}

Fourth, other

If you want a searchlight is out of a custom picture, it is more simple to use BitmapShader and ShapeDrawable direct binding, there are many methods online, you can also add a selection of pictures from the gallery inside the method, all came to a simple, due to space restrictions, there is no longer described.

Original article, reproduced, please add a link https://www.jianshu.com/p/438e5c7f3ba7

Reproduced in: https: //www.jianshu.com/p/438e5c7f3ba7

Guess you like

Origin blog.csdn.net/weixin_34162401/article/details/91171083