RecyclerView實現圖文混排
阿新 • • 發佈:2018-11-13
RecyclerView實現圖文混排
一、實現效果
WhatsNote專案地址:https://github.com/jicanghai37927/WhatsAndroid
二、設計思路
- 實現圖片混排的幾種方案
TextView
通過ImageSpan
新增圖片;WebView
載入網頁方式;ScrollView
RecyclerView
等佈局控制元件組合TextView
、ImageView
;
WhatsNote採用的RecyclerView
組合TextView
、ImageView
的方式,這種方式的限制是文字與圖片只能按照固定的並排方式出現,無法實現圖片環繞等效果。圖片環繞需要通過TextView
的Span
來實現。
- 圖文混排實現過程
Intent.ACTION_PICK
選擇圖片;Glide
載入圖片;ImageView
顯示圖片;
三個過程完成新增圖片功能。
三、實現過程
1. 選擇圖片
圖片選擇採用Intent呼叫第三方Activity的方式實現,並且允許選擇多張圖片。
boolean requestPhoto() {
SoftInputUtils.hide(getActivity());
Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
"image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
try {
this .startActivityForResult(intent, REQUEST_PHOTO);
return true;
} catch (Exception e) {
}
return false;
}
在onActivityResult
中處理返回結果。
if ((resultCode == RESULT_OK) && (data != null)) {
ArrayList<Uri> list = new ArrayList<>();
{
ClipData clipData = data.getClipData();
if (clipData != null) {
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
Uri uri = item.getUri();
list.add(uri);
}
}
if (list.isEmpty()) {
Uri uri = data.getData();
if (uri != null) {
list.add(uri);
}
}
}
this.insertPhotos(list);
}
2. 載入圖片
圖片載入使用Glide
實現,整個過程非常簡單。with
,load
,apply
,into
4個方法完成載入過程。
RequestOptions options = createRequestOptions(item);
Glide.with(parent)
.load(item.getUri())
.apply(options)
.into(pictureView);
RequestOptions createRequestOptions(PictureEntity entity) {
RequestOptions options = new RequestOptions();
int maxWidth = this.getMaxWidth();
int maxHeight = 3 * this.getMaxHeight();
int width = maxWidth;
int height = width * entity.getHeight() / entity.getWidth();
if (height > maxHeight) {
height = maxHeight;
width = height * entity.getWidth() / entity.getHeight();
width = (width > maxWidth)? maxWidth: width;
}
options.override(width, height);
options.downsample(DownsampleStrategy.FIT_CENTER);
options.signature(new ObjectKey(entity.getSignature()));
return options;
}
重要的apply
方法,指定了三個引數。
- override圖片大小(寬度不大於螢幕寬度,高度不大於3倍螢幕高度,降低OutOfMemory出現概率)
- downsample取樣模式(採用FIT_CENTER方式,居中縮放)
- signature簽名
3. 顯示圖片
使用TargetSizeImageView
顯示圖片,TargetSizeImageView
是ImageView
的子類,通過指定目標尺寸決定控制元件大小。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (targetWidth <= 0 || targetHeight <= 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
if (measureWidth <= 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
Log.v(TAG, "onMeasure width = " + measureWidth + ", height = " + measureHeight);
int minWidth = this.getSuggestedMinimumWidth();
int minHeight = this.getSuggestedMinimumHeight();
int width = targetWidth;
width = (width > measureWidth)? measureWidth : width; // width must not large then measureWidth
width = (width < minWidth)? minWidth: width; // and not smaller then minWidth
int height = width * targetHeight / targetWidth; // calculate height from width
if (height < minHeight) { // recalculate width
height = minHeight;
width = height * targetWidth / targetHeight;
width = (width > targetWidth)? targetWidth: width;
width = (width > measureWidth)? measureWidth : width; // width must not large then measureWidth
width = (width < minWidth)? minWidth: width; // and not smaller then minWidth
}
Log.v(TAG, "width = " + width + ", height = " + height);
this.setMeasuredDimension(width, height);
}
TargetSizeImageView
控制元件大小計算過程
- targetWidth(指定的目標寬度)
- measureWidth(傳入的測量寬度)
- minWidth(最小寬度)保證小圖的顯示尺寸
int width = targetWidth; // 等於targetWidth
width = (width > measureWidth)? measureWidth : width; // 但不能大於measureWidth
width = (width < minWidth)? minWidth: width; // 並且不能小於minWidth
寬度確定後,根據targetWidth
和targetHeight
的比例計算高度。
int height = width * targetHeight / targetWidth; // 按比例計算高度
同時保證高度不小於最小高度。
if (height < minHeight) { // recalculate width
height = minHeight;
width = height * targetWidth / targetHeight;
width = (width > targetWidth)? targetWidth: width;
width = (width > measureWidth)? measureWidth : width;
width = (width < minWidth)? minWidth: width;
}
四、最後
到這裡,我們實現了CRUD的Create和Read兩個環節。
Update和Delete將在後續過程中實現。