我有个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;
【讨论】:
这会保存图像,但到画廊的最后,虽然当你用相机拍照时它会保存在顶部。如何将图像保存到图库顶部? 请注意,您还必须将.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.getExternalStoragePublicDirectory
和 Intent.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 项目急需要用这种类似画廊控件的样式,(见图) 中间的图大,两边图渐渐变小的。求救!!的主要内容,如果未能解决你的问题,请参考以下文章
android 卡片画廊效果及RecycleView、ViewPager、ScrollView之前的冲突解决