RecyclerView实现图文混排

版权声明:个人原创,欢迎转载。 https://blog.csdn.net/chuyangchangxi/article/details/83960485

一、实现效果

RecyclerView实现图文混排

WhatsNote项目地址:https://github.com/jicanghai37927/WhatsAndroid

二、设计思路

  • 实现图片混排的几种方案
  1. TextView通过ImageSpan添加图片;
  2. WebView加载网页方式;
  3. ScrollViewRecyclerView等布局控件组合TextViewImageView

WhatsNote采用的RecyclerView组合TextViewImageView的方式,这种方式的限制是文字与图片只能按照固定的并排方式出现,无法实现图片环绕等效果。图片环绕需要通过TextViewSpan来实现。

  • 图文混排实现过程
  1. Intent.ACTION_PICK选择图片;
  2. Glide加载图片;
  3. 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实现,整个过程非常简单。withloadapplyinto4个方法完成加载过程。

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显示图片,TargetSizeImageViewImageView的子类,通过指定目标尺寸决定控件大小。

@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

宽度确定后,根据targetWidthtargetHeight的比例计算高度。

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将在后续过程中实现。

猜你喜欢

转载自blog.csdn.net/chuyangchangxi/article/details/83960485
今日推荐