* 显示富文本
|
|
|
22
|
*/
|
|
|
23
|
public class RichTextView extends ScrollView {
|
|
|
24
|
private static final String TAG = "RichTextView";
|
|
|
25
|
private static final int EDIT_PADDING = 3; // edittext常规padding是10dp
|
|
|
26
|
|
|
|
27
|
private int viewTagIndex = 1; // 新生的view都会打一个tag,对每个view来说,这个tag是唯一的。
|
|
|
28
|
private LinearLayout allLayout; // 这个是所有子view的容器,scrollView内部的唯一一个ViewGroup
|
|
|
29
|
private LayoutInflater inflater;
|
|
|
30
|
private int editNormalPadding = 0; //
|
|
|
31
|
|
|
|
32
|
public RichTextView(Context context) {
|
|
|
33
|
this(context, null);
|
|
|
34
|
}
|
|
|
35
|
|
|
|
36
|
public RichTextView(Context context, AttributeSet attrs) {
|
|
|
37
|
this(context, attrs, 0);
|
|
|
38
|
}
|
|
|
39
|
|
|
|
40
|
public RichTextView(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
|
41
|
super(context, attrs, defStyleAttr);
|
|
|
42
|
inflater = LayoutInflater.from(context);
|
|
|
43
|
|
|
|
44
|
// 1. 初始化allLayout
|
|
|
45
|
allLayout = new LinearLayout(context);
|
|
|
46
|
allLayout.setOrientation(LinearLayout.VERTICAL);
|
|
|
47
|
//allLayout.setBackgroundColor(Color.WHITE);//去掉背景
|
|
|
48
|
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
|
|
|
49
|
LayoutParams.WRAP_CONTENT);
|
|
|
50
|
allLayout.setPadding(50, 15, 50, 15);//设置间距,防止生成图片时文字太靠边
|
|
|
51
|
addView(allLayout, layoutParams);
|
|
|
52
|
|
|
|
53
|
LinearLayout.LayoutParams firstEditParam = new LinearLayout.LayoutParams(
|
|
|
54
|
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
|
|
55
|
//editNormalPadding = dip2px(EDIT_PADDING);
|
|
|
56
|
TextView firstText = createTextView("没有内容", dip2px(context, EDIT_PADDING));
|
|
|
57
|
allLayout.addView(firstText, firstEditParam);
|
|
|
58
|
}
|
|
|
59
|
|
|
|
60
|
public int dip2px(Context context, float dipValue) {
|
|
|
61
|
float m = context.getResources().getDisplayMetrics().density;
|
|
|
62
|
return (int) (dipValue * m + 0.5f);
|
|
|
63
|
}
|
|
|
64
|
|
|
|
65
|
/**
|
|
|
66
|
* 清除所有的view
|
|
|
67
|
*/
|
|
|
68
|
public void clearAllLayout() {
|
|
|
69
|
allLayout.removeAllViews();
|
|
|
70
|
}
|
|
|
71
|
|
|
|
72
|
/**
|
|
|
73
|
* 获得最后一个子view的位置
|
|
|
74
|
*
|
|
|
75
|
* @return
|
|
|
76
|
*/
|
|
|
77
|
public int getLastIndex() {
|
|
|
78
|
int lastEditIndex = allLayout.getChildCount();
|
|
|
79
|
return lastEditIndex;
|
|
|
80
|
}
|
|
|
81
|
|
|
|
82
|
/**
|
|
|
83
|
* 生成文本输入框
|
|
|
84
|
*/
|
|
|
85
|
public TextView createTextView(String hint, int paddingTop) {
|
|
|
86
|
TextView textView = (TextView) inflater.inflate(R.layout.rich_textview, null);
|
|
|
87
|
textView.setTag(viewTagIndex++);
|
|
|
88
|
textView.setPadding(editNormalPadding, paddingTop, editNormalPadding, paddingTop);
|
|
|
89
|
textView.setHint(hint);
|
|
|
90
|
return textView;
|
|
|
91
|
}
|
|
|
92
|
|
|
|
93
|
/**
|
|
|
94
|
* 生成图片View
|
|
|
95
|
*/
|
|
|
96
|
private RelativeLayout createImageLayout() {
|
|
|
97
|
RelativeLayout layout = (RelativeLayout) inflater.inflate(
|
|
|
98
|
R.layout.edit_imageview, null);
|
|
|
99
|
layout.setTag(viewTagIndex++);
|
|
|
100
|
View closeView = layout.findViewById(R.id.image_close);
|
|
|
101
|
closeView.setVisibility(GONE);
|
|
|
102
|
return layout;
|
|
|
103
|
}
|
|
|
104
|
|
|
|
105
|
/**
|
|
|
106
|
* 在特定位置插入EditText
|
|
|
107
|
*
|
|
|
108
|
* @param index 位置
|
|
|
109
|
* @param editStr EditText显示的文字
|
|
|
110
|
*/
|
|
|
111
|
public void addTextViewAtIndex(final int index, CharSequence editStr) {
|
|
|
112
|
TextView textView = createTextView("", EDIT_PADDING);
|
|
|
113
|
textView.setText(editStr);
|
|
|
114
|
|
|
|
115
|
allLayout.addView(textView, index);
|
|
|
116
|
}
|
|
|
117
|
|
|
|
118
|
/**
|
|
|
119
|
* 在特定位置添加ImageView
|
|
|
120
|
*/
|
|
|
121
|
public void addImageViewAtIndex(final int index, String imagePath) {
|
|
|
122
|
String width, height;
|
|
|
123
|
String[] strarray = imagePath.split("\\&");
|
|
|
124
|
final String path = strarray[0];
|
|
|
125
|
width = strarray[1];
|
|
|
126
|
if (width.contains(".")) {
|
|
|
127
|
width = width.substring(0, width.indexOf("."));
|
|
|
128
|
}
|
|
|
129
|
height = strarray[2];
|
|
|
130
|
if (height.contains(".")) {
|
|
|
131
|
height = height.substring(0, height.indexOf("."));
|
|
|
132
|
}
|
|
|
133
|
|
|
|
134
|
// Bitmap bmp = BitmapFactory.decodeFile(imagePath);
|
|
|
135
|
|
|
|
136
|
final RelativeLayout imageLayout = createImageLayout();
|
|
|
137
|
DataImageView imageView = (DataImageView) imageLayout.findViewById(R.id.edit_imageView);
|
|
|
138
|
RequestOptions options = new RequestOptions().centerCrop();
|
|
|
139
|
Glide.with(getContext()).load(imagePath).apply(options).into(imageView);
|
|
|
140
|
//imageView.setImageBitmap(bmp);//这里改用Glide加载图片
|
|
|
141
|
//imageView.setBitmap(bmp);//这句去掉,保留下面的图片地址即可,优化图片占用
|
|
|
142
|
// imageView.setAbsolutePath(imagePath);//保留这句,后面保存数据会用
|
|
|
143
|
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);//裁剪剧中
|
|
|
144
|
|
|
|
145
|
// 调整imageView的高度
|
|
|
146
|
int imageHeight = 500;
|
|
|
147
|
int img_width = Integer.parseInt(width);
|
|
|
148
|
int img_height = Integer.parseInt(height);
|
|
|
149
|
if (width != null) {
|
|
|
150
|
imageHeight = allLayout.getWidth() * img_height / img_width;
|
|
|
151
|
// 使用之后,还是回收掉吧
|
|
|
152
|
// bmp.recycle();
|
|
|
153
|
}
|
|
|
154
|
// Log.e(TAG, "addImageViewAtIndex_imageHeight: "+imageHeight );
|
|
|
155
|
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
|
|
|
156
|
LayoutParams.MATCH_PARENT, imageHeight);
|
|
|
157
|
lp.bottomMargin = 6;
|
|
|
158
|
imageView.setLayoutParams(lp);
|
|
|
159
|
|
|
|
160
|
allLayout.addView(imageLayout, index);
|
|
|
161
|
}
|
|
|
162
|
|
|
|
163
|
/**
|
|
|
164
|
* 根据view的宽度,动态缩放bitmap尺寸
|
|
|
165
|
*
|
|
|
166
|
* @param width view的宽度
|
|
|
167
|
*/
|
|
|
168
|
public Bitmap getScaledBitmap(String filePath, int width) {
|
|
|
169
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
|
|
170
|
options.inJustDecodeBounds = true;
|
|
|
171
|
BitmapFactory.decodeFile(filePath, options);
|
|
|
172
|
int sampleSize = options.outWidth > width ? options.outWidth / width
|
|
|
173
|
+ 1 : 1;
|
|
|
174
|
options.inJustDecodeBounds = false;
|
|
|
175
|
options.inSampleSize = sampleSize;
|
|
|
176
|
return BitmapFactory.decodeFile(filePath, options);
|
|
|
177
|
}
|
|
|
178
|
|
|
|
179
|
}
|
|
|
@ -0,0 +1,131 @@
|
|
|
1
|
package com.electric.chargingpile.view.xrichtext;
|
|
|
2
|
|
|
|
3
|
import android.content.ContentResolver;
|
|
|
4
|
import android.content.Context;
|
|
|
5
|
import android.database.Cursor;
|
|
|
6
|
import android.graphics.Bitmap;
|
|
|
7
|
import android.net.Uri;
|
|
|
8
|
import android.os.Environment;
|
|
|
9
|
import android.provider.MediaStore;
|
|
|
10
|
|
|
|
11
|
import java.io.File;
|
|
|
12
|
import java.io.FileNotFoundException;
|
|
|
13
|
import java.io.FileOutputStream;
|
|
|
14
|
import java.io.IOException;
|
|
|
15
|
|
|
|
16
|
public class SDCardUtil {
|
|
|
17
|
public static String SDCardRoot = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;
|
|
|
18
|
|
|
|
19
|
/**
|
|
|
20
|
* 检查是否存在SDCard
|
|
|
21
|
*
|
|
|
22
|
* @return
|
|
|
23
|
*/
|
|
|
24
|
public static boolean hasSdcard() {
|
|
|
25
|
String state = Environment.getExternalStorageState();
|
|
|
26
|
if (state.equals(Environment.MEDIA_MOUNTED)) {
|
|
|
27
|
return true;
|
|
|
28
|
} else {
|
|
|
29
|
return false;
|
|
|
30
|
}
|
|
|
31
|
}
|
|
|
32
|
|
|
|
33
|
/**
|
|
|
34
|
* 获得文章图片保存路径
|
|
|
35
|
*
|
|
|
36
|
* @return
|
|
|
37
|
*/
|
|
|
38
|
public static String getPictureDir() {
|
|
|
39
|
String imageCacheUrl = SDCardRoot + "XRichText" + File.separator;
|
|
|
40
|
File file = new File(imageCacheUrl);
|
|
|
41
|
if (!file.exists())
|
|
|
42
|
file.mkdir(); //如果不存在则创建
|
|
|
43
|
return imageCacheUrl;
|
|
|
44
|
}
|
|
|
45
|
|
|
|
46
|
/**
|
|
|
47
|
* 图片保存到SD卡
|
|
|
48
|
*
|
|
|
49
|
* @param bitmap
|
|
|
50
|
* @return
|
|
|
51
|
*/
|
|
|
52
|
public static String saveToSdCard(Bitmap bitmap) {
|
|
|
53
|
String imageUrl = getPictureDir() + System.currentTimeMillis() + "-.jpeg";
|
|
|
54
|
File file = new File(imageUrl);
|
|
|
55
|
try {
|
|
|
56
|
FileOutputStream out = new FileOutputStream(file);
|
|
|
57
|
if (bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)) {
|
|
|
58
|
out.flush();
|
|
|
59
|
out.close();
|
|
|
60
|
}
|
|
|
61
|
} catch (FileNotFoundException e) {
|
|
|
62
|
e.printStackTrace();
|
|
|
63
|
} catch (IOException e) {
|
|
|
64
|
e.printStackTrace();
|
|
|
65
|
}
|
|
|
66
|
return file.getAbsolutePath();
|
|
|
67
|
}
|
|
|
68
|
|
|
|
69
|
/**
|
|
|
70
|
* 保存到指定路径,笔记中插入图片
|
|
|
71
|
*
|
|
|
72
|
* @param bitmap
|
|
|
73
|
* @param path
|
|
|
74
|
* @return
|
|
|
75
|
*/
|
|
|
76
|
public static String saveToSdCard(Bitmap bitmap, String path) {
|
|
|
77
|
File file = new File(path);
|
|
|
78
|
try {
|
|
|
79
|
FileOutputStream out = new FileOutputStream(file);
|
|
|
80
|
if (bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)) {
|
|
|
81
|
out.flush();
|
|
|
82
|
out.close();
|
|
|
83
|
}
|
|
|
84
|
} catch (FileNotFoundException e) {
|
|
|
85
|
e.printStackTrace();
|
|
|
86
|
} catch (IOException e) {
|
|
|
87
|
e.printStackTrace();
|
|
|
88
|
}
|
|
|
89
|
//System.out.println("文件保存路径:"+ file.getAbsolutePath());
|
|
|
90
|
return file.getAbsolutePath();
|
|
|
91
|
}
|
|
|
92
|
|
|
|
93
|
/**
|
|
|
94
|
* 删除文件
|
|
|
95
|
**/
|
|
|
96
|
public static void deleteFile(String filePath) {
|
|
|
97
|
File file = new File(filePath);
|
|
|
98
|
if (file.isFile() && file.exists())
|
|
|
99
|
file.delete(); // 删除文件
|
|
|
100
|
}
|
|
|
101
|
|
|
|
102
|
/**
|
|
|
103
|
* 根据Uri获取图片文件的绝对路径
|
|
|
104
|
*/
|
|
|
105
|
public static String getFilePathByUri(Context context, final Uri uri) {
|
|
|
106
|
if (null == uri) {
|
|
|
107
|
return null;
|
|
|
108
|
}
|
|
|
109
|
final String scheme = uri.getScheme();
|
|
|
110
|
String data = null;
|
|
|
111
|
if (scheme == null) {
|
|
|
112
|
data = uri.getPath();
|
|
|
113
|
} else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
|
|
|
114
|
data = uri.getPath();
|
|
|
115
|
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
|
|
|
116
|
Cursor cursor = context.getContentResolver().query(uri,
|
|
|
117
|
new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
|
|
|
118
|
if (null != cursor) {
|
|
|
119
|
if (cursor.moveToFirst()) {
|
|
|
120
|
int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
|
|
|
121
|
if (index > -1) {
|
|
|
122
|
data = cursor.getString(index);
|
|
|
123
|
}
|
|
|
124
|
}
|
|
|
125
|
cursor.close();
|
|
|
126
|
}
|
|
|
127
|
}
|
|
|
128
|
return data;
|
|
|
129
|
}
|
|
|
130
|
|
|
|
131
|
}
|
|
|
@ -0,0 +1,24 @@
|
|
|
1
|
<?xml version="1.0" encoding="utf-8"?>
|
|
|
2
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
|
3
|
android:layout_width="match_parent"
|
|
|
4
|
android:layout_height="wrap_content">
|
|
|
5
|
|
|
|
6
|
<com.electric.chargingpile.view.xrichtext.DataImageView
|
|
|
7
|
android:id="@+id/edit_imageView"
|
|
|
8
|
android:layout_width="match_parent"
|
|
|
9
|
android:layout_height="wrap_content"
|
|
|
10
|
android:scaleType="fitXY" />
|
|
|
11
|
|
|
|
12
|
<ImageView
|
|
|
13
|
android:id="@+id/image_close"
|
|
|
14
|
android:layout_width="50dp"
|
|
|
15
|
android:layout_height="50dp"
|
|
|
16
|
android:layout_alignParentRight="true"
|
|
|
17
|
android:paddingLeft="20dp"
|
|
|
18
|
android:paddingTop="5dp"
|
|
|
19
|
android:paddingRight="5dp"
|
|
|
20
|
android:paddingBottom="20dp"
|
|
|
21
|
android:scaleType="fitXY"
|
|
|
22
|
android:src="@drawable/icon_close" />
|
|
|
23
|
|
|
|
24
|
</RelativeLayout>
|
|
|
@ -0,0 +1,9 @@
|
|
|
1
|
<?xml version="1.0" encoding="utf-8"?>
|
|
|
2
|
<com.electric.chargingpile.view.xrichtext.DeletableEditText xmlns:android="http://schemas.android.com/apk/res/android"
|
|
|
3
|
android:layout_width="match_parent"
|
|
|
4
|
android:layout_height="wrap_content"
|
|
|
5
|
android:background="@null"
|
|
|
6
|
android:cursorVisible="true"
|
|
|
7
|
android:lineSpacingExtra="8dp"
|
|
|
8
|
android:textColor="#616161"
|
|
|
9
|
android:textSize="16sp" />
|
|
|
@ -0,0 +1,10 @@
|
|
|
1
|
<?xml version="1.0" encoding="utf-8"?>
|
|
|
2
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
|
3
|
android:layout_width="match_parent"
|
|
|
4
|
android:layout_height="wrap_content"
|
|
|
5
|
android:background="@null"
|
|
|
6
|
android:cursorVisible="true"
|
|
|
7
|
android:lineSpacingExtra="8dp"
|
|
|
8
|
android:textIsSelectable="true"
|
|
|
9
|
android:textSize="16sp"
|
|
|
10
|
android:textColor="#616161" />
|