xamarin 拍照功能和相册浏览功能,c#源码详解,兼容android sdk 5.0至8.0

13 篇文章 3 订阅
10 篇文章 1 订阅

        原来以为拍照比较简单,后来发现android对拍照的权限根据不同的版本要求不同,储存的权限也是要求动态或取的,动态或取其实讲白了,就是要app主动去获取,同事在xml也要写权限。本人花了一些时间整理了一下给大家。源文件在我的下载里。
        最后鄙视一下那些自恃清高(大学霸)的人,一边卖着xamarin稀少的资源,一边管开发者们叫“伸手党”,令人反感。博客精神就是开源开放,让大家少花不必要的时间,大家的时间都很宝贵,有源码有demo干嘛不用。

本案例包括5部分:

1、Main.axml,其实比较简单,就两个按钮,一个imageview。

2、MainActivity.cs,也就是主窗体的cs文件,里面包括了拍照,拍完会看,浏览相册,看相册某一张的基本功能

3、BitmapHelpers.cs,看图片的类,没什么好说的,无非就是设定一下图片横看还是竖看,图片框的大小等信息

4、CameraHelper.cs,文件的路径类,读文件的取和保存

5、AndroidManifest.xml权限类的放置位置,该文件在vs 的 properties下

好了,直接上代码:

1、Main.axml,视图文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:text="浏览"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_Browse" />
    <Button
        android:text="拍照"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_Shot" />
    <ImageView
        android:src="@android:drawable/ic_menu_gallery"
        android:layout_width="match_parent"
        android:layout_height="418.5dp"
        android:id="@+id/imageView1" />
</LinearLayout>

2、MainActivity.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Provider;
using Android.Database;
using System.Threading;
using Java.IO;
using Android.Graphics;
using Environment = Android.OS.Environment;
using Uri = Android.Net.Uri;
using Android.Content.PM;
using Android;

namespace CallLocalPhoto
{
    [Activity(Label = "CallLocalPhoto", MainLauncher = true)]
    public class MainActivity : Activity
    {
        Button btn_Browse,btn_Shot;
        ImageView iv;
        public static File _file;
        public static File _dir;
        public static Bitmap bitmap;

        private Java.IO.File originalFile;
        private File finalFile;

        private string imgName;
        private int requestCode_browse=2;
        private int requestCode_shot=0;

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.Main);

            //其他安卓芯片的默认拍照路径
            originalFile = new Java.IO.File(Android.OS.Environment.GetExternalStoragePublicDirectory(
                Android.OS.Environment.DirectoryPictures
                ), "zcb_pic_" + SystemClock.CurrentThreadTimeMillis() + ".jpg");

            //高通芯片的默认拍照路径
            finalFile = new Java.IO.File(Android.OS.Environment.GetExternalStoragePublicDirectory(
                Android.OS.Environment.DirectoryDcim  +@"/Camera"
                ), "zcb_pic_" + SystemClock.CurrentThreadTimeMillis() + ".jpg");


            if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.M)
            {
                initPhotoError();
            }

            btn_Browse = FindViewById<Button>(Resource.Id.btn_Browse);
            btn_Shot = FindViewById<Button>(Resource.Id.btn_Shot);
            iv = FindViewById<ImageView>(Resource.Id.imageView1);
            btn_Browse.Click += Btn_Browse_Click;
            btn_Shot.Click += TakeAPicture;

            if (IsThereAnAppToTakePictures())   //判断本设备是否存在拍照功能
                {
                //可以自己创建拍照的路径,也可以选择默认的相册路径
                   // CreateDirectoryForPictures();
                }
            else
                {
                    Toast.MakeText(this, "无拍照功能 !", ToastLength.Long).Show();
                }
        }


      

        /// <summary>
        ///  判断是否具备拍照功能
        /// </summary>
        /// <returns></returns>
        private bool IsThereAnAppToTakePictures()
        {
            Intent intent = new Intent(MediaStore.ActionImageCapture);
            IList<ResolveInfo> availableActivities =    PackageManager.QueryIntentActivities(intent, PackageInfoFlags.MatchDefaultOnly);
            return availableActivities != null && availableActivities.Count > 0;
        }

        /// <summary>
        /// 创建目录图片
        /// </summary> 
        private void CreateDirectoryForPictures()
        {
            CameraHelper._dir = new File(
            Environment.GetExternalStoragePublicDirectory(
            Environment.DirectoryPictures), "CameraAppDemo");        //CameraAppDemo
            if (!CameraHelper._dir.Exists())
            {
                CameraHelper._dir.Mkdirs();
                Toast.MakeText(this, "有拍照功能 "+ CameraHelper._dir + "路径已创建成功!", ToastLength.Long).Show();
            }
            else
            {
                Toast.MakeText(this, "有拍照功能 " + CameraHelper._dir + "路径已存在!", ToastLength.Long).Show();
            }
        }


   //浏览相册
        private void Btn_Browse_Click(object sender, EventArgs e)
        {
             Intent _intentCut = new Intent(Intent.ActionPick, null);
            _intentCut.SetType("image/*");// 设置文件类型
            CameraHelper._file = finalFile;//照片的保存路径即相册

            _intentCut.PutExtra(MediaStore.ExtraOutput, Android.Net.Uri.FromFile(CameraHelper._file));
          StartActivityForResult(_intentCut, requestCode_browse); //2代表看相册
        }

        /// <summary>
        /// 拍照
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="eventArgs"></param>
        private void TakeAPicture(object sender, EventArgs eventArgs)
        {
              try
            {
                // 摄像头拍摄
                    Intent intent = new Intent(MediaStore.ActionImageCapture);
                if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.M)
                {
                    //判断是否授予了权限
                    if (ApplicationContext.CheckSelfPermission(Android.Manifest.Permission.Camera) != Android.Content.PM.Permission.Granted)
                    {
                        //没有权限,当场申请
                        RequestPermissions(new string[] { Android.Manifest.Permission.Camera }, 1);
                        Toast.MakeText(this, "没有拍照权限,正在授予", ToastLength.Long).Show();
                    }
                    else
                    {
                        Toast.MakeText(this, "有拍照权限了", ToastLength.Long).Show();
                    }
                    if (ApplicationContext.CheckSelfPermission(Manifest.Permission.ReadExternalStorage) != Android.Content.PM.Permission.Granted)
                    {
                        //RequestPermissions(new String[] {Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage,Manifest.Permission.Camera}, 1);
                        RequestPermissions(new String[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage, }, 1);
                     
                        Toast.MakeText(this, "没有读写扩展卡权限,正在授予", ToastLength.Long).Show();
                    }
                    else
                    {
                        Toast.MakeText(this, "有读写扩展卡权限了", ToastLength.Long).Show();
                    }
                }

        

               CameraHelper._file = finalFile;//照片的保存路径
                intent.PutExtra(MediaStore.ExtraOutput, Android.Net.Uri.FromFile(CameraHelper._file));
                StartActivityForResult(intent, requestCode_shot);

            }
            catch (Exception ex)
            {
                Toast.MakeText(this,   "Shot Error:" + ex.ToString (), ToastLength.Long).Show();
            }


          
        }


        private void initPhotoError()
        {
            // android 7.0系统解决拍照的问题
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.SetVmPolicy(builder.Build());
            builder.DetectFileUriExposure();
        }

  

        /// <summary>
        /// 选择图片后返回
        /// </summary>
        /// <param name="requestCode"></param>
        /// <param name="ResultStatus"></param>
        /// <param name="data"></param>
        protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result ResultStatus, Intent data)
        {
            if (ResultStatus != Result.Ok)
            {
                return;
            }
         
                if (requestCode == requestCode_browse)//看相册请求
                {
                    /*
                    * 若系统版本低于4.4,返回原uri
                    * 若高于4.4,解析uri后返回
                    * */
                    if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
                    {
                        //var url = Android.Net.Uri.Parse("file://" + GetPath(BaseContext, data.Data));
                    var url = Android.Net.Uri.Parse("file://" + GetPath(BaseContext, data.Data));

                    data.SetData(url);
                        //将本地相册照片显示在控件上
                        iv.SetImageURI(Android.Net.Uri.FromFile(new File(GetPath(BaseContext, data.Data))));
                        string fileName = url.LastPathSegment.ToString();
                        Toast.MakeText(this, fileName, ToastLength.Long).Show();

                    }
                }

            try
            {
                if (requestCode == requestCode_shot)//拍照看照片请求
                {
                    if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
                    {
                        int height = Resources.DisplayMetrics.HeightPixels;
                        int width = iv.Height;

                        //获取拍照的位图
                        CameraHelper.bitmap = CameraHelper._file.Path.LoadAndResizeBitmap(width, height);
                        if (CameraHelper.bitmap != null)
                        {
                            //将图片绑定到控件上
                            iv.SetImageBitmap(CameraHelper.bitmap);

                            //清空bitmap 否则会出现oom问题
                            CameraHelper.bitmap = null;
                        }

                        // Dispose of the Java side bitmap.
                        GC.Collect();

                        string fileName = CameraHelper._file.Name.ToString();
                        Toast.MakeText(this, fileName, ToastLength.Long).Show();
                    }

                }
            }
            catch (Exception ex)
            {
                Toast.MakeText(this, "拍照回调错误:" + ex.ToString(), ToastLength.Long).Show();

            }

        }


        #region 高于 v4.4 版本 解析真实路径
        public static String GetPath(Context context, Android.Net.Uri uri)
        {

            bool isKitKat = Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat;

            // DocumentProvider  
            if (isKitKat && DocumentsContract.IsDocumentUri(context, uri))
            {
                // ExternalStorageProvider  
                if (isExternalStorageDocument(uri))
                {
                    String docId = DocumentsContract.GetDocumentId(uri);
                    String[] split = docId.Split(':');
                    String type = split[0];

                    if ("primary".Equals(type.ToLower()))
                    {
                        return Android.OS.Environment.ExternalStorageDirectory + "/" + split[1];
                    }

                    // TODO handle non-primary volumes  
                }
                // DownloadsProvider  
                else if (isDownloadsDocument(uri))
                {

                    String id = DocumentsContract.GetDocumentId(uri);
                    Android.Net.Uri contentUri = ContentUris.WithAppendedId(
                            Android.Net.Uri.Parse("content://downloads/public_downloads"), long.Parse(id));

                    return getDataColumn(context, contentUri, null, null);
                }
                // MediaProvider  
                else if (isMediaDocument(uri))
                {
                    String docId = DocumentsContract.GetDocumentId(uri);
                    String[] split = docId.Split(':');
                    String type = split[0];

                    Android.Net.Uri contentUri = null;
                    if ("image".Equals(type))
                    {
                        contentUri = MediaStore.Images.Media.ExternalContentUri;
                    }
                    else if ("video".Equals(type))
                    {
                        contentUri = MediaStore.Video.Media.ExternalContentUri;
                    }
                    else if ("audio".Equals(type))
                    {
                        contentUri = MediaStore.Audio.Media.ExternalContentUri;
                    }

                    String selection = "_id=?";
                    String[] selectionArgs = new String[] {
                    split[1]
            };

                    return getDataColumn(context, contentUri, selection, selectionArgs);
                }
            }
            // MediaStore (and general)  
            else if ("content".Equals(uri.Scheme.ToLower()))
            {

                // Return the remote address  
                if (isGooglePhotosUri(uri))
                    return uri.LastPathSegment;

                return getDataColumn(context, uri, null, null);
            }
            // File  
            else if ("file".Equals(uri.Scheme.ToLower()))
            {
                return uri.Path;
            }

            return null;
        }

        /** 
         * Get the value of the data column for this Uri. This is useful for 
         * MediaStore Uris, and other file-based ContentProviders. 
         * 
         * @param context The context. 
         * @param uri The Uri to query. 
         * @param selection (Optional) Filter used in the query. 
         * @param selectionArgs (Optional) Selection arguments used in the query. 
         * @return The value of the _data column, which is typically a file path. 
         */
        public static String getDataColumn(Context context, Android.Net.Uri uri, String selection,  String[] selectionArgs)
        {

            ICursor cursor = null;
            String column = "_data";
            String[] projection = {
                column
            };

            try
            {
                cursor = context.ContentResolver.Query(uri, projection, selection, selectionArgs,
                        null);
                if (cursor != null && cursor.MoveToFirst())
                {
                    int index = cursor.GetColumnIndexOrThrow(column);
                    return cursor.GetString(index);
                }
            }
            finally
            {
                if (cursor != null)
                    cursor.Close();
            }
            return null;
        }


        /** 
         * @param uri The Uri to check. 
         * @return Whether the Uri authority is ExternalStorageProvider. 
         */
        public static bool isExternalStorageDocument(Android.Net.Uri uri)
        {
            return "com.android.externalstorage.documents".Equals(uri.Authority);
        }

        /** 
         * @param uri The Uri to check. 
         * @return Whether the Uri authority is DownloadsProvider. 
         */
        public static bool isDownloadsDocument(Android.Net.Uri uri)
        {
            return "com.android.providers.downloads.documents".Equals(uri.Authority);
        }

        /** 
         * @param uri The Uri to check. 
         * @return Whether the Uri authority is MediaProvider. 
         */
        public static bool isMediaDocument(Android.Net.Uri uri)
        {
            return "com.android.providers.media.documents".Equals(uri.Authority);
        }

        /** 
         * @param uri The Uri to check. 
         * @return Whether the Uri authority is Google Photos. 
         */
        public static bool isGooglePhotosUri(Android.Net.Uri uri)
        {
            return "com.google.android.apps.photos.content".Equals(uri.Authority);
        }

        #endregion


    }


    }
 

3、BitmapHelpers.cs

namespace CallLocalPhoto
{
    using System.IO;

    using Android.Graphics;

    public static class BitmapHelpers
    {
        public static Bitmap LoadAndResizeBitmap(this string fileName, int width, int height)
        {
            // First we get the the dimensions of the file on disk
            BitmapFactory.Options options = new BitmapFactory.Options { InJustDecodeBounds = true };
            BitmapFactory.DecodeFile(fileName, options);

            // Next we calculate the ratio that we need to resize the image by
            // in order to fit the requested dimensions.
            int outHeight = options.OutHeight;
            int outWidth = options.OutWidth;
            int inSampleSize = 1;

            if (outHeight > height || outWidth > width)
            {
                inSampleSize = outWidth > outHeight
                                   ? outHeight / height
                                   : outWidth / width;
            }

            // Now we will load the image and have BitmapFactory resize it for us.
            options.InSampleSize = inSampleSize;
            options.InJustDecodeBounds = false;
            Bitmap resizedBitmap = BitmapFactory.DecodeFile(fileName, options);

            return resizedBitmap;
        }
    }
}

4、CameraHelper.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.IO;

namespace CallLocalPhoto
{
    class CameraHelper
    {
        public static File _file;
        public static File _dir;
        public static Bitmap bitmap;


        public static void CreateDirectoryForPictures()
        {
            _dir = new File(   Android.OS.Environment.GetExternalStoragePublicDirectory(   Android.OS.Environment.DirectoryPictures), "CameraAppDemo");
            if (!_dir.Exists())
            {
                _dir.Mkdirs();
            }
        }

        public static Bitmap LoadAndResizeBitmap(string fileName, int width, int height)
        {
            // First we get the the dimensions of the file on disk
            BitmapFactory.Options options = new BitmapFactory.Options { InJustDecodeBounds = true };
            BitmapFactory.DecodeFile(fileName, options);

            // Next we calculate the ratio that we need to resize the image by
            // in order to fit the requested dimensions.
            int outHeight = options.OutHeight;
            int outWidth = options.OutWidth;
            int inSampleSize = 1;

            if (outHeight > height || outWidth > width)
            {
                inSampleSize = outWidth > outHeight
                                   ? outHeight / height
                                   : outWidth / width;
            }

            // Now we will load the image and have BitmapFactory resize it for us.
            options.InSampleSize = inSampleSize;
            options.InJustDecodeBounds = false;
            Bitmap resizedBitmap = BitmapFactory.DecodeFile(fileName, options);

            return resizedBitmap;

        }
    } 
}

 

5、AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="CallLocalPhoto.CallLocalPhoto" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="27" />

  <uses-feature android:name="android.hardware.camera" />
  <!-- 相机权限 -->
  <uses-permission android:name="android.permission.CAMERA" />
  <!--写入SD卡的权限:如果你希望保存相机拍照后的照片-->
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <!--读取SD卡的权限:打开相册选取图片所必须的权限-->
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  
  <!-- 录音权限 
  <uses-permission android:name="android.permission.RECORD_AUDIO" />-->
 <!--软件自主安装升级权限
  <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />-->
  <application android:allowBackup="true" android:label="@string/app_name"></application>


</manifest>

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值