Android实现长按图片保存至相册功能

前言:前面写了一篇reactnative的学习笔记,说reactnative的Android框架中有很多福利,确实是的,也说到了我们app中的一个把图片保存到相册的功能,好吧,还是准备写一篇博客,就当笔记了~

先上几张app的图片:

一进app就是一个进度条加载图片(我待会也会说一下进度条view跟怎么监听图片加载过程):

图片加载完毕后:

长按图片进入相册可以看到我们保存的图片:

监听图片加载的loaddingview源码(不是很难,我就直接贴代码了):

package com.leo.camerroll; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.widget.ProgressBar; /** * Created by leo on 17/1/22. */ public class LoadingView extends ProgressBar { private final int DEFAULT_RADIUS = dp2px(15); private final int DEFAULT_REACH_COLOR = 0XFFFFFFFF; private final int DEFAULT_UNREACH_COLOR = 0X88000000; private final long ANIM_DURATION = 1000; private final String BASE_TEXT = "00%"; private boolean isStop; private int mRadius = DEFAULT_RADIUS; private int mStrokeWidth; private Paint reachPaint; private Paint unreachPaint; private Paint textPaint; private Paint bgPaint; private int mStartAngle=0; private float mSweepAngle=360*0.382f; private ValueAnimator anim; public LoadingView(Context context) { this(context, null); } public LoadingView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } private void initView() { reachPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); reachPaint.setStrokeCap(Paint.Cap.ROUND); reachPaint.setStyle(Paint.Style.STROKE); unreachPaint = new Paint(reachPaint); reachPaint.setColor(DEFAULT_REACH_COLOR); unreachPaint.setColor(DEFAULT_UNREACH_COLOR); textPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); textPaint.setStyle(Paint.Style.STROKE); textPaint.setColor(Color.WHITE); textPaint.setFakeBoldText(true); bgPaint=new Paint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG); bgPaint.setStrokeCap(Paint.Cap.ROUND); bgPaint.setColor(Color.argb(44,0,0,0)); setMax(100); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int defWidth = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); int defHeight = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); int expectSize = Math.min(defHeight, defWidth); if (expectSize <= 0) { expectSize = mRadius * 2; } else { mRadius = expectSize / 2; } mStrokeWidth = mRadius / 5; reachPaint.setStrokeWidth(mStrokeWidth); unreachPaint.setStrokeWidth(mStrokeWidth); setMeasuredDimension(expectSize, expectSize); float textSize=0; while(true){ textSize+=0.1; textPaint.setTextSize(textSize); if(textPaint.measureText(BASE_TEXT,0,BASE_TEXT.length())>=mRadius){ break; } } } @Override protected synchronized void onDraw(Canvas canvas) { if(isStop){ setVisibility(View.GONE); return; } //drawbackground transparent canvas.drawCircle(getWidth()/2,getWidth()/2,mRadius-mStrokeWidth,bgPaint); //draw reach drawProgressReach(canvas); //draw progress text drawProgressText(canvas); } private void drawProgressText(Canvas canvas) { String text=String.valueOf((int)(getProgress()*1.0f/getMax()*100))+"%"; int centerX=getWidth()/2; int centerY=getWidth()/2; int baseX= (int) (centerX-textPaint.measureText(text,0,text.length())/2); int baseY= (int) (centerY-(textPaint.getFontMetrics().ascent+textPaint.getFontMetrics().descent)/2); canvas.drawText(text,baseX,baseY,textPaint); } private void drawProgressReach(Canvas canvas) { canvas.drawArc(new RectF(0 + mStrokeWidth / 2, 0 + mStrokeWidth / 2, mRadius * 2 - mStrokeWidth / 2, mRadius * 2 - mStrokeWidth / 2), mStartAngle, mSweepAngle, false, reachPaint); //drawonreach canvas.drawArc(new RectF(0 + mStrokeWidth / 2, 0 + mStrokeWidth / 2, mRadius * 2 - mStrokeWidth / 2, mRadius * 2 - mStrokeWidth / 2), mStartAngle+mSweepAngle, 360-mSweepAngle,false, unreachPaint); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if(anim==null){ anim=ValueAnimator.ofInt(0,360); anim.setInterpolator(new LinearInterpolator()); anim.setDuration(ANIM_DURATION); anim.setRepeatCount(Animation.INFINITE); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { if(animation!=null&&animation.getAnimatedValue()!=null){ int startAngle= (int) animation.getAnimatedValue(); mStartAngle=startAngle; postInvalidate(); } } }); }else{ anim.cancel(); anim.removeAllUpdateListeners(); } anim.start(); } public void loadCompleted() { isStop=true; if(anim!=null){ anim.cancel(); anim.removeAllUpdateListeners(); this.setVisibility(View.GONE); } } /** * @param size * @return px */ private int dp2px(int size) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, getContext().getResources().getDisplayMetrics()); } }

实现起来还是很简单的,就是动态改变两端弧的起点和终点,通过属性动画不断的在(0-360)循环,代码应该还算比较清晰哈!~~~~

图片加载用了一个AsyncTask:

private class DownImageTask extends AsyncTask<String, Long, Bitmap> { private ImageView imageView; private long contentLength; public DownImageTask(ImageView imageView) { this.imageView = imageView; } @Override protected Bitmap doInBackground(String... params) { Bitmap bitmap = null; BufferedInputStream bis = null; ByteArrayOutputStream bos = null; try { File fileDir=new File(getApplication().getExternalCacheDir(),"images"); if(fileDir==null||!fileDir.isDirectory()){ fileDir.mkdir(); } File file=new File(fileDir.getAbsolutePath()+"/"+params[0].hashCode()+".png"); if(file!=null&&file.length()>0){ return bitmap=BitmapFactory.decodeFile(file.getAbsolutePath()); } bos=new ByteArrayOutputStream(); byte[] buffer = new byte[512]; long total=0; int len ; URL url = new URL(params[0]); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); this.contentLength = conn.getContentLength(); bis = new BufferedInputStream(conn.getInputStream()); while ((len = bis.read(buffer)) != -1) { total+=len; publishProgress(total); Thread.sleep(100); bos.write(buffer, 0, len); bos.flush(); } bitmap= BitmapFactory.decodeByteArray(bos.toByteArray(),0,bos.toByteArray().length); saveBitmapToDisk(bos,params[0]); } catch (Exception e) { e.printStackTrace(); } finally { try { if (bis != null) { bis.close(); } if (bos != null) { bos.close(); } } catch (IOException e) { e.printStackTrace(); } } return bitmap; } private void saveBitmapToDisk(final ByteArrayOutputStream baos, final String url) { new Thread(){ @Override public void run() {BufferedOutputStream bos=null; try{ if(!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){ Log.e("TAG","内存卡不存在"); return; } Log.e("TAG","开始保存图片至内存卡~~"); byte[] bytes = baos.toByteArray(); File fileDir=new File(getApplication().getExternalCacheDir(),"images"); if(fileDir==null||!fileDir.isDirectory()){ fileDir.mkdir(); } File file=new File(fileDir.getAbsolutePath()+"/"+url.hashCode()+".png"); file.createNewFile(); bos=new BufferedOutputStream(new FileOutputStream(file)); bos.write(bytes); bos.flush(); Log.e("TAG","图片已经保存至内存卡~~"); }catch (Exception e){ e.printStackTrace(); }finally { if(bos!=null){ try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }.start(); } @Override protected void onProgressUpdate(Long... values) { mLoadingView.setProgress((int) ((values[0].longValue() * 1.0f / contentLength) * 100)); } @Override protected void onPostExecute(Bitmap bitmap) { if (imageView != null && bitmap != null) { imageView.setImageBitmap(bitmap); mLoadingView.loadCompleted(); } } }

加载完毕后把图片存放在了内存卡中(当然,这是我随便写的一个图片加载,大家换成自己的加载框架哈,):

private void saveBitmapToDisk(final ByteArrayOutputStream baos, final String url) { new Thread(){ @Override public void run() {BufferedOutputStream bos=null; try{ if(!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){ Log.e("TAG","内存卡不存在"); return; } Log.e("TAG","开始保存图片至内存卡~~"); byte[] bytes = baos.toByteArray(); File fileDir=new File(getApplication().getExternalCacheDir(),"images"); if(fileDir==null||!fileDir.isDirectory()){ fileDir.mkdir(); } File file=new File(fileDir.getAbsolutePath()+"/"+url.hashCode()+".png"); file.createNewFile(); bos=new BufferedOutputStream(new FileOutputStream(file)); bos.write(bytes); bos.flush(); Log.e("TAG","图片已经保存至内存卡~~"); }catch (Exception e){ e.printStackTrace(); }finally { if(bos!=null){ try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }.start(); }

这里我们是需要把图片保存到内存卡中,所以考虑到了android 6.0的运行时权限,所以小伙伴们也一定要判断哦,我在oncreate的时候就判断了:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestAlertWindowPermission(); } } private static final int REQUEST_CODE = 1; private void requestAlertWindowPermission() { ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_CODE); }

下面就是讲长按图片保存至相册了:

mImageView.setOnLongClickListener(new View.OnLongClickListener(){ @Override public boolean onLongClick(View v) { if(mImageView.getDrawable() instanceof BitmapDrawable){ Toast.makeText(getApplicationContext(),"长按保存图片至相册",Toast.LENGTH_SHORT).show(); File fileDir=new File(getApplication().getExternalCacheDir(),"images"); File file=new File(fileDir.getAbsolutePath()+"/"+IMAGE_URL.hashCode()+".png"); if(file!=null&&file.length()>0){ CameraRollManager rollManager=new CameraRollManager(MainActivity.this, Uri.parse(file.getAbsolutePath())); rollManager.execute(); } } return false; } });

CameraRollManager是我直接copy的reactnatvie中的android模块的代码:

CameraRollManager.java

package com.leo.camerroll.camera; import android.content.Context; import android.content.Intent; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.widget.Toast; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; /** * Created by leo on 17/1/22. */ public class CameraRollManager extends GuardedAsyncTask{ private static Context mContext; private final Uri mUri; private static Handler handler=new Handler(Looper.getMainLooper()){ @Override public void handleMessage(Message msg) { Toast.makeText(mContext,"保存成功!",Toast.LENGTH_SHORT).show(); Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); mContext.startActivity(intent); } }; public CameraRollManager(Context context, Uri uri) { super(context); mContext = context; mUri = uri; } @Override protected void doInBackgroundGuarded(Object[] params) { File source = new File(mUri.getPath()); FileChannel input = null, output = null; try { File exportDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); exportDir.mkdirs(); if (!exportDir.isDirectory()) { return; } File dest = new File(exportDir, source.getName()); int n = 0; String fullSourceName = source.getName(); String sourceName, sourceExt; if (fullSourceName.indexOf('.') >= 0) { sourceName = fullSourceName.substring(0, fullSourceName.lastIndexOf('.')); sourceExt = fullSourceName.substring(fullSourceName.lastIndexOf('.')); } else { sourceName = fullSourceName; sourceExt = ""; } while (!dest.createNewFile()) { dest = new File(exportDir, sourceName + "_" + (n++) + sourceExt); } input = new FileInputStream(source).getChannel(); output = new FileOutputStream(dest).getChannel(); output.transferFrom(input, 0, input.size()); input.close(); output.close(); MediaScannerConnection.scanFile( mContext, new String[]{dest.getAbsolutePath()}, null, new MediaScannerConnection.OnScanCompletedListener() { @Override public void onScanCompleted(String path, Uri uri) { handler.sendEmptyMessage(0); } }); } catch (IOException e) { } finally { if (input != null && input.isOpen()) { try { input.close(); } catch (IOException e) { } } if (output != null && output.isOpen()) { try { output.close(); } catch (IOException e) { } } } } }

GuardedAsyncTask.java:

package com.leo.camerroll.camera; import android.content.Context; import android.os.AsyncTask; /** * Created by leo on 17/1/22. */ public abstract class GuardedAsyncTask <Params, Progress> extends AsyncTask<Params, Progress, Void> { private final Context mReactContext; protected GuardedAsyncTask(Context reactContext) { mReactContext = reactContext; } @Override protected final Void doInBackground(Params... params) { try { doInBackgroundGuarded(params); } catch (RuntimeException e) { } return null; } protected abstract void doInBackgroundGuarded(Params... params); }

好啦!!! 看着简单哈,花了我一个上午的时间,还是自己不熟练的原因额,感觉高了一段时间rn,结果android原生又生疏了,小伙伴们如果也像我一样的话,一定要常练习哦,两个东西都是需要常敲的那种,不然又忘记了!!!

最后附上demo的git链接:
https://github.com/913453448/CamerRoll

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-10-01 04:10:54

Android实现长按图片保存至相册功能的相关文章

安卓图片保存到相册但是不显示出来的问题

问题描述 安卓图片保存到相册但是不显示出来的问题 已经通过下面的代码把网络图片存入sd卡上的dcim目录了,可是打开相册,里面没有下载的图片,是红米手机,请问怎么回事? public static void saveFile(Bitmap bm, String fileName, String path) throws IOException { String subForder = SAVE_REAL_PATH + path; File foder = new File(subForder);

管理-Android中怎么把图片添加进相册

问题描述 Android中怎么把图片添加进相册 Android中管理相册的类是哪个啊我想把图片存进相册应该怎么做呢我是把工程目录下的图片获取了然后存入到相册里面 解决方案 这个应该是利用系统的ContentProvider进行.参照下面博客,http://blog.csdn.net/mr_dsw/article/details/48524977 解决方案二: Android 相册图片 添加应用到分享列表android裁剪相册图片Android 保存图片到系统相册 解决方案三: 把你的图片放在相册

iOS实现图片保存与搜索功能_IOS

本文实现Photos.framework的常见功能,包括:创建自定义相册.保存图片到自定义相册.搜索所有相册的图片,具体内容如下1.保存图片到相册 /** * 保存图片到相册 */ - (IBAction)saveImage { PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; if (status == PHAuthorizationStatusDenied) { NSLog(@"请到[设置-隐私-照片]打

利用SurfaceView预览,拍照且保存至相册

mainActivity如下: package c.c; import java.io.IOException; import java.util.Iterator; import java.util.List; import android.app.Activity; import android.content.ContentResolver; import android.content.pm.ActivityInfo; import android.content.res.Configu

android中如何将一个图片处理成相同长和宽?

问题描述 android中如何将一个图片处理成相同长和宽? 我实现了一个从手机相册获得图片的功能,获得的图片的高和宽是不相等,图片是一个长方形,要怎样处理才能将它的宽和高是相等的? 解决方案 public static Bitmap createTargetSizeBitmap(int targetSizeBitmap image){ int w = image.getWidth(); int h = image.getHeight(); Matrix m = new Matrix(); m.p

Android 图片存入系统相册更新显示实例详解

Android 图片存入系统相册更新显示实例详解 在开发android的过程中,我们避免不了可能会涉及到做一个自定义相册或则会去本地创建一个文件夹来存储我们需要的图片.拿相册来说,比如我们创建一个test的文件夹,拍完一张照片后存储到这个指定的test文件夹里,然后在相册里面显示出来,就像微信的效果一样.拍完即可立即显示.但是,在实际开发过程中我们保存完一张图片后并不能立即更新显示出来这个图片,需要我们重启手机才能在系统相册中显示出来. 这里先提供一个插入系统图库的方法: MediaStore.

viewpager-怎么把res文件夹下drawable文件夹下的图片保存到本地或者本地相册

问题描述 怎么把res文件夹下drawable文件夹下的图片保存到本地或者本地相册 我有一个项目是需要把res文件夹下的drawable文件夹下的图片保存到本地相册或者SD卡里面 我有一个viewpager 点击当前的图片让其保存到本地相册或者SD卡 我怎么获取当前的drawable? 解决方案 可以给viewpager里面的imageView添加事件,然后进行保存. 保存imageview到本地: http://www.codes51.com/article/detail_151353.htm

图片下载 图片缓存-android下载图片保存到本地图片大小为0KB,是什么原因??求大神解决

问题描述 android下载图片保存到本地图片大小为0KB,是什么原因??求大神解决 public Drawable loadImageFromUrl(String urlPath, String directory, String filename) { byte[] data = null; InputStream is = null; Drawable drawable = null; HttpURLConnection conn = null; URL url = null; try {

Android 实现WebView点击图片查看大图列表及图片保存功能

在日常开发过程中,有时候会遇到需要在app中嵌入网页,此时使用WebView实现效果,但在默认情况下是无法点击图片查看大图的,更无法保存图片.本文将就这一系列问题的实现进行说明. 图示: 项目的知识点: 加载网页后如何捕捉网页中的图片点击事件: 获取点击的图片资源后进行图片显示,获取整个页面所有的图片: 支持查看上下一张的图片以及对图片缩放显示: 对图片进行保存: 其他:图片缓存的处理(不用每次都重新加载已查看过的图片) 项目代码结构: 前期准备(添加权限.依赖和混淆设置): 添加权限: <us