使用Xamarin.Forms访问摄像头

Fal*_*lko 30 c# camera xamarin.mobile xamarin.forms xamarin.forms.labs

是否有人能够提供一个关于如何使用Xamarin.Forms 1.3.x访问相机的简短,自包含的示例?只需调用本机相机应用程序并检索生成的图片就会很棒.在Xamarin.Forms页面上显示实时视图真棒!

我已经尝试过使用Xamarin.Mobile和Xamarin.Forms.Labs,但我无法在这两个平台上使用任何解决方案(现在专注于Android和iOS).Web上发现的大多数代码片段(包括stackoverflow)都是不完整的,例如没有显示IMediaPicker对象的实现或者锚定拍照方法的位置.

Fal*_*lko 35

我终于为iOS和Android创建了最低限度的解决方案.

共享项目

首先,让我们看一下共享代码.为了在共享App类和特定于平台的代码之间轻松交互,我们Instance在以下内容中存储静态public static App:

public static App Instance;
Run Code Online (Sandbox Code Playgroud)

此外,我们将显示一个Image,稍后将填充内容.所以我们创建一个成员:

readonly Image image = new Image();
Run Code Online (Sandbox Code Playgroud)

App构造函数中,我们存储Instance并创建页面内容,这是一个简单的button和前面提到的image:

public App()
{
   Instance = this;

   var button = new Button {
       Text = "Snap!",
       Command = new Command(o => ShouldTakePicture()),
   };

   MainPage = new ContentPage {
       Content = new StackLayout {
       VerticalOptions = LayoutOptions.Center,
           Children = {
                    button,
                    image,
           },
       },
   };
}
Run Code Online (Sandbox Code Playgroud)

按钮的单击处理程序调用该事件ShouldTakePicture.它是一个公共成员,特​​定于平台的代码部分稍后将分配给它.

public event Action ShouldTakePicture = () => {};
Run Code Online (Sandbox Code Playgroud)

最后,我们提供了一种显示捕获图像的公共方法:

public void ShowImage(string filepath)
{
    image.Source = ImageSource.FromFile(filepath);
}
Run Code Online (Sandbox Code Playgroud)

Android项目

在Android上我们修改了MainActivity.首先,我们为捕获的图像文件定义路径:

static readonly File file = new File(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures), "tmp.jpg");
Run Code Online (Sandbox Code Playgroud)

在结束时,OnCreate我们可以使用Instance创建的静态App并分配一个匿名事件处理程序,它将启动一个新Intent的捕获图像:

App.Instance.ShouldTakePicture += () => {
   var intent = new Intent(MediaStore.ActionImageCapture);
   intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(file));
   StartActivityForResult(intent, 0);
};
Run Code Online (Sandbox Code Playgroud)

最后但同样重要的是,我们的活动必须对生成的图像做出反应.它只是将其文件路径推送到共享ShowImage方法.

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
   base.OnActivityResult(requestCode, resultCode, data);
   App.Instance.ShowImage(file.Path);
}
Run Code Online (Sandbox Code Playgroud)

就是这样!只是不要忘记在"AndroidManifest.xml"中设置"Camera"和"WriteExternalStorage"权限!

iOS项目

对于iOS实现,我们创建了一个自定义渲染器.因此,我们添加一个新文件"CustomContentPageRenderer"并在using语句后面添加相应的程序集属性:

[assembly:ExportRenderer(typeof(ContentPage), typeof(CustomContentPageRenderer))]
Run Code Online (Sandbox Code Playgroud)

CustomContentPageRenderer继承自PageRenderer:

public class CustomContentPageRenderer: PageRenderer
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

我们覆盖该ViewDidAppear方法并添加以下部分.

创建一个新的图像选择器控制器参考相机:

var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
Run Code Online (Sandbox Code Playgroud)

一旦ShouldTakePicture事件被提出,就呈现图像选择器控制器:

App.Instance.ShouldTakePicture += () => PresentViewController(imagePicker, true, null);
Run Code Online (Sandbox Code Playgroud)

拍摄照片后,将其保存到MyDocuments文件夹并调用共享ShowImage方法:

imagePicker.FinishedPickingMedia += (sender, e) => {
            var filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "tmp.png");
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
            InvokeOnMainThread(() => {
                image.AsPNG().Save(filepath, false);
                App.Instance.ShowImage(filepath);
            });
            DismissViewController(true, null);
        };
Run Code Online (Sandbox Code Playgroud)

最后,我们需要处理取消图像处理过程:

imagePicker.Canceled += (sender, e) => DismissViewController(true, null);
Run Code Online (Sandbox Code Playgroud)

  • @NorborIllig你可能想看看[这个稍微更新和简化的版本](http://xforms-kickstarter.com/#camera). (2认同)

Cur*_*ity 5

试试James Montemagno的MediaPlugin.

您只需键入并运行即可使用Package Manager Console安装插件,Install-Package Xam.Plugin.Media -Version 2.6.2或者转到Manage NuGet Packages ...然后输入Xam.Plugin.Media并安装插件.(必须在所有项目中安装插件 - 包括客户端项目)

一个readme.txt文件将被提示,并按照指示.之后,将以下代码(根据需要)添加到共享项目中.上述readme.txt文件中要遵循的说明如下.

对于Android Project

在您的BaseActivity或MainActivity(对于Xamarin.Forms)中添加以下代码:

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
    PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}  
Run Code Online (Sandbox Code Playgroud)

您还必须添加一些其他配置文件以遵守新的严格模式:

  1. 将以下内容添加到< application >标记内的AndroidManifest.xml中:

    <provider android:name="android.support.v4.content.FileProvider" 
              android:authorities="YOUR_APP_PACKAGE_NAME.fileprovider" 
              android:exported="false" 
              android:grantUriPermissions="true">
        <meta-data android:name="android.support.FILE_PROVIDER_PATHS" 
                   android:resource="@xml/file_paths"></meta-data>
    </provider>
    
    Run Code Online (Sandbox Code Playgroud)

    YOUR_APP_PACKAGE_NAME必须设置为您的应用包名称!

  2. 将名为xml的新文件夹添加到Resources文件夹中,并添加一个名为的新XML文件 file_paths.xml

    添加以下代码:

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path name="my_images" path="Android/data/YOUR_APP_PACKAGE_NAME/files/Pictures" />
        <external-path name="my_movies" path="Android/data/YOUR_APP_PACKAGE_NAME/files/Movies" />
    </paths>
    
    Run Code Online (Sandbox Code Playgroud)

    YOUR_APP_PACKAGE_NAME必须设置为您的应用包名称!

对于iOS项目

您的应用程序需要有钥匙,你的Info.plist用于NSCameraUsageDescriptionNSPhotoLibraryUsageDescription以访问设备的摄像头和照片/视频库.如果您正在使用库的视频功能,那么您还必须添加NSMicrophoneUsageDescription.当提示用户提供访问这些设备功能的权限时,将为用户显示为每个密钥提供的字符串.

如:

<key>NSCameraUsageDescription</key>
<string>This app needs access to the camera to take photos.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to photos.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs access to microphone.</string>
Run Code Online (Sandbox Code Playgroud)

对于共享项目

要简单地打开相机,保存照片并显示带有文件路径的警报,请在共享项目中输入以下内容.

if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
    await DisplayAlert("No Camera", ":( No camera avaialble.", "OK");
    return;
}

var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
    PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,
    Directory = "Sample",
    Name = "test.jpg"
});

if (file == null)
    return;

await DisplayAlert("File Location", file.Path, "OK"); 
Run Code Online (Sandbox Code Playgroud)