2021年1月5日 星期二

Xamarin.Forms 使用 Xamarin.Essentials 媒體選擇器

Xamarin.Forms 使用 Xamarin.Essentials 媒體選擇器

在這篇文章將會逐步說明,如何使用 Xamarin.Essentials 套件提供的 媒體選擇器 功能,幫 Xamarin.Forms 可以製作出可以使用照相機鏡頭的拍照功能。

建立專案

  • 開啟 Visual Studio 2019
  • 在 [Visual Studio 2019] 對話窗中,選擇 [建立新的專案]
  • 在 [建立新專案] 對話窗,選擇 [Prism Blank App (Xamarin.Forms)]
  • 點選 [下一步] 按鈕
  • 在 [設定新的專案] 對話窗, [專案名稱] 欄位輸入 xfMediaPicker
  • 點選 [建立] 按鈕
  • 在 [RPISM PROJECT WIZARD] 對話窗內,勾選 [ANDROID] & [iOS]
  • 點選 [CREATE PROJECT] 按鈕

加入與更新套件

  • 在 [方案總管] 視窗內,展開 Xamarin.Forms 專案節點,也就是 [xfMediaPicker]
  • 滑鼠右擊 [相依性節點],點選 [管理 NuGet 套件]
  • 當 [NuGet: xfMediaPicker] 視窗出現後,點選 [瀏覽] 標籤頁次
  • 在文字輸入盒內輸入 PropertyChanged.Fody ,搜尋出這個套件
  • 點選 [PropertyChanged.Fody] 這個套件,安裝到 Xamarin.Forms 專案內
  • 滑鼠右擊 [方案總管] 最上方的節點 [解決方案 xfMediaPicker]
  • 點選 [管理方案的 NuGet 套件]
  • 當 [NuGet: 解決方案] 視窗出現後,點選 [更新] 標籤頁次
  • 點選 [選取所有封裝] ,接著點選 [更新按鈕]
  • 將選取套件更新到最新版本

查看 Xamarin.Essentials 媒體選擇器 使用方式

打開 Xamarin.Essentials 媒體選擇器 文件,可以看到這個 Xamarin.Essentials 媒體選擇器 使用說明

Android 專案修正

  • 找到 Android 專案 [xfMediaPicker.Android]
  • 開啟 [Properties] 資料夾下的 AssemblyInfo.cs 檔案
  • 在最後面加入底下宣告
// Add some common permissions, these can be removed if not needed
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]
// Needed for Picking photo/video
[assembly: UsesPermission(Android.Manifest.Permission.ReadExternalStorage)]

// Needed for Taking photo/video
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]
[assembly: UsesPermission(Android.Manifest.Permission.Camera)]

// Add these properties if you would like to filter out devices that do not have cameras, or set to false to make them optional
[assembly: UsesFeature("android.hardware.camera", Required = true)]
[assembly: UsesFeature("android.hardware.camera.autofocus", Required = true)]

iOS 專案修正

  • 找到 Android 專案 [xfMediaPicker.iOS]
  • 滑鼠右擊 [Info.plist] 檔案,選擇 [開啟方式]
  • 在 [開啟方式 - Info.plist] 對話窗出現後,選擇 [XML (文字) 編輯器]
  • 將底下內容輸入到 </dict> 文字前面
<key>NSCameraUsageDescription</key>
<string>This app needs access to the camera to take photos.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs access to microphone for taking videos.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs access to the photo gallery for picking photos and videos.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to photos gallery for picking photos and videos.</string>

修正首頁頁面

  • 打開 MainPage.xaml 檔案
  • 將這個檔案內容替換為底下內容
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="xfMediaPicker.Views.MainPage"
             Title="Xamarin.Essentials 媒體選擇器">

    <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
        <Label Text="Welcome to Xamarin Forms and Prism!" />
        <Button Text="Take Photo"
                Command="{Binding TakePhotoCommand}"/>
        <Label Text="{Binding FilePath}"/>
        <Image Source="{Binding Photo}"/>
    </StackLayout>

</ContentPage>

修正首頁 ViewModel

  • 打開 MainPageViewModel.cs 檔案
  • 將這個檔案內容替換為底下內容
using Prism.Commands;
using System;

namespace xfMediaPicker.ViewModels
{
    using System.ComponentModel;
    using System.IO;
    using System.Threading.Tasks;
    using Prism.Navigation;
    using Xamarin.Essentials;
    using Xamarin.Forms;

    public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private readonly INavigationService navigationService;
        public string FilePath { get; set; }
        public ImageSource Photo { get; set; }
        public DelegateCommand TakePhotoCommand { get; set; }
        public MainPageViewModel(INavigationService navigationService)
        {
            this.navigationService = navigationService;
            TakePhotoCommand = new DelegateCommand(async () =>
            {
                try
                {
                    FileResult photo = await MediaPicker.CapturePhotoAsync();
                    await LoadPhotoAsync(photo);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"CapturePhotoAsync THREW: {ex.Message}");
                }
            });
        }

        async Task LoadPhotoAsync(FileResult photo)
        {
            // canceled
            if (photo == null)
            {
                FilePath = "";
                return;
            }
            // save the file into local storage
            var newFile = Path.Combine(FileSystem.CacheDirectory, "MyPhoto.png");
            using (var stream = await photo.OpenReadAsync())
            using (var newStream = File.OpenWrite(newFile))
                await stream.CopyToAsync(newStream);

            File.Delete(photo.FullPath);
            FilePath = newFile;

            FileResult showFile = new FileResult(FilePath);
            Photo = ImageSource.FromStream( () =>
            {
                Stream stream = showFile.OpenReadAsync().Result;
                return stream;
            });
        }
        public void OnNavigatedFrom(INavigationParameters parameters)
        {
        }

        public void OnNavigatedTo(INavigationParameters parameters)
        {
        }

    }
}

開始執行這個專案

  • 選擇在 Android 模擬器下來執行這個專案
  • 當應用程式啟動之後,就會看到底下畫面

  • 點選 [TAKE PHOTO] 按鈕
  • 將會出現對話窗,詢問是否允許這個應用程式可以允許拍照或者錄影功能
  • 點選 [ALLOW] 按鈕

  • 現在將會出現底下對話窗,詢問這個應用程式是否可以允許存取圖片、媒體、檔案詢問這個應用程式是否可以允許存取圖片、媒體、檔案
  • 點選 [ALLOW] 按鈕

  • 現在,先回到 Visual Studio 內,打開 [MainPageViewModel.cs]
  • 找到 if (photo == null) 這行
  • 標示這行為中斷點

  • 現在將會看到模擬器出現了模擬的照相功能
  • 請點選最下方的 [照相機] 圖示,表示要拍照

  • 當出現下圖,點選底下的 [打勾] 按鈕

  • 現在程式停在剛剛設定中斷點上
  • 現在可以查看 LoadPhotoAsync 方法的參數 photo 的屬性值內容
  • 可以看到這次拍照的照片檔案存在在哪裡

  • 在我這台電腦上,所拍照的照片將會為這個檔案

/data/user/0/com.companyname.appname/cache/2203693cc04e0be7f4f024d5f9499e13/e5c347e3599d44ddb2f3c0ded01ab830/3fc6f9320d3a49018828d889843a03a7.jpg

  • 繼續執行這個專案,將會看到底下畫面

 




沒有留言:

張貼留言