允许用户为图像选择相机或图库

Wul*_*gar 149 android android-intent android-gallery android-camera android-intent-chooser

我想做的事情似乎很简单,但经过几天的搜索,我无法弄明白.

我有一个应用程序,允许用户选择多个(最多5个)图像.我正在使用ImageView.当用户点击时ImageView,我想允许他们选择

  1. 从图库中选择图像,或
  2. 使用相机拍摄图像.

我开始使用ACTION_GET_CONTENT意图,这对于进入画廊非常有用.那么我尝试使用ACTION_PICK_ACTIVITY意图允许用户选择相机或图库:

Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
Intent gallIntent=new Intent(Intent.ACTION_GET_CONTENT);
gallIntent.setType("image/*"); 
Intent camIntent = new Intent("android.media.action.IMAGE_CAPTURE");
pickIntent.putExtra(Intent.EXTRA_INTENT, camIntent);
pickIntent.putExtra(Intent.EXTRA_INTENT, gallIntent)
pickIntent.putExtra(Intent.EXTRA_TITLE, "Select Source");
startActivityForResult(pickIntent, IMAGE_SELECTOR);
Run Code Online (Sandbox Code Playgroud)

但似乎我只能添加一个EXTRA_INTENT.菜单按预期显示,但唯一的选项是图库和文件....没有相机).

有没有更好/更简单的方法来做到这一点,我错过了?谢谢你的帮助.

Dav*_*arl 318

如何启动单个Intent以从Gallery或Camera中选择图像,或者注册以浏览文件系统的任何应用程序.

而不是意图的选项列表创建对话框,它是好得多,以获得进入图形图标和各种"摄像机"的短名称使用Intent.createChooser,"画廊",甚至第三方文件系统浏览器的应用程序比如'Astro'等

这描述了如何使用标准选择器意图并添加其他意图.

private Uri outputFileUri;

private void openImageIntent() {

    // Determine Uri of camera image to save.
    final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "MyDir" + File.separator);
    root.mkdirs();
    final String fname = Utils.getUniqueImageFilename();
    final File sdImageMainDirectory = new File(root, fname);
    outputFileUri = Uri.fromFile(sdImageMainDirectory);

    // Camera.
    final List<Intent> cameraIntents = new ArrayList<Intent>();
    final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    final PackageManager packageManager = getPackageManager();
    final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
    for(ResolveInfo res : listCam) {
        final String packageName = res.activityInfo.packageName;
        final Intent intent = new Intent(captureIntent);
        intent.setComponent(new ComponentName(packageName, res.activityInfo.name));
        intent.setPackage(packageName);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
        cameraIntents.add(intent);
    }

    // Filesystem.
    final Intent galleryIntent = new Intent();
    galleryIntent.setType("image/*");
    galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

    // Chooser of filesystem options.
    final Intent chooserIntent = Intent.createChooser(galleryIntent, "Select Source");

    // Add the camera options.
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[cameraIntents.size()]));

    startActivityForResult(chooserIntent, YOUR_SELECT_PICTURE_REQUEST_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        if (requestCode == YOUR_SELECT_PICTURE_REQUEST_CODE) {
            final boolean isCamera;
            if (data == null) {
                isCamera = true;
            } else {
                final String action = data.getAction();
                if (action == null) {
                    isCamera = false;
                } else {
                    isCamera = action.equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                }
            }

            Uri selectedImageUri;
            if (isCamera) {
                selectedImageUri = outputFileUri;
            } else {
                selectedImageUri = data == null ? null : data.getData();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Shajeel,`Utils.getUniqueImageFilename()`是我自己生成唯一文件名的方法.有很多方法可以做到这一点.其中一个最简单的方法是使用类似"img _"+ System.currentTimeMillis()+".jpg"的东西.另一个是`File.createTempFile()`. (30认同)
  • 很好!只是一个快速改进:在第一个其他是isCamera = MediaStore.ACTION_IMAGE_CAPTURE.equals(data.getAction()); 一条线来统治它们;) (12认同)
  • 正如Rohan所说,这在5.1.1上有所改变.你需要做`if(data == null || data.getData()== null)`. (11认同)
  • 这对我很有用,但我有一个问题,即使用相机作为源不是调用onActivityResult而相机本身并没有消失.根本原因是清单中缺少权限:<uses-permission android:name ="android.permission.WRITE_EXTERNAL_STORAGE"/> (10认同)
  • 在我的情况下`final String fname = Utils.getUniqueImageFilename();`不起作用......它说'Utils无法解析':( (7认同)
  • 使用`Intent.ACTION_PICK`而不是`Intent.ACTION_GET_CONTENT`将返回更自然的照片应用程序而不是生成的动作选择器中的文档应用程序. (6认同)
  • 这段代码如何在KitKat OS 4.4上为人们工作?它似乎放弃了"厨房"和"照片"的选择,并用"文件"取而代之,这些文件不是很友好.这篇文章http://androiddev.orkitra.com/?p=128645似乎说这是预期的行为,但它似乎并不是很好. (4认同)
  • 任何人都可以告诉我为什么我为outputFileUri获取null(仅当使用相机时,带有图库才能正常工作)?我的测试设备是带有Anroid 4.2的Galaxy s2. (4认同)
  • 刚刚在5.1.1上运行了这个.我看到数据!= null和data.getAction()== null.这导致附加摄像机捕获的图像失败,因为uri最终为空.有什么指针吗? (4认同)
  • 效果很好!但我怎么能弄清楚女巫来源的图片来自哪里呢?如果用户选择了相机,我的实际代码只处理意图相关性. (3认同)
  • 我使用了这个代码,但isCamara总是返回false,即使我从选择器意图中选择了相机.任何的想法?? (2认同)
  • 我发现它是`if(data == null ||(data.getData()== null && data.getClipData()== null))`因为`data.getClipData()`如果是用户可能不是null从图书馆中选择了多个图像. (2认同)

Kev*_*din 31

您必须创建自己的选择器对话框,合并两个意图解析结果.

为此,您需要使用PackageManager.queryIntentActivities()查询PackageManager以获取两个原始意图,并为每个检索到的活动创建一个新Intent的最终列表,如下所示:

List<Intent> yourIntentsList = new ArrayList<Intent>();

List<ResolveInfo> listCam = packageManager.queryIntentActivities(camIntent, 0);
for (ResolveInfo res : listCam) {
    final Intent finalIntent = new Intent(camIntent);
    finalIntent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
    yourIntentsList.add(finalIntent);
}

List<ResolveInfo> listGall = packageManager.queryIntentActivities(gallIntent, 0);
for (ResolveInfo res : listGall) {
    final Intent finalIntent = new Intent(gallIntent);
    finalIntent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
    yourIntentsList.add(finalIntent);
}
Run Code Online (Sandbox Code Playgroud)

(我在这里直接写了这个,所以这可能无法编译)

然后,有关从列表创建自定义对话框的更多信息,请参阅https://developer.android.com/guide/topics/ui/dialogs.html#AlertDialog


ple*_*xus 22

我找到了这个.使用:

galleryIntent.setType("image/*");
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
Run Code Online (Sandbox Code Playgroud)

其中一个意图向用户显示在Android 4中选择"文档"的选项,我发现这非常令人困惑.使用它代替显示'gallery'选项:

Intent pickIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
Run Code Online (Sandbox Code Playgroud)


小智 12

我也有这个问题,我所做的是创建一个AlertDialog并使用setItems()方法和DialogInterface监听器:

AlertDialog.Builder getImageFrom = new AlertDialog.Builder(Fotos.this);
getImageFrom.setTitle("Select:");
final CharSequence[] opsChars = {getResources().getString(R.string.takepic), getResources().getString(R.string.opengallery)};
getImageFrom.setItems(opsChars, new android.content.DialogInterface.OnClickListener(){

    @Override
    public void onClick(DialogInterface dialog, int which) {
        if(which == 0){
            Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);
        }else
            if(which == 1){
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(Intent.createChooser(intent,
                    getResources().getString(R.string.pickgallery)), SELECT_PICTURE);
            }
        dialog.dismiss();
    }
});
Run Code Online (Sandbox Code Playgroud)


Mar*_*sco 11

我已经合并了一些解决方案,以便从Gallery或Camera中选择一个完整的util.这些是ImagePicker util的功能(也在Github lib中):

  • 合并了Gallery和Camera resquests的意图.
  • 调整所选大图像的大小(例如:2500 x 1600)
  • 如果需要,旋转图像

截图:

ImagePicker开始意图

编辑:这是一个代码片段,用于将Gallery和Camera应用程序合并为Intent.你可以在ImagePicker util(也在Github lib中)看到完整的代码:

public static Intent getPickImageIntent(Context context) {
    Intent chooserIntent = null;

    List<Intent> intentList = new ArrayList<>();

    Intent pickIntent = new Intent(Intent.ACTION_PICK,
            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    takePhotoIntent.putExtra("return-data", true);
    takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTempFile(context)));
    intentList = addIntentsToList(context, intentList, pickIntent);
    intentList = addIntentsToList(context, intentList, takePhotoIntent);

    if (intentList.size() > 0) {
        chooserIntent = Intent.createChooser(intentList.remove(intentList.size() - 1),
                context.getString(R.string.pick_image_intent_text));
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[]{}));
    }

    return chooserIntent;
}

private static List<Intent> addIntentsToList(Context context, List<Intent> list, Intent intent) {
    List<ResolveInfo> resInfo = context.getPackageManager().queryIntentActivities(intent, 0);
    for (ResolveInfo resolveInfo : resInfo) {
        String packageName = resolveInfo.activityInfo.packageName;
        Intent targetedIntent = new Intent(intent);
        targetedIntent.setPackage(packageName);
        list.add(targetedIntent);
    }
    return list;
}
Run Code Online (Sandbox Code Playgroud)


Sid*_*mit 8

此代码将帮助您,因为有两个按钮用于Camera,另一个用于Gallery,Image将显示在ImageView中

https://github.com/siddhpuraamitr/Choose-Image-From-Gallery-Or-Camera

  • 虽然此链接可能会回答这个问题,但最好在此处包含答案的基本部分并提供参考链接.如果链接的页面发生更改,则仅链接的答案可能会无效 (5认同)

Sha*_*hah 6

这应该照顾Tina的null outputFileUri问题:

private static final String STORED_INSTANCE_KEY_FILE_URI = "output_file_uri";

@Override
public void onSaveInstanceState( Bundle outState ) {
    super.onSaveInstanceState( outState );

    if ( outputFileUri != null ) {
        outState.putString( STORED_INSTANCE_KEY_FILE_URI, outputFileUri.toString() );
    }
}

@Override
public void onViewStateRestored( Bundle savedInstanceState ) {
    super.onViewStateRestored( savedInstanceState );

    if ( savedInstanceState != null ) {
      final String outputFileUriStr = savedInstanceState.getString( STORED_INSTANCE_KEY_FILE_URI );
      if ( outputFileUriStr != null && !outputFileUriStr.isEmpty() ) {
          outputFileUri = Uri.parse( outputFileUriStr );
      }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:我在android.support.v4.app.Fragment中使用此代码,根据您正在使用的Fragment/Activity版本,重写的方法可能会发生变化.


小智 6

对于那些在尝试使用图像选择时向上获得4.4错误的人可以使用下面的代码.

最好使用Intent.createChooser来访问各种"相机","图库"甚至第三方文件系统浏览器应用程序的图形图标和短名称,而不是创建带有Intent选项列表的Dialog.比如'Astro'等

这描述了如何使用标准选择器意图并添加其他意图.

private void openImageIntent(){

    // Determine Uri of camera image to save.
    final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "amfb" + File.separator);
    root.mkdir();
    final String fname = "img_" + System.currentTimeMillis() + ".jpg";
    final File sdImageMainDirectory = new File(root, fname);
    outputFileUri = Uri.fromFile(sdImageMainDirectory);

    // Camera.
    final List<Intent> cameraIntents = new ArrayList<Intent>();
    final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    final PackageManager packageManager = getPackageManager();
    final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
    for (ResolveInfo res : listCam){
        final String packageName = res.activityInfo.packageName;
        final Intent intent = new Intent(captureIntent);
        intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
        intent.setPackage(packageName);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
        cameraIntents.add(intent);
    }

    //FileSystem
    final Intent galleryIntent = new Intent();
    galleryIntent.setType("image/");
    galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

    // Chooser of filesystem options.
    final Intent chooserIntent = Intent.createChooser(galleryIntent, "Select Source");
    // Add the camera options.
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
    startActivityForResult(chooserIntent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);

}


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    //super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) {
            final boolean isCamera;
            if (data == null) {
                isCamera = true;
            } else {
                final String action = data.getAction();
                if (action == null) {
                    isCamera = false;
                } else {
                    isCamera = action.equals(MediaStore.ACTION_IMAGE_CAPTURE);
                }
            }

            Uri selectedImageUri;
            if (isCamera) {
                selectedImageUri = outputFileUri;
                //Bitmap factory
                BitmapFactory.Options options = new BitmapFactory.Options();
                // downsizing image as it throws OutOfMemory Exception for larger
                // images
                options.inSampleSize = 8;
                final Bitmap bitmap = BitmapFactory.decodeFile(selectedImageUri.getPath(), options);
                preview.setImageBitmap(bitmap);
            } else {
                selectedImageUri = data == null ? null : data.getData();
                Log.d("ImageURI", selectedImageUri.getLastPathSegment());
                // /Bitmap factory
                BitmapFactory.Options options = new BitmapFactory.Options();
                // downsizing image as it throws OutOfMemory Exception for larger
                // images
                options.inSampleSize = 8;
                try {//Using Input Stream to get uri did the trick
                    InputStream input = getContentResolver().openInputStream(selectedImageUri);
                    final Bitmap bitmap = BitmapFactory.decodeStream(input);
                    preview.setImageBitmap(bitmap);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    } else if (resultCode == RESULT_CANCELED){
        // user cancelled Image capture
        Toast.makeText(getApplicationContext(),
                "User cancelled image capture", Toast.LENGTH_SHORT)
                .show();
    } else {
        // failed to capture image
        Toast.makeText(getApplicationContext(),
                "Sorry! Failed to capture image", Toast.LENGTH_SHORT)
                .show();
    }
}
Run Code Online (Sandbox Code Playgroud)


Muh*_*que 5

您可以创建选项对话框

开放式摄像头:

Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                                MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString());
                        if (cameraIntent.resolveActivity(getActivity().getPackageManager()) != null) {
                            startActivityForResult(cameraIntent, CAMERA_IMAGE);
                        }
Run Code Online (Sandbox Code Playgroud)

打开图库:

if (Build.VERSION.SDK_INT <= 19) {
            Intent i = new Intent();
            i.setType("image/*");
            i.setAction(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            startActivityForResult(i, GALLARY_IMAGE);
        } else if (Build.VERSION.SDK_INT > 19) {
            Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(intent, GALLARY_IMAGE);
        }
Run Code Online (Sandbox Code Playgroud)

获得选择结果

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == GALLARY_IMAGE) {
                Uri selectedImageUri = data.getData();
                String selectedImagePath = getRealPathFromURI(selectedImageUri);
            } else if (requestCode == CAMERA_IMAGE) {
                Bundle extras = data.getExtras();
                Bitmap bmp = (Bitmap) extras.get("data");
                SaveImage(bmp);
            }
        }
    }

 public String getRealPathFromURI(Uri uri) {
        if (uri == null) {
            return null;
        }
        String[] projection = {MediaStore.Images.Media.DATA};
        Cursor cursor = getActivity().getContentResolver().query(uri, projection, null, null, null);
        if (cursor != null) {
            int column_index = cursor
                    .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }
        return uri.getPath();
    }
Run Code Online (Sandbox Code Playgroud)

保存捕获图像的方法

 private void SaveImage(final Bitmap finalBitmap) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                String root = Environment.getExternalStorageDirectory().toString();

                File myDir = new File(root + "/Captured Images/");
                if (!myDir.exists())
                    myDir.mkdirs();

                String fname = "/image-" + System.currentTimeMillis() + ".jpg";
                File file = new File(myDir, fname);
                try {
                    FileOutputStream out = new FileOutputStream(file);
                    finalBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
                    out.flush();
                    out.close();
                    localImagePath = myDir + fname;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }


        });
        t.start();

    }
Run Code Online (Sandbox Code Playgroud)