From 80577fa1ef47110a0c202e6e6c239b64d5911860 Mon Sep 17 00:00:00 2001 From: hewro Date: Tue, 14 Aug 2018 17:58:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E6=88=AA=E5=9B=BE?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyDataBase.java | 21 ++- .../activity/MainActivity.java | 22 ++- .../bean/Expression.java | 2 +- .../task/GenerateScreenshotTask.java | 113 +++++++++++++ .../task/SaveImageToGalleryTask.java | 2 + .../util/FileUtil.java | 5 +- .../util/UIUtil.java | 110 +++++++++++- .../view/ExpImageDialog.java | 5 +- .../view/LetterSpacingTextView.java | 156 ++++++++++++++++++ .../main/res/layout/share_one_sreenshot.xml | 74 +++++++++ 10 files changed, 495 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/com/ihewro/android_expression_package/task/GenerateScreenshotTask.java create mode 100644 app/src/main/java/com/ihewro/android_expression_package/view/LetterSpacingTextView.java create mode 100644 app/src/main/res/layout/share_one_sreenshot.xml diff --git a/app/src/main/java/com/ihewro/android_expression_package/MyDataBase.java b/app/src/main/java/com/ihewro/android_expression_package/MyDataBase.java index dd65b75..88ef4e8 100644 --- a/app/src/main/java/com/ihewro/android_expression_package/MyDataBase.java +++ b/app/src/main/java/com/ihewro/android_expression_package/MyDataBase.java @@ -36,32 +36,41 @@ */ public class MyDataBase { - - /** * 把一个表情信息加入到数据库 * @param expression * @return */ public static boolean addExpressionRecord(Expression expression,File source){ + + byte[] bytes = fileToCompressedBytes(source); + if (bytes!=null){ + return false; + }else { + return addExpressionRecord(expression,bytes); + } + } + + private static byte[] fileToCompressedBytes(File source){ //先进行图片压缩,避免数据太大,导致读取问题 - File compressToFile = null; + File compressToFile; compressToFile = FileUtil.returnCompressExp(source); ALog.d("压缩后的路径" + compressToFile.getAbsolutePath() + "大小" + compressToFile.length()); byte[] bytes = FileUtil.fileToBytes(compressToFile); ALog.d("文件大小为" + bytes.length); if (bytes.length>2060826){ - return false; + return null; }else { //因为compressToFile 和 source是同一个文件,所以先判断下,再决定是否删除 if (compressToFile.exists() && !Objects.equals(compressToFile.getAbsolutePath(), source.getAbsolutePath())){ compressToFile.delete(); } - return addExpressionRecord(expression,bytes); + return bytes; } - } + + public static boolean addExpressionRecord(Expression expression,byte[] source) { //1. 检查有没有表情对应的目录 List expressionFolderList = LitePal.where("name = ? and exist = ?",expression.getFolderName(), String.valueOf(1)).find(ExpressionFolder.class); diff --git a/app/src/main/java/com/ihewro/android_expression_package/activity/MainActivity.java b/app/src/main/java/com/ihewro/android_expression_package/activity/MainActivity.java index 24c4cd3..2aedd51 100644 --- a/app/src/main/java/com/ihewro/android_expression_package/activity/MainActivity.java +++ b/app/src/main/java/com/ihewro/android_expression_package/activity/MainActivity.java @@ -66,6 +66,7 @@ import com.ihewro.android_expression_package.fragment.ExpressionContentFragment; import com.ihewro.android_expression_package.http.HttpUtil; import com.ihewro.android_expression_package.task.CheckUpdateTask; +import com.ihewro.android_expression_package.task.GenerateScreenshotTask; import com.ihewro.android_expression_package.task.RecoverDataTask; import com.ihewro.android_expression_package.task.RemoveCacheTask; import com.ihewro.android_expression_package.task.GetExpFolderTask; @@ -691,13 +692,26 @@ public void onLoadFailed(@Nullable Drawable errorDrawable) { topImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - - Expression expression = new Expression(2, oneDetailLists.getDate().substring(0, 10) + (currentItem) + ".jpg", oneDetailList.get(currentItem).getImgUrl(), "头图"); - ExpImageDialog expImageDialog = new ExpImageDialog.Builder(MainActivity.this) + //生成截图 + final Expression expression = new Expression(3, oneDetailLists.getDate().substring(0, 10) + (currentItem) + ".jpg", oneDetailList.get(currentItem).getImgUrl(), "头图"); + final ExpImageDialog expImageDialog = new ExpImageDialog.Builder(MainActivity.this) .setContext(MainActivity.this, null,3) .build(); expImageDialog.setImageData(expression); - expImageDialog.show(); + + //判断是否已经生成过了 + File file = new File(GlobalConfig.appDirPath + expression.getFolderName() + "/" + expression.getName()); + if (file.exists()){ + expImageDialog.show(); + }else { + new GenerateScreenshotTask(MainActivity.this, oneText.getText().toString(), expression, new TaskListener() { + @Override + public void onFinish(Boolean result) { + expImageDialog.show(); + } + }).execute(); + } + } }); } diff --git a/app/src/main/java/com/ihewro/android_expression_package/bean/Expression.java b/app/src/main/java/com/ihewro/android_expression_package/bean/Expression.java index 1411727..8d39f60 100644 --- a/app/src/main/java/com/ihewro/android_expression_package/bean/Expression.java +++ b/app/src/main/java/com/ihewro/android_expression_package/bean/Expression.java @@ -19,7 +19,7 @@ public class Expression extends LitePalSupport{ private int id;//主键 - private int status;//标志位,图片来源:~~-1 apk内置图片~~ 1 sd卡图片 2 网络图片 + private int status;//标志位,图片来源:~~-1 apk内置图片~~ 1 数据库图片 2 网络图片 3 本机图片(数据库中没有存,头图分享卡片就是这种类型) private String name;//图片名称 private String url;//图片路径或者图片地址 private String folderName;//目录的名称 diff --git a/app/src/main/java/com/ihewro/android_expression_package/task/GenerateScreenshotTask.java b/app/src/main/java/com/ihewro/android_expression_package/task/GenerateScreenshotTask.java new file mode 100644 index 0000000..bc8cb58 --- /dev/null +++ b/app/src/main/java/com/ihewro/android_expression_package/task/GenerateScreenshotTask.java @@ -0,0 +1,113 @@ +package com.ihewro.android_expression_package.task; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.afollestad.materialdialogs.MaterialDialog; +import com.blankj.ALog; +import com.bumptech.glide.Glide; +import com.bumptech.glide.Priority; +import com.bumptech.glide.request.RequestOptions; +import com.ihewro.android_expression_package.R; +import com.ihewro.android_expression_package.bean.Expression; +import com.ihewro.android_expression_package.callback.TaskListener; +import com.ihewro.android_expression_package.util.UIUtil; + +import java.util.concurrent.ExecutionException; + +import es.dmoral.toasty.Toasty; + +/** + *
+ *     author : hewro
+ *     e-mail : ihewro@163.com
+ *     time   : 2018/08/12
+ *     desc   :
+ *     version: 1.0
+ * 
+ */ +public class GenerateScreenshotTask extends AsyncTask { + + private Activity activity; + private String content; + private MaterialDialog dialog; + private TaskListener listener; + private Expression expression; + private Bitmap.Config[] configs + = {Bitmap.Config.ALPHA_8, Bitmap.Config.ARGB_4444, Bitmap.Config.ARGB_8888, Bitmap.Config.RGB_565}; + + public GenerateScreenshotTask(Activity activity, String content ,Expression expression, TaskListener listener) { + this.activity = activity; + this.content = content; + this.listener = listener; + this.expression = expression; + } + + @Override + protected void onPreExecute() { + dialog = new MaterialDialog.Builder(activity) + .content("生成分享图片中……") + .progress(true, 0) + .progressIndeterminateStyle(true) + .show(); + } + + @Override + protected Boolean doInBackground(Void... voids) { + View view = activity.getLayoutInflater().inflate(R.layout.share_one_sreenshot,null); + View v = view.findViewById(R.id.item_view); + ImageView headerImage = view.findViewById(R.id.headerImage); + TextView date = view.findViewById(R.id.dateText); + TextView content = view.findViewById(R.id.content); + ALog.d("名称为" + expression.getName().substring(0,10)); + String text = expression.getName().substring(0,10); + //设置布局内容 + Drawable imageFile = null; + try { + imageFile = Glide.with(activity).asDrawable() + .apply(RequestOptions.priorityOf(Priority.HIGH).onlyRetrieveFromCache(true)) + .load(expression.getUrl()) + .submit().get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + if(imageFile != null){ + headerImage.setImageDrawable(imageFile); + }else { + return false; + } + date.setText(text); + content.setText(this.content); + //生成截图 + v.setDrawingCacheEnabled(true); + //measure()实际测量 自己显示在屏幕上的宽高 2个参数,int widthMeasureSpec 和 int heightMeasureSpec表示具体的测量规则。 + v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); + //确定View的大小和位置的,然后将其绘制出来 + v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); + //调用getDrawingCache方法就可 以获得view的cache图片 + Bitmap bb = Bitmap.createBitmap(v.getDrawingCache()); + //系统把原来的cache销毁 + v.setDrawingCacheEnabled(false); + + + // 保存bitmap到sd卡 + UIUtil.saveBitmapToSdCard(activity,bb,"头图/" + expression.getName()); + return true; + } + + @Override + protected void onPostExecute(Boolean aBoolean) { + Toasty.success(activity, "保存成功", Toast.LENGTH_SHORT).show(); + dialog.dismiss(); + listener.onFinish(true); + } +} diff --git a/app/src/main/java/com/ihewro/android_expression_package/task/SaveImageToGalleryTask.java b/app/src/main/java/com/ihewro/android_expression_package/task/SaveImageToGalleryTask.java index b4d3061..9736794 100644 --- a/app/src/main/java/com/ihewro/android_expression_package/task/SaveImageToGalleryTask.java +++ b/app/src/main/java/com/ihewro/android_expression_package/task/SaveImageToGalleryTask.java @@ -71,6 +71,8 @@ protected Boolean doInBackground(Expression... expressions) { } return result; + }else if (expression.getStatus() == 3){//本机图片 + return true; }else {//未知来源图片 return false; } diff --git a/app/src/main/java/com/ihewro/android_expression_package/util/FileUtil.java b/app/src/main/java/com/ihewro/android_expression_package/util/FileUtil.java index 9a0763f..9e95916 100644 --- a/app/src/main/java/com/ihewro/android_expression_package/util/FileUtil.java +++ b/app/src/main/java/com/ihewro/android_expression_package/util/FileUtil.java @@ -213,7 +213,8 @@ public static byte[] fileToBytes(String file) { return fileToBytes(new File(file)); } - public static byte[] fileToBytes(File file){ + + public static byte[] fileToBytes(File file){ InputStream is = null; byte[] bytes = null; try { @@ -249,4 +250,6 @@ public static File returnCompressExp(File file){ return null; } + + } diff --git a/app/src/main/java/com/ihewro/android_expression_package/util/UIUtil.java b/app/src/main/java/com/ihewro/android_expression_package/util/UIUtil.java index fa5fde2..2613127 100644 --- a/app/src/main/java/com/ihewro/android_expression_package/util/UIUtil.java +++ b/app/src/main/java/com/ihewro/android_expression_package/util/UIUtil.java @@ -2,6 +2,7 @@ import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.content.res.AssetFileDescriptor; import android.content.res.Resources; import android.graphics.Bitmap; @@ -14,15 +15,20 @@ import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.AsyncTask; +import android.os.Environment; import android.os.Handler; +import android.view.View; import android.widget.ImageView; +import android.widget.Toast; import com.blankj.ALog; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.GlideException; import com.bumptech.glide.request.RequestOptions; +import com.ihewro.android_expression_package.GlobalConfig; import com.ihewro.android_expression_package.MyApplication; import com.ihewro.android_expression_package.R; import com.ihewro.android_expression_package.bean.Expression; @@ -35,11 +41,15 @@ import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; +import es.dmoral.toasty.Toasty; + import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade; /** @@ -120,6 +130,10 @@ public static void setImageToImageView(Expression expression, final ImageView im final RequestOptions options = new RequestOptions() .placeholder(R.drawable.loading) .error(R.drawable.fail); + final RequestOptions options2 = new RequestOptions() + .placeholder(R.drawable.loading) + .error(R.drawable.fail) + .dontAnimate(); switch (expression.getStatus()){ case 1: if (expression.getImage() ==null ||expression.getImage().length == 0){ @@ -132,13 +146,16 @@ public void onFinish(Expression expression) { }else { //ALog.d("有图片数据"); Glide.with(UIUtil.getContext()).load(expression.getImage()).apply(options).transition(withCrossFade()).into(imageView); - } - break; case 2: Glide.with(UIUtil.getContext()).load(expression.getUrl()).apply(options).transition(withCrossFade()).into(imageView); break; + + case 3: + Glide.with(UIUtil.getContext()).asBitmap().load(GlobalConfig.appDirPath + expression.getFolderName() + "/" + expression.getName()).apply(options2).into(imageView); + + break; } } @@ -289,5 +306,94 @@ public static void goodEgg(int times, TaskListener listener){ } + /** + * 手动测量摆放View + * 对于手动 inflate 或者其他方式代码生成加载的View进行测量,避免该View无尺寸 + * @param v + * @param width + * @param height + */ + public static void layoutView(View v, int width, int height) { + // validate view.width and view.height + v.layout(0, 0, width, height); + int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY); + int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY); + + // validate view.measurewidth and view.measureheight + v.measure(measuredWidth, measuredHeight); + v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); + } + + + public static int px2dip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + /** + * 获取一个 View 的缓存视图 + * (前提是这个View已经渲染完成显示在页面上) + * @param view + * @return + */ + public static Bitmap getCacheBitmapFromView(View view) { + final boolean drawingCacheEnabled = true; + view.setDrawingCacheEnabled(drawingCacheEnabled); + view.buildDrawingCache(drawingCacheEnabled); + final Bitmap drawingCache = view.getDrawingCache(); + Bitmap bitmap; + if (drawingCache != null) { + bitmap = Bitmap.createBitmap(drawingCache); + view.setDrawingCacheEnabled(false); + } else { + bitmap = null; + } + return bitmap; + } + public static boolean saveBitmapToSdCard(Context context, Bitmap mybitmap, String name){ + boolean result = false; + //创建位图保存目录 + String path = GlobalConfig.appDirPath + name; + File sd = new File(path); + File fileParent = sd.getParentFile();//如果表情包目录都不存在,则需要先创建目录 + if(!fileParent.exists()){ + fileParent.mkdirs(); + } + + File file = new File(path); + if (!file.exists()){ + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + FileOutputStream fileOutputStream = null; + try { + // 判断SD卡是否存在,并且是否具有读写权限 + if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ + fileOutputStream = new FileOutputStream(file); + ALog.d(mybitmap); + mybitmap.compress(Bitmap.CompressFormat.JPEG,100,fileOutputStream); + fileOutputStream.flush(); + fileOutputStream.close(); + + //update gallery + Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + Uri uri = Uri.fromFile(file); + intent.setData(uri); + context.sendBroadcast(intent); + ALog.d("哈哈哈哈哈哈哈"); + result = true; + } + else{ + } + + } catch (IOException e) { + e.printStackTrace(); + } + return result; + } + } diff --git a/app/src/main/java/com/ihewro/android_expression_package/view/ExpImageDialog.java b/app/src/main/java/com/ihewro/android_expression_package/view/ExpImageDialog.java index 2e20207..333e51c 100644 --- a/app/src/main/java/com/ihewro/android_expression_package/view/ExpImageDialog.java +++ b/app/src/main/java/com/ihewro/android_expression_package/view/ExpImageDialog.java @@ -135,7 +135,10 @@ private void updateUI(){ }else { inputText.setText(""); } - }else { + } else if (expression.getStatus() == 3){ + delete.setVisibility(View.VISIBLE); + save.setVisibility(View.GONE); + } else if (expression.getStatus() == 2){ delete.setVisibility(View.GONE); inputView.setVisibility(View.GONE); } diff --git a/app/src/main/java/com/ihewro/android_expression_package/view/LetterSpacingTextView.java b/app/src/main/java/com/ihewro/android_expression_package/view/LetterSpacingTextView.java new file mode 100644 index 0000000..abaad2a --- /dev/null +++ b/app/src/main/java/com/ihewro/android_expression_package/view/LetterSpacingTextView.java @@ -0,0 +1,156 @@ +package com.ihewro.android_expression_package.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.ScaleXSpan; +import android.util.AttributeSet; +import android.widget.TextView; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + *
+ *     author : hewro
+ *     e-mail : ihewro@163.com
+ *     time   : 2018/08/12
+ *     desc   :
+ *     version: 1.0
+ * 
+ */ +public class LetterSpacingTextView extends android.support.v7.widget.AppCompatTextView { + + private String content; + private int width; + private Paint paint; + private int xPadding; + private int yPadding; + private int textHeight; + private int xPaddingMin; + int count; + //记录每个字的二维数组 + int[][] position; + + public LetterSpacingTextView(Context context) { + super(context); + init(); + } + + public LetterSpacingTextView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public LetterSpacingTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public void setText(String str) { + width = this.getWidth(); + getPositions(str); + //重新画控件 + this.invalidate(); + } + public void init() { + + paint = new Paint(); + paint.setColor(Color.parseColor("#888888")); + paint.setTypeface(Typeface.DEFAULT); + paint.setTextSize(dip2px(this.getContext(), 14f)); + Paint.FontMetrics fm = paint.getFontMetrics();// 得到系统默认字体属性 + textHeight = (int) (Math.ceil(fm.descent - fm.top) + 2);// 获得字体高度 + //字间距 + xPadding = dip2px(this.getContext(), 4f); + //行间距 + yPadding = dip2px(this.getContext(), 10f); + //比较小的字间距(字母和数字应紧凑) + xPaddingMin = dip2px(this.getContext(), 2f); + + } + + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (!TextUtils.isEmpty(content)) { + for (int i = 0; i < count; i++) { + canvas.drawText(String.valueOf(content.charAt(i)), position[i][0],position[i][1], paint); + } + } + } + + + public void getPositions(String content) { + this.content = content; + char ch; + //输入点的 x的坐标 + int x = 0; + //当前行数 + int lineNum = 1; + count = content.length(); + //初始化字体位置数组 + position=new int[count][2]; + for (int i = 0; i < count; i++) { + ch =content.charAt(i); + String str = String.valueOf(ch); + + //根据画笔获得每一个字符的显示的rect 就是包围框(获得字符宽度) + Rect rect = new Rect(); + paint.getTextBounds(str, 0, 1, rect); + int strwidth = rect.width(); + //对有些标点做些处理 + if (str.equals("《") || str.equals("(")) { + strwidth += xPaddingMin * 2; + } + //当前行的宽度 + float textWith = strwidth; + //没画字前预判看是否会出界 + x += textWith; + //出界就换行 + if (x > width) { + lineNum++;// 真实的行数加一 + x = 0; + } else { + //回到预判前的位置 + x -= textWith; + } + //记录每一个字的位置 + position[i][0]=x; + position[i][1]=textHeight * lineNum + yPadding * (lineNum - 1); + //判断是否是数字还是字母 (数字和字母应该紧凑点) + //每次输入完毕 进入下一个输入位置准备就绪 + if (isNumOrLetters(str)) { + x += textWith + xPaddingMin; + } else { + x += textWith + xPadding; + } + } + //根据所画的内容设置控件的高度 + this.setHeight((textHeight +yPadding) * lineNum); + } + + + + //工具类:判断是否是字母或者数字 + public boolean isNumOrLetters(String str) + { + String regEx="^[A-Za-z0-9_]+$"; + Pattern p= Pattern.compile(regEx); + Matcher m=p.matcher(str); + return m.matches(); + } + // 工具类:在代码中使用dp的方法(因为代码中直接用数字表示的是像素) + public static int dip2px(Context context, float dip) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dip * scale + 0.5f); + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/share_one_sreenshot.xml b/app/src/main/res/layout/share_one_sreenshot.xml new file mode 100644 index 0000000..e912a68 --- /dev/null +++ b/app/src/main/res/layout/share_one_sreenshot.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + +