Two SurfaceView overlap effects Similar to video and handfitution practices in live broadcast

Effect Picture

First of all, don’t talk nonsense, just go to a picture. Only when there is a picture can the truth come out, otherwise everyone will look at it for a long time. I realized that it was not the effect I wanted, so I wasted everyone’s time like this.

There are many practical application scenarios, such as the display of camera data at the back and a drawing board in front , The live video and handout display

layout

The layout is very simple, directly let the two surfaceView overlap each other

<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:background="#00f" tools:context="cn.woblog.testsurfaceview.MainActivity"> <SurfaceView  android:id="@+id/sv"  android:layout_width="match_parent" android:layout_height="400dp" /> <RelativeLayout  android:id="@+id/rl" android:layout_width=< span class="hljs-value">"wrap_content" android:layout_height="wrap_content"> <SurfaceView  android:id="@+id/sv_mini" < span class="hljs-attribute">android:layout_width="200dp" android:layout_height="200dp" android:clickable="false"  android:focusable="false" /> RelativeLayout>RelativeLayout >

Add content to be displayed

I did not play video or use camera data for testing purposes. , But directly painted a color, but the principle is the same

sv = (SurfaceView) findViewById(R.id.sv);sfh = sv.getHolder(); //Operate surfaceView sfh.addCallback(new SurfaceHolder.C allback() {@Override public void surfaceCreated(SurfaceHolder holder) {Canvas c = sfh.lockCanvas(new Rect(0, 0, 600, 600)); //2. Open painting Paint p = new Paint( ); p.setColor(Color.RED); Rect aa = new Rect(0, 0, 600, 600); c.drawRect( aa, p); //3. Unlock the canvas and update the submission screen display content sfh.unlockCanvasAndPost(c); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) {} });

If this step , These two interfaces will definitely not have the effect of the above picture, but the first one will cover the second. Below is the key code

sv_mini.setZOrderOnTop(true);holder.setFormat(PixelFormat.TRANSPARENT);

Set the top surface to the top and make it transparent. If you don’t set transparency , Then only the surfaceView at the top can be seen, and the other places are black. At this point, the overlapping display of the two surfaceViews is basically solved. Let’s add the drag effect.

Use layout method

@TargetApi(Build.VERSION_CODES.HONEYCOMB)@Overridepublic span> boolean onTouch(View v, MotionEvent event) { int ea = event.getAction(); switch (ea) {case MotionEvent.ACTION_DOWN : lastX = (int) event.getRawX(); lastY = (int) event.getRawY() ; break; /** * layout(l,t,r,b) * l Left position, relative to parent t Top position, relative to parent r Right position, relative to parent b Bottom position, relative to parent * */ case MotionEvent.ACTION_MOVE: int dx = (int) event.getRawX()-lastX; int dy = (int) event.getRawY()- lastY; int left = v.getLeft() + dx; int top = v.getTop() + dy; int right = v.getRight() + dx; int bottom = v.getBottom() + dy; if (left <0) {left = 0 ; right = left + v.getWidth();} if (right> screenWidth) {right = screenWidth; left = right-v.getWidth() ;} if (top <0) {top = 0; bottom = top + v.getHeight();} if (bottom> screenHeight) {bottom = screenHeight; top = bottom-v.getHeight();} v.layout(left, top, right, bottom); Log.i("", "position:" + left + < span class="hljs-string">", " + top + ", " + right + " , " + bottom); lastX = (int) event.getRawX(); lastY = (int< /span>) event.getRawY(); break; case MotionEvent.ACTION_UP: break;} return true;}

use margin

with add~

Complete code

package cn.woblog.testsurfaceview;import android.annotation.TargetApi;import android.graphics.Canvas; import android.graphics.Color;import android.graphics.Paint;import android.graphics .PixelFormat;import android.graphics.Rect;import android.os.Build;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.DisplayMetrics;import android.util.Log;import and roid.view.GestureDetector;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View; import android.view.ViewGroup;import android.widget.RelativeLayout;public class MainActivity extends span> AppCompatActivity implements View.OnTouchListener { public static final String TAG = "TAG"; private SurfaceView sv; private SurfaceView sv_mini; private SurfaceHolder sfh; private SurfaceHolder holder; private RelativeLayout rl; private < span class="hljs-keyword">int lastX; private int lastY; private int screenWidth; private int screenHeight; @Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView (R.layout.activity_ma in); DisplayMetrics dm = getResources().getDisplayMetrics(); screenWidth = dm.widthPixels; screenHeight = dm.heightPixels-50; getSupportActionBar().hide(); sv = (SurfaceView) findViewById(R.id.sv); rl = (RelativeLayout) findViewById(R.id.rl); rl.setOnTouchListener(this); sfh = sv.getHolder(); //Operate surfaceView sfh.addCallback(new SurfaceHolder.Callback( ) {@Override public void surfaceCreated(SurfaceHolder holder) {Canvas c = sfh.lockCanvas(new Rect(0, 0, 600, 600)); //2. Open painting Paint p = new Paint(); p.setColor(Color.RED); Rect aa = new Rect(0, < span class="hljs-number">0, 600, 600); c. drawRect(aa, p); //3. Unlock the canvas to update and submit the screen display content sfh.unlockCanvasAndPost(c);}  @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int  height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) { } });// Automatically run surfaceCreated and surfaceChanged sv_mini = (SurfaceView) findViewById(R.id.sv_mini);/ / sv.setZOrderOnTop(false); //These two methods are similar. Once set, it will appear to the top. However, the latter is invisible, so you should set it as below Transparent sv_mini.setZOrderOnTop(true); sv_mini.setZOrderMediaOverlay(true); holder = sv_mini .getHolder(); holder.setFormat(PixelFormat.TRANSPARENT); sfh.setFormat(PixelFormat.TRANSPARENT); holder.addCallback(new SurfaceHolder.Callback() {@Override public void surfaceCreated(SurfaceHolder holder) {Canvas c = holder.lockCanvas(new Rect(0, 0, 400, 400 )); //2.Open painting Paint p = new Paint(); p.setColor(Color .BLUE); Rect aa = new Rect(0,  0, 400, 400); c.drawRect(aa, p); //3. Unlock the canvas and update the submission screen display content holder.unlockCanvasAndPost(c);} @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) {} });} @TargetApi (Build.VERSION_CODES.HONEYCOMB) @Override public boolean onTouch(View v, MotionEvent event) {int ea = event.getAction (); switch (ea) {case MotionEvent.ACTION_DOWN: lastX = (int) event.getRawX(); lastY = (int) event.getRawY(); break; /** * layout(l,t,r,b) * l Left position, relative to parent t Top position, relative to parent r Right position, relative to parent b Bottom position, relative to parent * */ case MotionEvent.ACTION_MOVE: int dx = (int) event.getRawX()-lastX; int dy = (int ) event.getRawY()-lastY; int left = v.getLeft() + dx; int< /span> top = v.getTop() + dy; int right = v.getRight() + dx; int< /span> bottom = v.get Bottom() + dy; if (left <0) {left = 0; right = left + v.getWidth();} if (right> screenWidth) {right = screenWidth; left = right-v .getWidth();} if (top <0) {top = 0; bottom = top + v.getHeight();} if (bottom> screenHeight) {bottom = screenHeight; top = bottom-v .getHeight();} v.layout(left, top, right, bottom); Log.i("",  "position:" + left + ", " + top + ", " + right + ", " + bottom); lastX = (int) event.getRawX(); lastY = (int span>) event.getRawY(); break; case MotionEvent.ACTION_UP: break;} return true; }}

The next issue of the Demo address will analyze why the above problems exist from the perspective of the source code, so stay tuned

renderings

h2>

First of all, don’t talk nonsense, just go to a picture, there is a picture to have the truth, otherwise you will find that it is not the effect I want after looking at it for a long time, so this wastes everyone’s time

< img src="/wp-content/uploadshttp:/img.voidcn.com/vcimg/static/loading.png" alt="" title="" d="5090578" s="814_63c" t="gif">

There are many practical application scenarios, such as displaying camera data in the back and a drawing board in front, showing live video and handouts

layout

The layout is very simple, just let the two surfaceView overlap each other

< RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:tools="http://schemas.android.com/tools" < span class="hljs-attribute">android:layout_width="match_parent" android:layout_height="match_parent" android:background="#00f " tools:context="cn.woblog.testsurfaceview.MainActivity"> <SurfaceView  android:id="@+id/sv" and roid:layout_width="match_parent" android:layout_height="400dp" /> <RelativeLayout  android:id="@+id/rl" android:layout_width=< span class="hljs-value">"wrap_content" android:layout_height="wrap_content"> <SurfaceView  android:id= "@+id/sv_mini" android:layout_width=" 200dp" android:layout_height="200dp" android:clickable="false" android:focusable="false" /> RelativeLayout>RelativeLayout>

Add the content to be displayed

I did not play here for testing purposes Video or using camera data, but directly draw a color, but the truth is the same

sv = (SurfaceView) findViewById(R.id.sv);sfh = sv.getHolder(); //Operate surfaceView sfh.addCallback(new SurfaceHolder.Callback() {@Override public void surfaceCreated(SurfaceHolder holder) {Canvas c = sfh.lockCanvas(new Rect(0, 0, 600, 600)); //2. Open painting span> Paint p = new Paint(); p.setColor(Color.RED); Rect aa = new Rect(0, 0, 600 , 600); c.drawRect(aa, p); //3. Unlock the canvas and update the submission screen display content span> sfh.unlockCanvasAndPost(c);} @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) {} });

If this step is reached, these two interfaces will definitely not have the effect of the above picture, but the first one will Covering the second one, here is the key code

sv_mini.setZOrderOnTop(true);holder.setFormat(PixelFormat.TRANSPARENT );

Set the top surface to the top and make it transparent. If you don’t set transparency, you can only see the top surfaceView, and the other places are black. At this point, the overlapping display of the two surfaceViews is basically solved. Let’s add the drag effect.

Use layout method

@TargetApi(Build.VERSION_CODES.HONEYCOMB)@Overridepublic span> boolean onTouch(View v, MotionEvent event) { int ea = event.getAction(); switch (ea) {case MotionEvent.ACTION_DOWN : lastX = (int) event.getRawX(); lastY = (int) event.getRawY() ; break; /** * layout(l,t,r,b) * l Left position, relative to parent t Top position, relative to parent r Right position, relative to parent b Bottom position, relative to parent * */ case MotionEvent.ACTION_MOVE: int dx = (int ) event.getRawX()-lastX; int dy = (int) event.getRawY()-lastY ; int left = v.getLeft() + dx; int top = v.getTop() + dy ; int right = v.getRight() + dx; int bottom = v.getBottom() + dy ; if (left <0) {left = 0< /span>; right = left + v.getWidth();} if (right> screenWidth) {right = screenWidth; left = right-v.getWidth(); } if (top <0) {top = 0; bottom = top + v.getHeight();} if (bottom> screenHeight) {bottom = screenHeight; top = bottom-v.getHeight();} v.layout(left, top , right, bottom); Log.i("", "position:" + left + ", " + top + ", " + right + ", " + bottom); lastX = (int) event.getRawX(); lastY = (int span>) event.getRawY(); break; case MotionEvent.ACTION_UP: break;} return true;}

use margin

with add~

Complete code

package cn.woblog.testsurfaceview;import android.annotation.TargetApi;import android.graphics.Canvas; import android.graphics.Color;import android.graphics.Paint;import android.graphics .PixelFormat;import android.graphics.Rect;import android.os.Build;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.DisplayMetrics;import android.util.Log;import android. v iew.GestureDetector;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import< /span> android.view.ViewGroup;import android.widget.RelativeLayout;public class MainActivity extends AppCompatActivity implements View.OnTouchListener { public static final String TAG = "TAG"; private SurfaceView sv; private SurfaceView sv_mini; private SurfaceHolder sfh; private SurfaceHolder holder; private RelativeLayout rl; private int lastX; private int lastY; private int screenWidth; private int screenHeight; @Override protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView( R.layout.activity_main);        DisplayMetrics dm = getResources().getDisplayMetrics();        screenWidth = dm.widthPixels;        screenHeight = dm.heightPixels - 50;        getSupportActionBar().hide();        sv = (SurfaceView) findViewById(R.id.sv);        rl = (RelativeLayout) findViewById(R.id.rl);        rl.setOnTouchListener(this);        sfh = sv.getHolder();        //对 surfaceView 进行操作        sfh.addCallback(new SurfaceHolder.Callback() {            @Override            public void surfaceCreated(SurfaceHolder holder) {                Canvas c = sfh.lockCanvas(new Rect(0, 0, 600, 600));                //2.开画                Paint p = new Paint();                p.setColor(Color.RED);                Rect aa = new Rect(0, 0, 600, 600);                c.drawRect(aa, p);                //3. 解锁画布 更新提交屏幕显示内容                sfh.unlockCanvasAndPost(c);            }            @Override            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {            }            @Override            < span class="hljs-keyword">public void surfaceDestroyed(SurfaceHolder holder) {            }        });// 自动运行surfaceCreated以及surfaceChanged        sv_mini = (SurfaceView) findViewById(R.id.sv_mini);// sv.setZOrderOnTop(false);        //这两个方法差不多,设置了就会浮现到顶部,但是,后面的看不见,要像下面设置为透明        sv_mini.setZOrderOnTop(true);        sv_mini.setZOrderMediaOverlay(true);        holder = sv_mini.getHolder();        holder.setFormat(PixelFormat.TRANSPARENT);        sfh.setFormat(PixelFormat.TRANSPARENT);        holder.addCallback(new SurfaceHolder.Callback() {            @Override            public void s urfaceCreated(SurfaceHolder holder) {                Canvas c = holder.lockCanvas(new Rect(0, 0, 400, 400));                //2.开画                Paint p = new Paint();                p.setColor(Color.BLUE);                Rect aa = new Rect(0, 0, 400, 400);                c.drawRect(aa, p);                //3. 解锁画布 更新提交屏幕显示内容                holder.unlockCanvasAndPost(c);            }            @Override            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {            }            @Override            public void surfaceDestroyed(SurfaceHolder holder) {            }        });    }    @TargetApi(Build.VERSION_CODES.HONEYCOMB)    @Override    public boolean onTouch(View v, MotionEvent event) {        int ea = event.getAction();        switch (ea) {            case MotionEvent.ACTION_DOWN:                lastX = (int) e vent.getRawX();                lastY = (int) event.getRawY();                break;            /** * layout(l,t,r,b) * l Left position, relative to parent t Top position, relative to parent r Right position, relative to parent b Bottom position, relative to parent * */            case MotionEvent.ACTION_MOVE:                int dx = (int) event.getRawX() - lastX;                int dy = (int) event.getRawY() - lastY;                int left = v.getLeft() + dx;                int top = v.getTop() + dy;                int right = v.getRight() + dx;                int bottom = v.getBottom () + dy;                if (left < 0) {                    left = 0;                    right = left + v.getWidth();                }                if (right > screenWidth) {                    right = screenWidth;                    left = right - v.getWidth();                }                if (top < 0) {                    top = 0;                    bottom = top + v.getHeight();                }                if (bottom > screenHeight) {                    bottom = screenHeight;                    top = bottom - v.getHeight();                }                v.layout(left, top, right, bottom);                Log.i("", "position:" + left + ", " + top + ", " + right + ", " + bottom);                lastX = (int) event.getRawX();                lastY = (int) event.getRawY();                break;            case MotionEvent.ACTION_UP:                break;        }        return true;    }}

Demo地址下一期会从源码的角度解析为什么会有上述问题存在,敬请期待

Leave a Comment

Your email address will not be published.