我有个android 项目急需要用这种类似画廊控件的样式,(见图) 中间的图大,两边图渐渐变小的。求救!!

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我有个android 项目急需要用这种类似画廊控件的样式,(见图) 中间的图大,两边图渐渐变小的。求救!!相关的知识,希望对你有一定的参考价值。

我有个android 项目急需要用这种类似画廊控件的样式,(见图) 中间的图大,两边图渐渐变小的。求救!!在线等,如果有大虾做过,希望可以指点,如有源码可以提供,可以发邮件到1173183403QQ.COM.谢谢

参考技术A Galley + <? extends BaseAdapter> + animations 应该就可以实现 参考技术B 这个类似于Gallery,建议看一下源码

android - 将图像保存到画廊

【中文标题】android - 将图像保存到画廊【英文标题】:android - save image into gallery 【发布时间】:2012-01-23 12:49:23 【问题描述】:

我有一个带有图片库的应用程序,我希望用户可以将其保存到自己的图库中。 我创建了一个带有单个语音“保存”的选项菜单以允许这样做,但问题是...如何将图像保存到图库中?

这是我的代码:

@Override
        public boolean onOptionsItemSelected(MenuItem item) 
            // Handle item selection
            switch (item.getItemId()) 
            case R.id.menuFinale:

                imgView.setDrawingCacheEnabled(true);
                Bitmap bitmap = imgView.getDrawingCache();
                File root = Environment.getExternalStorageDirectory();
                File file = new File(root.getAbsolutePath()+"/DCIM/Camera/img.jpg");
                try 
                
                    file.createNewFile();
                    FileOutputStream ostream = new FileOutputStream(file);
                    bitmap.compress(CompressFormat.JPEG, 100, ostream);
                    ostream.close();
                 
                catch (Exception e) 
                
                    e.printStackTrace();
                



                return true;
            default:
                return super.onOptionsItemSelected(item);
            
        

我不确定这部分代码:

File root = Environment.getExternalStorageDirectory();
                File file = new File(root.getAbsolutePath()+"/DCIM/Camera/img.jpg");

保存到图库是否正确? 不幸的是,代码不起作用:(

【问题讨论】:

您解决了这个问题吗?可以和我分享一下吗 我也有同样的问题***.com/questions/21951558/… 对于那些在保存文件时仍有问题的人,可能是因为您的 url 包含非法字符,例如“?”、“:”和“-”,删除这些,它应该可以工作.这是国外设备和安卓模拟器的常见错误。在这里查看更多信息:***.com/questions/11394616/… 接受的答案在 2019 年有点过时了。我在这里写了一个更新的答案:***.com/questions/36624756/… 【参考方案1】:
MediaStore.Images.Media.insertImage(getContentResolver(), yourBitmap, yourTitle , yourDescription);

之前的代码会将图片添加到图库末尾。如果您想修改日期以使其出现在开头或任何其他元数据,请参阅下面的代码(Cortesy of S-K,samkirton):

https://gist.github.com/samkirton/0242ba81d7ca00b475b9

/**
 * Android internals have been modified to store images in the media folder with 
 * the correct date meta data
 * @author samuelkirton
 */
public class CapturePhotoUtils 

    /**
     * A copy of the Android internals  insertImage method, this method populates the 
     * meta data with DATE_ADDED and DATE_TAKEN. This fixes a common problem where media 
     * that is inserted manually gets saved at the end of the gallery (because date is not populated).
     * @see android.provider.MediaStore.Images.Media#insertImage(ContentResolver, Bitmap, String, String)
     */
    public static final String insertImage(ContentResolver cr, 
            Bitmap source, 
            String title, 
            String description) 

        ContentValues values = new ContentValues();
        values.put(Images.Media.TITLE, title);
        values.put(Images.Media.DISPLAY_NAME, title);
        values.put(Images.Media.DESCRIPTION, description);
        values.put(Images.Media.MIME_TYPE, "image/jpeg");
        // Add the date meta data to ensure the image is added at the front of the gallery
        values.put(Images.Media.DATE_ADDED, System.currentTimeMillis());
        values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis());

        Uri url = null;
        String stringUrl = null;    /* value to be returned */

        try 
            url = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

            if (source != null) 
                OutputStream imageOut = cr.openOutputStream(url);
                try 
                    source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut);
                 finally 
                    imageOut.close();
                

                long id = ContentUris.parseId(url);
                // Wait until MINI_KIND thumbnail is generated.
                Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id, Images.Thumbnails.MINI_KIND, null);
                // This is for backward compatibility.
                storeThumbnail(cr, miniThumb, id, 50F, 50F,Images.Thumbnails.MICRO_KIND);
             else 
                cr.delete(url, null, null);
                url = null;
            
         catch (Exception e) 
            if (url != null) 
                cr.delete(url, null, null);
                url = null;
            
        

        if (url != null) 
            stringUrl = url.toString();
        

        return stringUrl;
    

    /**
     * A copy of the Android internals StoreThumbnail method, it used with the insertImage to
     * populate the android.provider.MediaStore.Images.Media#insertImage with all the correct
     * meta data. The StoreThumbnail method is private so it must be duplicated here.
     * @see android.provider.MediaStore.Images.Media (StoreThumbnail private method)
     */
    private static final Bitmap storeThumbnail(
            ContentResolver cr,
            Bitmap source,
            long id,
            float width, 
            float height,
            int kind) 

        // create the matrix to scale it
        Matrix matrix = new Matrix();

        float scaleX = width / source.getWidth();
        float scaleY = height / source.getHeight();

        matrix.setScale(scaleX, scaleY);

        Bitmap thumb = Bitmap.createBitmap(source, 0, 0,
            source.getWidth(),
            source.getHeight(), matrix,
            true
        );

        ContentValues values = new ContentValues(4);
        values.put(Images.Thumbnails.KIND,kind);
        values.put(Images.Thumbnails.IMAGE_ID,(int)id);
        values.put(Images.Thumbnails.HEIGHT,thumb.getHeight());
        values.put(Images.Thumbnails.WIDTH,thumb.getWidth());

        Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values);

        try 
            OutputStream thumbOut = cr.openOutputStream(url);
            thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
            thumbOut.close();
            return thumb;
         catch (FileNotFoundException ex) 
            return null;
         catch (IOException ex) 
            return null;
        
    

【讨论】:

这会保存图像,但到画廊的最后,虽然当你用相机拍照时它会保存在顶部。如何将图像保存到图库顶部? 请注意,您还必须将 添加到您的 manifext.xml。 图像不会保存在图库顶部,因为在内部 insertImage 不会添加任何日期元数据。请参阅此 GIST:gist.github.com/0242ba81d7ca00b475b9.git 它是 insertImage 方法的精确副本,但它添加了日期元日期以确保将图像添加到画廊的前面。 Here is the correct GIST link mentioned above(需要去掉末尾的.git MediaStore.Images.Media.insertImage(...) 已被弃用。【参考方案2】:

实际上,您可以将图片保存在任何地方。如果您想保存在公共空间中,以便任何其他应用程序可以访问,请使用此代码:

storageDir = new File(
    Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    ), 
    getAlbumName()
);

图片不会进入相册。为此,您需要调用扫描:

private void galleryAddPic() 
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);

您可以在https://developer.android.com/training/camera/photobasics.html#TaskGallery找到更多信息

【讨论】:

这是一个不错的简单解决方案,因为我们不需要更改整个实现,并且我们可以为应用创建自定义文件夹。 当您只能扫描文件时发送广播可能会浪费资源:***.com/a/5814533/43051。 你实际上在哪里传递位图? Environment.getExternalStoragePublicDirectoryIntent.ACTION_MEDIA_SCANNER_SCAN_FILE 现在已弃用...【参考方案3】:

我已经尝试了很多方法来让它在 Marshmallow 和 Lollipop 上运行。 最后,我最终将保存的图片移动到 DCIM 文件夹(新的 Google Photo 应用程序仅在显然位于此文件夹内时才会扫描图像)

public static File createImageFile() throws IOException 
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
         .format(System.currentTimeInMillis());
    File storageDir = new File(Environment
         .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/Camera/");
    if (!storageDir.exists())
        storageDir.mkdirs();
    File image = File.createTempFile(
            timeStamp,                   /* prefix */
            ".jpeg",                     /* suffix */
            storageDir                   /* directory */
    );
    return image;

然后是扫描文件的标准代码,您可以在Google Developers site too 中找到。

public static void addPicToGallery(Context context, String photoPath) 
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(photoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    context.sendBroadcast(mediaScanIntent);

请记住,这个文件夹不可能存在于世界上的每个设备中,并且从 Marshmallow (API 23) 开始,您需要向用户请求 WRITE_EXTERNAL_STORAGE 的权限。

【讨论】:

感谢您提供有关 Google 相册的信息。 这是唯一一个解释得很好的解决方案。没有人提到该文件必须在 DCIM 文件夹中。谢谢!!! Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) 为我解决了问题。谢谢! getExternalStoragePublicDirectory() 现在在 API 29 上已弃用。需要使用 MediaStore @riggaroo 是的,你是对的,丽贝卡,我会尽快更新答案【参考方案4】:

根据this course,正确的做法是:

Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    )

这将为您提供图库目录的根路径。

【讨论】:

我尝试了这个新代码,但它崩溃了 java.lang.NoSuchFieldError: android.os.Environment.DIRECTORY_PICTURES 好的,谢谢,所以没有办法在 android 完美 - 直接指向 Android 开发者网站的链接。这很有效,而且是一个简单的解决方案。 不错的答案,但如果在此处的其他答案中添加“galleryAddPic”方法会更好,因为您通常希望 Gallery 应用程序注意到新图片。 Environment.getExternalStoragePublicDirectory 已被弃用...【参考方案5】:
private void galleryAddPic() 
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);

【讨论】:

【参考方案6】:

您可以在相机文件夹中创建一个目录并保存图像。之后,您可以简单地执行扫描。它会立即在图库中显示您的图像。

String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString()+ "/Camera/Your_Directory_Name";
File myDir = new File(root);
myDir.mkdirs();
String fname = "Image-" + image_name + ".png";
File file = new File(myDir, fname);
System.out.println(file.getAbsolutePath());
if (file.exists()) file.delete();
    Log.i("LOAD", root + fname);
    try 
        FileOutputStream out = new FileOutputStream(file);
        finalBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
        out.flush();
        out.close();
     catch (Exception e) 
       e.printStackTrace();
    

MediaScannerConnection.scanFile(context, new String[]file.getPath(), new String[]"image/jpeg", null);

【讨论】:

在这个标准中这是最好的答案 您的代码中的 finalBitmap 是在哪里初始化的......示例中缺少它 @MichealPaccione 显然,您需要将图像放在位图中。如果您在创建需要保存的图像的位图对象时遇到问题,那就另当别论了。尝试先解决它。【参考方案7】:

这对我有用:

 private fun saveBitmapAsImageToDevice(bitmap: Bitmap?) 
    // Add a specific media item.
    val resolver = this.contentResolver

    val imageStorageAddress = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) 
        MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
     else 
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    

    val imageDetails = ContentValues().apply 
        put(MediaStore.Images.Media.DISPLAY_NAME, "my_app_$System.currentTimeMillis().jpg")
        put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
        put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis())
    

    try 
        // Save the image.
        val contentUri: Uri? = resolver.insert(imageStorageAddress, imageDetails)
        contentUri?.let  uri ->
            // Don't leave an orphan entry in the MediaStore
            if (bitmap == null) resolver.delete(contentUri, null, null)
            val outputStream: OutputStream? = resolver.openOutputStream(uri)
            outputStream?.let  outStream ->
                val isBitmapCompressed =
                    bitmap?.compress(Bitmap.CompressFormat.JPEG, 95, outStream)
                if (isBitmapCompressed == true) 
                    outStream.flush()
                    outStream.close()
                
             ?: throw IOException("Failed to get output stream.")
         ?: throw IOException("Failed to create new MediaStore record.")
     catch (e: IOException) 
        throw e
    

【讨论】:

【参考方案8】:

我带着同样的疑问来到这里,但对于 Android 版 Xamarin,我在保存文件后使用了 Sigrist 答案来执行此方法:

private void UpdateGallery()

    Intent mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
    Java.IO.File file = new Java.IO.File(_path);
    Android.Net.Uri contentUri = Android.Net.Uri.FromFile(file);
    mediaScanIntent.SetData(contentUri);
    Application.Context.SendBroadcast(mediaScanIntent);
 

它解决了我的问题,Thx Sigrist。我把它放在这里是因为我没有为 Xamarin 找到关于这个的答案,我希望它可以帮助其他人。

【讨论】:

【参考方案9】:

在我的情况下,上述解决方案不起作用,我必须执行以下操作:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(f)));

【讨论】:

很高兴知道这个选项,但不幸的是不适用于某些带有 android 6 的设备,所以ContentProvider 更可取的 solytion【参考方案10】:
 String filePath="/storage/emulated/0/DCIM"+app_name;
    File dir=new File(filePath);
    if(!dir.exists())
        dir.mkdir();
    

此代码在onCreate方法中。此代码用于创建app_name的目录。 现在,可以使用 android 中的默认文件管理器应用程序访问此目录。 在需要设置目标文件夹的任何地方使用此字符串 filePath。 我确信这个方法也适用于 Android 7,因为我在它上面进行了测试。因此,它也可以在其他版本的 android 上运行。

【讨论】:

【参考方案11】:

您只需要在保存完成后扫描您的媒体。

 BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
            Bitmap bitmap = drawable.getBitmap();

            File filepath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
            File dir = new File(filepath.getAbsolutePath()+"/Pro Scanner/");
            if(!dir.exists())
                dir.mkdir();
            
            File file = new File(dir,System.currentTimeMillis()+"_Pro_Scanner.png");
            try 
                outputStream = new FileOutputStream(file);
             catch (FileNotFoundException e) 
                e.printStackTrace();
                downloadQRCode.setVisibility(View.VISIBLE);
                loadingBar.setVisibility(View.INVISIBLE);
            
            bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
            Toast.makeText(GenerateQRCodeActivity.this, "QR image saved successfully", Toast.LENGTH_SHORT).show();
            try 
                outputStream.flush();
                outputStream.close();
                loadingBar.setVisibility(View.INVISIBLE);
                downloadDone.setVisibility(View.VISIBLE);
                downloadDone.setAnimation(bottomAnimation);
             catch (IOException e) 
                downloadQRCode.setVisibility(View.VISIBLE);
                loadingBar.setVisibility(View.INVISIBLE);
                e.printStackTrace();
            

            MediaScannerConnection.scanFile(GenerateQRCodeActivity.this,new String[]file.getPath(),new String[] "image/jpeg",null);

这些代码和每个人都一样。如果您在此之后尝试下面的代码,它将起作用。你只需要这一行代码:

MediaScannerConnection.scanFile(GenerateQRCodeActivity.this,new String[]file.getPath(),new String[] "image/jpeg",null);

轰!!!您现在可以在您的图库中获取您保存的图像。

【讨论】:

【参考方案12】:

注意:对于Build.VERSION.SDK_INT

将图像保存到云端是通过让用户在导出之后和删除您的应用 APK 之前打开他们的 Google Photos 或 Amazon Photos 应用来完成的。如果

这是 Q(29 级)之前的 Android 版本的一个错误。 29 级及更高版本直接保存到照片库。

Android 清单 XML

<!-- Adding Read External Storage Permission -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

保存功能

// - Save Image -

@Throws(FileNotFoundException::class)
private fun saveImage(
    bitmap: Bitmap,
    context: Context,
    folderName: String
) 

    if (Build.VERSION.SDK_INT >= 29) 

        val values = ContentValues()
        values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/$folderName")
        values.put(MediaStore.Images.Media.IS_PENDING, true)

        // RELATIVE_PATH and IS_PENDING are introduced in API 29.

        val uri: Uri? = context.contentResolver
            .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

        if (uri != null) 
            saveImageToStream(bitmap, context.contentResolver.openOutputStream(uri))
            values.put(MediaStore.Images.Media.IS_PENDING, false)
            context.contentResolver.update(uri, values, null, null)
        

     else 

        var dir = File(
            applicationContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES),
            ""
        )

        // getExternalStorageDirectory is deprecated in API 29

        if (!dir.exists()) 

            dir.mkdirs()

        

        val date = Date()

        val fullFileName = "myFileName.jpeg"

        val fileName = fullFileName?.substring(0, fullFileName.lastIndexOf("."))
        val extension = fullFileName?.substring(fullFileName.lastIndexOf("."))

        var imageFile = File(
            dir.absolutePath
                .toString() + File.separator
                    + fileName + "_" + Timestamp(date.time).toString()
                    + ".jpg"
        )

        println("imageFile: $imageFile")

        saveImageToStream(bitmap, FileOutputStream(imageFile))

        if (imageFile.getAbsolutePath() != null) 

            val values = ContentValues()

            values.put(MediaStore.Images.Media.DATA, imageFile.absolutePath)

            // .DATA is deprecated in API 29

            context.contentResolver
                .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

        

    



private fun contentValues(): ContentValues? 

    val values = ContentValues()

    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
    values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000)
    values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())

    return values



private fun saveImageToStream(bitmap: Bitmap, outputStream: OutputStream?) 

    println("saveImageToStream")

    if (outputStream != null) 

        try 

            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
            outputStream.close()

            // success dialog

            runOnUiThread 

                val successDialog = SuccessDialog.getInstance(null)
                successDialog.show(supportFragmentManager, SuccessDialog.TAG)

            

         catch (e: Exception) 

            e.printStackTrace()

            // warning dialog

            runOnUiThread 

                val warningDialog = WarningDialog.getInstance(null)
                warningDialog.show(supportFragmentManager, WarningDialog.TAG)

            

        

    


【讨论】:

以上是关于我有个android 项目急需要用这种类似画廊控件的样式,(见图) 中间的图大,两边图渐渐变小的。求救!!的主要内容,如果未能解决你的问题,请参考以下文章

viewpager怎么实现画廊

android 卡片画廊效果及RecycleView、ViewPager、ScrollView之前的冲突解决

Android开发怎么自定义绘制如下图中这种进度条?急需!在线等!

android画廊怎样做出超炫效果

android画廊怎样做出超炫效果

Android滚轮时间选择控件(可扩展自定义)