Xamarin.Forms Android无需NuGet实现相机多拍及ListView绑定
嘿,我来帮你搞定这个多图拍摄并绑定到ListView的问题!你的现有代码只能拍一张,主要是因为用了固定的文件名(每次都会覆盖),而且没有维护拍摄的图片路径集合。下面是不用任何NuGet包的完整解决方案:
第一步:修改安卓端拍摄逻辑(MainActivity.cs)
首先,我们需要替换固定的文件对象,改用动态生成的唯一文件名,同时维护一个集合存储所有拍摄的照片路径,还要处理异步等待拍摄完成的逻辑:
using System; using System.Collections.Generic; using System.Threading.Tasks; using Android.App; using Android.Content; using Android.Content.PM; using Android.OS; using Android.Provider; using Java.IO; using Xamarin.Forms; namespace YourAppNamespace.Droid { [Activity(Label = "YourApp", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity { private List<string> _capturedImagePaths = new List<string>(); private File _currentCaptureFile; private TaskCompletionSource<bool> _onCaptureCompleted; private TaskCompletionSource<bool> _onPermissionGranted; protected override void OnCreate(Bundle savedInstanceState) { TabLayoutResource = Resource.Layout.Tabbar; ToolbarResource = Resource.Layout.Toolbar; base.OnCreate(savedInstanceState); Xamarin.Essentials.Platform.Init(this, savedInstanceState); global::Xamarin.Forms.Forms.Init(this, savedInstanceState); LoadApplication(new App()); // 绑定拍摄触发事件 (Application.Current as App).ShouldTakePicture += async () => { bool keepCapturing = true; while (keepCapturing) { // 检查安卓6.0+动态权限 if (!await CheckAndRequestPermissions()) { await Application.Current.MainPage.DisplayAlert("权限不足", "需要相机和存储权限才能拍摄照片", "确定"); break; } // 生成唯一文件名,避免覆盖 string fileName = $"photo_{DateTime.Now:yyyyMMddHHmmssfff}.jpg"; _currentCaptureFile = new File( Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures), fileName ); // 创建相机Intent var intent = new Intent(MediaStore.ActionImageCapture); intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(_currentCaptureFile)); // 检查是否有可用相机应用 if (intent.ResolveActivity(PackageManager) != null) { _onCaptureCompleted = new TaskCompletionSource<bool>(); StartActivityForResult(intent, 0); await _onCaptureCompleted.Task; // 询问用户是否继续拍摄 keepCapturing = await Application.Current.MainPage.DisplayAlert( "继续拍摄?", "是否再拍一张照片?", "是", "否" ); } else { await Application.Current.MainPage.DisplayAlert("错误", "未找到可用的相机应用", "确定"); keepCapturing = false; } } // 拍摄完成后更新App中的照片集合 (Application.Current as App).UpdateCapturedImages(_capturedImagePaths); }; } protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); if (requestCode == 0 && resultCode == Result.Ok) { // 确认拍摄文件存在 if (_currentCaptureFile?.Exists() ?? false) { _capturedImagePaths.Add(_currentCaptureFile.Path); _onCaptureCompleted?.SetResult(true); } else { _onCaptureCompleted?.SetResult(false); } } else { // 用户取消拍摄 _onCaptureCompleted?.SetResult(false); } _onCaptureCompleted = null; } public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) { base.OnRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1) { bool allGranted = grantResults.All(r => r == Permission.Granted); _onPermissionGranted?.SetResult(allGranted); _onPermissionGranted = null; } } private async Task<bool> CheckAndRequestPermissions() { string[] requiredPermissions = { Manifest.Permission.Camera, Manifest.Permission.WriteExternalStorage }; bool allGranted = true; foreach (var perm in requiredPermissions) { if (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(this, perm) != Permission.Granted) { allGranted = false; break; } } if (!allGranted) { _onPermissionGranted = new TaskCompletionSource<bool>(); Android.Support.V4.App.ActivityCompat.RequestPermissions(this, requiredPermissions, 1); return await _onPermissionGranted.Task; } return true; } } }
第二步:在App类中添加数据绑定支持
在共享项目的App.cs中维护照片路径集合,并实现INotifyPropertyChanged来通知UI更新:
using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using Xamarin.Forms; namespace YourAppNamespace { public partial class App : Application, INotifyPropertyChanged { private List<string> _capturedImages = new List<string>(); public List<string> CapturedImages { get => _capturedImages; set { _capturedImages = value; OnPropertyChanged(); } } public event Func<Task> ShouldTakePicture; public App() { InitializeComponent(); MainPage = new MainPage(); } public void UpdateCapturedImages(List<string> newPaths) { CapturedImages.Clear(); CapturedImages.AddRange(newPaths); OnPropertyChanged(nameof(CapturedImages)); } // 实现INotifyPropertyChanged接口 public new event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
第三步:在Xamarin.Forms页面绑定ListView
在页面XAML中添加ListView和拍摄按钮,并绑定到CapturedImages集合:
<?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="YourAppNamespace.MainPage"> <StackLayout> <!-- 触发拍摄的按钮 --> <Button Text="开始拍摄" Clicked="StartCapture_Clicked" Margin="10"/> <!-- 显示拍摄的照片列表 --> <ListView ItemsSource="{Binding CapturedImages}" Margin="10"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout Orientation="Horizontal" Padding="5"> <Image Source="{Binding .}" HeightRequest="80" WidthRequest="80" Aspect="AspectFill"/> <Label Text="{Binding .}" VerticalOptions="Center" Margin="10,0"/> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage>
然后在页面代码后台添加按钮点击事件:
using System; using Xamarin.Forms; namespace YourAppNamespace { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); BindingContext = App.Current; // 设置绑定上下文为App实例 } private async void StartCapture_Clicked(object sender, EventArgs e) { if ((App.Current as App).ShouldTakePicture != null) { await (App.Current as App).ShouldTakePicture.Invoke(); } } } }
权限配置
在安卓项目的AndroidManifest.xml中添加必要权限:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera" android:required="true" />
这样,用户点击按钮后可以连续拍摄多张照片,每次拍摄后会询问是否继续,所有拍摄的照片路径都会自动显示在ListView里。
内容的提问来源于stack exchange,提问作者Pritish
相关产品推荐
相关产品推荐

