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