【转】如何实现TextureView或者SurfaceView预览框为圆角
如何让 SurfaceView 或者 TextureView 实现圆角呢?这篇文章正好解决此问题,转载一手。其实主要是基于 ViewOutlineProvider 这个组件专门用于裁剪 View 的边界,注意使用 ViewOutlineProvider 时必须API >= 21。不光可以实现圆角裁剪,还可以实现轮廓、阴影等很多效果,这个如果后面用到了再补充。
项目中,视频预览界面框为圆角;但发现是使用的 Renderer 渲染的方法进行的,的确可以有圆角效果。
但有个问题是:我的视频源与要显示视频的预览框的长宽比率不同,预览框需要满屏看到视频源,如果不做处理,视频源只能通过压缩来显示。造成了视频的变形,如果不拉伸处理,那么就进行裁剪处理,需要对视频进行Matrix操作,如移动,伸缩处理。进行这些处理后,渲染的圆角效果就不再出现了。所以通过Renderer来进行圆角效果,不但复杂而且并不可靠。
通过网上的搜索可以找到 Android5.0后,一个类 ViewOutlineProvider;基于 View 自身的setClipToOutline(boolean clipToOutline) 和 setOutlineProvider(ViewOutlineProvider provider) 方法实现了该需求。
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);
}
}
mView.setOutlineProvider(new TextureVideoViewOutlineProvider(radius));
mView.setClipToOutline(true);
任何 View 都可通过此方法达到圆角效果。
下面是我自己试了一下:
<?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>
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);
}
}
