这是代码(运行它看看有什么问题) => https://github.com/x0axz/CustomRenderer
在我的 Xamarin 应用程序中,有一个适用于 Android 的自定义相机渲染器,它是从ViewModel
通过MessagingCenter.Send<object>(this, "A");
.
运行良好。唯一的问题是,在第一页上它拍摄图片,但是当我导航到另一个页面时,那里有另一个命令,MessagingCenter.Send<object>(this, "A");
,拍照,但是这次返回错误调用 Camera.release() 后相机正在被使用.
下面是 ViewModel 和 Camera Renderer 的代码。
FirstCameraViewModel.cs
private void FirstCamera(object sender, EventArgs e)
{
try
{
MessagingCenter.Send<object>(this, "A");
}
catch
{
Console.WriteLine(error.InnerException.StackTrace);
Console.WriteLine(error.InnerException.Message);
}
finally
{
timer_countdown = new Timer();
timer_countdown.Interval = 1000;
timer_countdown.Elapsed += OnTimedEvent;
timer_countdown.Enabled = true;
timer_countdown.AutoReset = true;
timer_countdown.Start();
}
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
Seconds++;
if (Seconds == 5)
{
MainThread.BeginInvokeOnMainThread(async () =>
{
await NavigationService.NavigateToAsync<SecondCameraViewModel>();
});
}
}
SecondCameraViewModel.cs,在此页面中返回错误
private void SecondCamera(object sender, EventArgs e)
{
try
{
MessagingCenter.Send<object>(this, "A");
}
catch
{
Console.WriteLine(error.InnerException.StackTrace);
Console.WriteLine(error.InnerException.Message);
}
finally
{
timer_countdown = new Timer();
timer_countdown.Interval = 1000;
timer_countdown.Elapsed += OnTimedEvent;
timer_countdown.Enabled = true;
timer_countdown.AutoReset = true;
timer_countdown.Start();
}
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
Seconds++;
if (Seconds == 5)
{
MainThread.BeginInvokeOnMainThread(async () =>
{
await NavigationService.NavigateToAsync<IndexViewModel>();
});
}
}
UPDATE
相机预览.cs
public sealed class CameraPreview : ViewGroup, ISurfaceHolderCallback, Camera.IPictureCallback
{
SurfaceView surfaceView;
ISurfaceHolder holder;
Camera.Size previewSize;
IList<Camera.Size> supportedPreviewSizes;
Camera camera;
IWindowManager windowManager;
public bool IsPreviewing { get; set; }
public Camera Preview
{
get { return camera; }
set
{
camera = value;
if (camera != null)
{
supportedPreviewSizes = Preview.GetParameters().SupportedPreviewSizes;
RequestLayout();
}
}
}
public CameraPreview(Context context)
: base(context)
{
surfaceView = new SurfaceView(context);
AddView(surfaceView);
windowManager = Context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
IsPreviewing = false;
holder = surfaceView.Holder;
holder.AddCallback(this);
MessagingCenter.Subscribe<object>(this, "A", (e) =>
{
camera.TakePicture(null, null, this);
});
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = ResolveSize(SuggestedMinimumWidth, widthMeasureSpec);
int height = ResolveSize(SuggestedMinimumHeight, heightMeasureSpec);
SetMeasuredDimension(width, height);
if (supportedPreviewSizes != null)
{
previewSize = GetOptimalPreviewSize(supportedPreviewSizes, width, height);
}
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);
surfaceView.Measure(msw, msh);
surfaceView.Layout(0, 0, r - l, b - t);
}
public void SurfaceCreated(ISurfaceHolder holder)
{
try
{
if (Preview != null)
{
Preview.SetPreviewDisplay(holder);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(@" ERROR: ", ex.Message);
}
}
public void SurfaceDestroyed(ISurfaceHolder holder)
{
if (Preview != null)
{
Preview.StopPreview();
}
}
public void SurfaceChanged(ISurfaceHolder holder, Android.Graphics.Format format, int width, int height)
{
var parameters = Preview.GetParameters();
parameters.SetPreviewSize(previewSize.Width, previewSize.Height);
RequestLayout();
switch (windowManager.DefaultDisplay.Rotation)
{
case SurfaceOrientation.Rotation0:
camera.SetDisplayOrientation(90);
break;
case SurfaceOrientation.Rotation90:
camera.SetDisplayOrientation(0);
break;
case SurfaceOrientation.Rotation270:
camera.SetDisplayOrientation(180);
break;
}
Preview.SetParameters(parameters);
Preview.StartPreview();
IsPreviewing = true;
}
Camera.Size GetOptimalPreviewSize(IList<Camera.Size> sizes, int w, int h)
{
const double AspectTolerance = 0.1;
double targetRatio = (double)w / h;
if (sizes == null)
{
return null;
}
Camera.Size optimalSize = null;
double minDiff = double.MaxValue;
int targetHeight = h;
foreach (Camera.Size size in sizes)
{
double ratio = (double)size.Width / size.Height;
if (Math.Abs(ratio - targetRatio) > AspectTolerance)
continue;
if (Math.Abs(size.Height - targetHeight) < minDiff)
{
optimalSize = size;
minDiff = Math.Abs(size.Height - targetHeight);
}
}
if (optimalSize == null)
{
minDiff = double.MaxValue;
foreach (Camera.Size size in sizes)
{
if (Math.Abs(size.Height - targetHeight) < minDiff)
{
optimalSize = size;
minDiff = Math.Abs(size.Height - targetHeight);
}
}
}
return optimalSize;
}
public void OnPictureTaken(byte[] data, Camera camera)
{
camera.StopPreview();
FileOutputStream outStream = null;
File dataDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim);
if (data != null)
{
try
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
var s = ts.TotalMilliseconds;
outStream = new FileOutputStream(dataDir + "/" + s + ".jpg");
outStream.Write(data);
outStream.Close();
}
catch (FileNotFoundException e)
{
System.Console.Out.WriteLine(e.Message);
}
catch (IOException ie)
{
System.Console.Out.WriteLine(ie.Message);
}
}
camera.StartPreview();
}
}
CameraPreviewRenderer.cs
public class CameraPreviewRenderer : ViewRenderer<Mobile.App.CameraPreview, CameraPreview>
{
CameraPreview cameraPreview;
public CameraPreviewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Mobile.App.CameraPreview> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Unsubscribe
cameraPreview.Click -= OnCameraPreviewClicked;
}
if (e.NewElement != null)
{
if (Control == null)
{
cameraPreview = new CameraPreview(Context);
SetNativeControl(cameraPreview);
}
Control.Preview = Camera.Open((int)e.NewElement.Camera);
// Subscribe
cameraPreview.Click += OnCameraPreviewClicked;
}
}
void OnCameraPreviewClicked(object sender, EventArgs e)
{
if (cameraPreview.IsPreviewing)
{
cameraPreview.Preview.StopPreview();
cameraPreview.IsPreviewing = false;
}
else
{
cameraPreview.Preview.StartPreview();
cameraPreview.IsPreviewing = true;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Control.Preview.Release();
}
base.Dispose(disposing);
}
}