首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Xamarin.Forms实现摄像头的存取

用Xamarin.Forms实现摄像头的存取
EN

Stack Overflow用户
提问于 2015-01-29 05:27:18
回答 4查看 60.5K关注 0票数 35

有没有人能给出一个简短的、自成一体的例子,说明如何用Xamarin.Forms 1.3.x访问相机?只需调用本机相机应用程序并检索结果图片就很好了。在Xamarin.Forms页面上显示一个实时视图将是非常棒的!

我已经尝试过使用Xamarin.Mobile和Xamarin.Forms.Labs,但我无法在这两个平台上找到任何解决方案(目前主要针对安卓和iOS )。大多数在web上找到的代码片段(包括堆栈溢出)都是不完整的,例如,没有显示IMediaPicker对象的实现,也没有显示用于拍照的方法。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-02-03 12:42:45

我最终为iOS和安卓创建了一个最小的解决方案。

共享项目

首先,让我们看看共享代码。为了便于共享App类和特定于平台的代码之间的交互,我们在public static App中存储一个静态Instance

代码语言:javascript
复制
public static App Instance;

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

代码语言:javascript
复制
readonly Image image = new Image();

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

代码语言:javascript
复制
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,
           },
       },
   };
}

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

代码语言:javascript
复制
public event Action ShouldTakePicture = () => {};

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

代码语言:javascript
复制
public void ShowImage(string filepath)
{
    image.Source = ImageSource.FromFile(filepath);
}

Android项目

在安卓系统上,我们修改MainActivity。首先,我们为捕获的图像文件定义一个路径:

代码语言:javascript
复制
static readonly File file = new File(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures), "tmp.jpg");

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

代码语言:javascript
复制
App.Instance.ShouldTakePicture += () => {
   var intent = new Intent(MediaStore.ActionImageCapture);
   intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(file));
   StartActivityForResult(intent, 0);
};

最后但并非最不重要的是,我们的活动必须对产生的图像作出反应。它将简单地将其文件路径推送到共享的ShowImage方法。

代码语言:javascript
复制
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
   base.OnActivityResult(requestCode, resultCode, data);
   App.Instance.ShowImage(file.Path);
}

事情就是这样!只是不要忘记在"AndroidManifest.xml“中设置”照相机“和”AndroidManifest.xml“权限!

iOS项目

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

代码语言:javascript
复制
[assembly:ExportRenderer(typeof(ContentPage), typeof(CustomContentPageRenderer))]

CustomContentPageRenderer继承自PageRenderer

代码语言:javascript
复制
public class CustomContentPageRenderer: PageRenderer
{
    ...
}

我们重写ViewDidAppear方法并添加以下部分。

创建一个新的图像选择器控制器,引用摄像机:

代码语言:javascript
复制
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };

在引发ShouldTakePicture事件后,立即显示图像选择器控制器:

代码语言:javascript
复制
App.Instance.ShouldTakePicture += () => PresentViewController(imagePicker, true, null);

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

代码语言:javascript
复制
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);
        };

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

代码语言:javascript
复制
imagePicker.Canceled += (sender, e) => DismissViewController(true, null);
票数 38
EN

Stack Overflow用户

发布于 2017-06-28 09:11:40

试试James的MediaPlugin

您可以使用包管理控制台安装插件,只需输入并运行Install-Package Xam.Plugin.Media -Version 2.6.2,或者转到管理NuGet包。并键入Xam.Plugin.Media并安装插件。(必须在所有项目中安装插件--包括客户端项目)

将提示一个readme.txt并按照那里的说明进行操作。然后,将添加以下代码 (视需要)用于您的共享项目。上述readme.txt文件中的说明如下所示。

用于Android项目

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

代码语言:javascript
复制
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
    PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}  

还必须添加一些额外的配置文件,以遵循新的严格模式:

  1. 将以下内容添加到<application>标记中的AndroidManifest.xml中: YOUR_APP_PACKAGE_NAME必须设置为您的应用程序包名称!
  2. 将名为xml的新文件夹添加到参考资料文件夹中,并添加一个名为file_paths.xml的新XML文件 添加以下code:YOUR_APP_PACKAGE_NAME必须设置为您的应用程序包名称!

用于iOS项目

为了访问设备的相机和照片/视频库,您的应用程序需要在Info.plist中为NSCameraUsageDescriptionNSPhotoLibraryUsageDescription设置密钥。如果使用的是库的视频功能,那么还必须添加NSMicrophoneUsageDescription。当提示用户提供访问这些设备功能的权限时,您为这些键提供的字符串将显示给用户。

例如:

代码语言:javascript
复制
<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>

共享项目

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

代码语言:javascript
复制
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"); 
票数 5
EN

Stack Overflow用户

发布于 2016-11-25 04:46:48

下面是如何在Xamarin表单上实现交叉Xamarin iOS的方法。

这是一个很好的启动基础,但是它需要一个页面来呈现,在这个页面中,您可以为它指定UIApplication来为相机/照片选择控制器提供UIView。

https://stackoverflow.com/a/28299259/1941942

便携式项目

代码语言:javascript
复制
public interface ICameraProvider
{
    Task<CameraResult> TakePhotoAsync();
    Task<CameraResult> PickPhotoAsync();
}

private Command AttachImage 
{
    var camera = await DependencyService.Get<ICameraProvider>().TakePhotoAsync();
}

iOS项目

代码语言:javascript
复制
[assembly: Xamarin.Forms.Dependency(typeof(CameraProvider))]

public class CameraProvider : ICameraProvider
{
    private UIImagePickerController _imagePicker;
    private CameraResult _result;
    private static TaskCompletionSource<CameraResult> _tcs;

    public async Task<CameraResult> TakePhotoAsync()
    {
        _tcs = new TaskCompletionSource<CameraResult>();

        _imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };

        _imagePicker.FinishedPickingMedia += (sender, e) =>
        {
            _result = new CameraResult();
            var filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "tmp.png");
            var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));

            _result.ImageSource = ImageSource.FromStream(() => new MemoryStream(image.AsPNG().ToArray())); 
            _result.ImageBytes = image.AsPNG().ToArray();
            _result.FilePath = filepath;

            _tcs.TrySetResult(_result);
            _imagePicker.DismissViewController(true, null);
        };

        _imagePicker.Canceled += (sender, e) =>
        {
            UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
        };

        await UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewControllerAsync(_imagePicker, true);

        return await _tcs.Task; 
    }

    public async Task<CameraResult> PickPhotoAsync()
    {
        _tcs = new TaskCompletionSource<CameraResult>();

        _imagePicker = new UIImagePickerController
        {
            SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
            MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary)
        };

        _imagePicker.FinishedPickingMedia += (sender, e) =>
        {

            if (e.Info[UIImagePickerController.MediaType].ToString() == "public.image")
            {
                var filepath = (e.Info[new NSString("UIImagePickerControllerReferenceUrl")] as NSUrl);
                var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
                //var image = e.Info[UIImagePickerController.OriginalImage] as UIImage;

                _result.ImageSource = ImageSource.FromStream(() => new MemoryStream(image.AsPNG().ToArray()));
                _result.ImageBytes = image.AsPNG().ToArray();
                _result.FilePath = filepath?.Path;
            }

            _tcs.TrySetResult(_result);
            _imagePicker.DismissViewController(true, null);
        };

        _imagePicker.Canceled += (sender, e) =>
        {
            UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
        };

        await UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewControllerAsync(_imagePicker, true);

        return await _tcs.Task;
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28207571

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档