【转】如何实现TextureView或者SurfaceView预览框为圆角
如何让 SurfaceView 或者 TextureView 实现圆角呢?这篇文章正好解决此问题,转载一手。其实主要是基于 ViewOutlineProvider 这个组件专门用于裁剪 View 的边界,注意使用 ViewOutlineProvider 时必须API >= 21。不光可以实现圆角裁剪,还可以实现轮廓、阴影等很多效果,这个如果后面用到了再补充。
项目中,视频预览界面框为圆角;但发现是使用的 Renderer 渲染的方法进行的,的确可以有圆角效果。
但有个问题是:我的视频源与要显示视频的预览框的长宽比率不同,预览框需要满屏看到视频源,如果不做处理,视频源只能通过压缩来显示。造成了视频的变形,如果不拉伸处理,那么就进行裁剪处理,需要对视频进行Matrix操作,如移动,伸缩处理。进行这些处理后,渲染的圆角效果就不再出现了。所以通过Renderer来进行圆角效果,不但复杂而且并不可靠。
通过网上的搜索可以找到 Android5.0后,一个类 ViewOutlineProvider;基于 View 自身的setClipToOutline(boolean clipToOutline) 和 setOutlineProvider(ViewOutlineProvider provider) 方法实现了该需求。
1import android.graphics.Outline;
2import android.graphics.Rect;
3import android.view.View;
4import android.view.ViewOutlineProvider;
5
6public class TextureVideoViewOutlineProvider extends ViewOutlineProvider {
7 private float mRadius;
8
9 public TextureVideoViewOutlineProvider(float radius) {
10 this.mRadius = radius;
11 }
12
13 @Override
14 public void getOutline(View view, Outline outline) {
15 Rect rect = new Rect();
16 view.getGlobalVisibleRect(rect);
17 int leftMargin = 0;
18 int topMargin = 0;
19 Rect selfRect = new Rect(leftMargin, topMargin,
20 rect.right - rect.left - leftMargin, rect.bottom - rect.top - topMargin);
21 outline.setRoundRect(selfRect, mRadius);
22 }
23}
1mView.setOutlineProvider(new TextureVideoViewOutlineProvider(radius));
2mView.setClipToOutline(true);
任何 View 都可通过此方法达到圆角效果。
下面是我自己试了一下:
1<?xml version="1.0" encoding="utf-8"?>
2<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 tools:context=".MainActivity">
8
9 <SurfaceView
10 android:id="@+id/preview_surface"
11 android:layout_width="300dp"
12 android:layout_height="300dp"
13 android:layout_centerInParent="true"
14 />
15</RelativeLayout>
1import androidx.appcompat.app.AppCompatActivity;
2
3import android.content.Context;
4import android.graphics.Outline;
5import android.graphics.Rect;
6import android.hardware.Camera;
7import android.os.Bundle;
8import android.view.SurfaceHolder;
9import android.view.SurfaceView;
10import android.view.View;
11import android.view.ViewOutlineProvider;
12
13import java.io.IOException;
14
15public class MainActivity extends AppCompatActivity {
16 private Camera mCamera; // 相机
17 @Override
18 protected void onCreate(Bundle savedInstanceState) {
19 super.onCreate(savedInstanceState);
20 setContentView(R.layout.activity_main);
21 mCamera = android.hardware.Camera.open();
22 SurfaceView mPreview = findViewById(R.id.preview_surface);
23 mPreview.setOutlineProvider(new TextureVideoViewOutlineProvider(
24 DensityUtil.dip2px(this, 150)));
25 mPreview.setClipToOutline(true);
26
27 mPreview.getHolder().addCallback(new SurfaceHolder.Callback() {
28 @Override
29 public void surfaceCreated(SurfaceHolder holder) {
30 try {
31 mCamera.setPreviewDisplay(mPreview.getHolder());
32 } catch (IOException e) {
33 e.printStackTrace();
34 }
35 mCamera.startPreview();
36 }
37
38 @Override
39 public void surfaceChanged(SurfaceHolder holder,
40 int format, int width, int height) {
41 }
42
43 @Override
44 public void surfaceDestroyed(SurfaceHolder holder) {
45
46 }
47 });
48 }
49
50 @Override
51 protected void onResume() {
52 super.onResume();
53 if(mCamera != null) {
54 mCamera.startPreview();
55 }
56 }
57
58 @Override
59 protected void onPause() {
60 super.onPause();
61 if(mCamera != null) {
62 mCamera.stopPreview();
63 }
64 }
65
66 @Override
67 protected void onDestroy() {
68 super.onDestroy();
69 if(mCamera != null) {
70 mCamera.release();
71 }
72 }
73}
74
75class TextureVideoViewOutlineProvider extends ViewOutlineProvider {
76 private final float mRadius;
77
78 public TextureVideoViewOutlineProvider(float radius) {
79 this.mRadius = radius;
80 }
81
82 @Override
83 public void getOutline(View view, Outline outline) {
84 Rect rect = new Rect();
85 view.getGlobalVisibleRect(rect);
86 int leftMargin = 0;
87 int topMargin = 0;
88 Rect selfRect = new Rect(leftMargin, topMargin,
89 rect.right - rect.left - leftMargin,
90 rect.bottom - rect.top - topMargin);
91 outline.setRoundRect(selfRect, mRadius);
92 }
93}
94
95class DensityUtil {
96 public static int dip2px(Context context, float dpValue) {
97 final float scale = context.getResources().getDisplayMetrics().density;
98 return (int) (dpValue * scale + 0.5f);
99 }
100
101 public static int px2dip(Context context, float pxValue) {
102 final float scale = context.getResources().getDisplayMetrics().density;
103 return (int) (pxValue / scale + 0.5f);
104 }
105}