栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

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

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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;



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);
    }
  }

  
  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 {
    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;



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

public abstract class GuardedAsyncTask 
    extends AsyncTask {

  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

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/159554.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号