参考的博客地址
RecyclerView瀑布流的那些坑
Recyclerview之瀑布流分割线左右间距均等问题
自定义ImageView,实现圆角矩形、原型、固定宽高比样式
Android内存分析工具:Memory Profiler
2019-07-14 本编文章修改
今天我对这边博客进行了修改,因为我发现在使用CornerTransform圆角工具的时候会出现几个问题,
1、当你不设置imageView的android:scaleType为fitXY,图片会出现上边空白,或者是左右空白的情况,无法填充父容器
2、设置了imageView的android:scaleType为fitXY,第一次加载数据图片处于正常的状态,第二次下拉刷新会导致图片放大拉伸(个别图片)
以上问题都是adapter缓存影响,它并没有去执行CornerTransform的代码,此次修改我会保留部分之前写的,然后文章末尾部分,贴出自己搞的demo。公司的代码跟我自己写的代码是有很多出入的,所以有些问题并没有在我这个demo里面出现
问题点
bug.png
解决办法
1、自定义ImageView,对图片进行一个缩放,每次加载图片的时候获取图片的宽高,与我们要向用户展示的宽高做一个缩放比,缩放比我们需要取最大的值
学习到的知识点
1、BitmapShader是着色器,当我们创建出一个bitmap的时候,需要使用它为其上色
2、Matrix缩放图片,有点类似拉着图片的右下角来进行扩大缩小
3、我们缩放的图片是原图片的bitmap,要先将Drawable转为bitmap,bitmap的宽高都要采用Drawable的,当然了我们最后向用户展示的宽高会和我们原图的宽高不同,所以我们需要对原图的进行缩放
自定义Imageview代码展示
public class MyImageView2 extends android.support.v7.widget.AppCompatImageView {
//最后确认的宽高
private RectF drawRectF;
private Paint mPaint;
private Matrix matrix;
private BitmapShader bitmapShader;
private boolean topLeftRightCorner,bottomLeftRightCorner;//定义上面与下面的是否为圆角
private int radius = 5;
public MyImageView2(Context context) {
this(context,null);
}
public MyImageView2(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MyImageView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
private void init(Context context, AttributeSet attrs){
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.MyImageView2);
topLeftRightCorner = typedArray.getBoolean(R.styleable.MyImageView2_topLeftRightCorner,false);
bottomLeftRightCorner = typedArray.getBoolean(R.styleable.MyImageView2_bottomLeftRightCorner,false);
radius = typedArray.getInt(R.styleable.MyImageView2_radius,5);
typedArray.recycle();
mPaint = new Paint();
mPaint.setAntiAlias(true);
matrix = new Matrix();
radius = dip2px(radius);
}
public int getRadius() {
return radius;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
drawRectF = new RectF(0,0,w,h);
}
@Override
protected void onDraw(Canvas canvas) {
Drawable sourCeDrawable = getDrawable();
if (sourCeDrawable==null){
return;
}
Bitmap sourceBitMap = drawable2Bitmap(sourCeDrawable);
//BitmapShader 为着色器
bitmapShader = new BitmapShader(sourceBitMap,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
// float scaleMax = 1.0f,scaleX=1.0f,scaleY=1.0f;
float scaleMax = 1.0f;
// 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的图片的宽高,一定要大于我们view的宽高;所以我们这里取大值;
if (getWidth() != sourceBitMap.getWidth() || getHeight() !=sourceBitMap.getHeight()){
/* scaleX = (float) getWidth() / (float)sourceBitMap.getWidth();
scaleY = (float)getHeight() / (float)sourceBitMap.getHeight();*/
scaleMax = Math.max((float) getWidth() / (float)sourceBitMap.getWidth(),(float)getHeight() / (float)sourceBitMap.getHeight());
}
//对我们创建出来的bitmap进行缩放
matrix.setScale(scaleMax,scaleMax);
bitmapShader.setLocalMatrix(matrix);
mPaint.setShader(bitmapShader);
//纠正圆角
// int radius = (int) (getRadius() * scaleMax);
//画出我们需要的直角图形
canvas.drawRoundRect(drawRectF,radius,radius,mPaint);
if (topLeftRightCorner){
//左边底部
canvas.drawRect(0,canvas.getHeight() - radius ,radius,canvas.getHeight(),mPaint);
//右边底部
canvas.drawRect(canvas.getWidth() - radius, canvas.getHeight() - radius,canvas.getWidth(),canvas.getHeight(),mPaint);
}
if (bottomLeftRightCorner){
//左边顶部
canvas.drawRect(0,0,radius,radius,mPaint);
//右边顶部
canvas.drawRect(canvas.getWidth() - radius,0,canvas.getWidth(),radius,mPaint);
}
}
public int dip2px(float dipValue){
final float scale = Resources.getSystem().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
//Drawable 转bitmap
private Bitmap drawable2Bitmap(Drawable drawable){
//获取 Drawable 的内部宽高,包含 padding
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
//创建一个w,h的bitmap
Bitmap bitmap = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
//设置绘画区域
drawable.setBounds(0,0,width,height);
drawable.draw(canvas);
return bitmap;
}
}
topLeftRightCorner,bottomLeftRightCorner表示上部份和下部分是否为圆角,radius是圆角的半径
attrs.xml
xml
gitHub:https://github.com/caocao123/loadMoae
以下部分是之前的代码和描述
需求
公司最近说要做瀑布流的效果,要求显示的图片顶部才有圆角,底部是没有圆角的,如下效果图
学习到的知识点
1、view.getLayoutParams().getSpanIndex()是获取某一个View左右空白的下标
2、解决上拉,下拉闪烁问题
int start = findsModeList.size();//findsModeList表示是全局的list
findsModeList.addAll(list);//这里的list表示是从服务器返回的10条item数据集合
if (p!=1){//加载更多
adapter.notifyItemInserted(start);
}else {//下拉刷新
adapter.notifyDataSetChanged();
}
3、解决从底部滑动到顶部,导致的换位问题
refreshRecyclerView.getRecyclerView().addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
int[] first = new int[2];
staggeredGridLayoutManager.findFirstCompletelyVisibleItemPositions(first);
if (newState == RecyclerView.SCROLL_STATE_IDLE && (first[0] == 1 || first[1] == 1)) {
staggeredGridLayoutManager.invalidateSpanAssignments();//刷新间隔
}
}
});
实现思路与部分代码
1、在item.xml里面,父容器与ImageView的layout_width都要为match_parent
.....其它控件
2、为了防止会出现错位的问题,我们需要后台提供每张图片的高度,宽度,然后动态的设置ImageView的LayoutParams.height
3、在拿到后台给我们的数据的时候,我们需要对数据进行处理,因为有可能后台给的高度是1080px、或者是1920px等,我们在展示ImageView的时候,是不会展示这么高的图片出来
//图片最大的高度,图片最小的高度
private int IMAGE_MAXH = 0;
private int IMAGE_MINH = 0;
private int IMAGEDEFAULT = 0;//每个Item的宽度
IMAGE_MAXH = this.getResources().getDimensionPixelOffset(R.dimen.dp_215);
IMAGE_MINH = this.getResources().getDimensionPixelOffset(R.dimen.dp_172);
//设置decoration
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
StaggeredGridLayoutSpaceItemDecoration dividler = new StaggeredGridLayoutSpaceItemDecoration(getResources().getDimensionPixelOffset(R.dimen.dp_10), 2);
int phoneWidth = ScreentUtil.getInstance().getScreenWidth(mContext);//获取手机的横项PX
//一般来说,我们现实瀑布流,每个Item之间都会有间隔,所以我这里dp_10,表示的是Item之间的间隔
IMAGEDEFAULT = (phoneWidth - getResources().getDimensionPixelOffset(R.dimen.dp_10) * 3) / 2;//得到每个Item的宽度
我们需要给图片设置一个最大的高度,与最小的高度,现在我们有1点可以确认的就是每个item的宽度是多少了,float 缩放比 = 每个Item宽度/服务器给的宽度,然后我们就可以算出我们需要展示的高度了
if (list.size() > 0) {
for (FindsMode findsMode : list) {
findsMode.setBanner(SPUtils.returnHaveHttpoHttps(findsMode.getBanner()));
findsMode.setHead_pic(SPUtils.returnHaveHttpoHttps(findsMode.getHead_pic()));
float scale = (float) IMAGEDEFAULT / (float) findsMode.getBanner_w();
int showHeight = (int) (findsMode.getBanner_h() * scale);
if (showHeight >= IMAGE_MAXH) {
showHeight = IMAGE_MAXH;
} else if (showHeight <= IMAGE_MINH) {
showHeight = IMAGE_MINH;
}else {
showHeight = IMAGE_MAXH;
}
findsMode.setShowBannerH(showHeight);
}
}
CornerTransform transformation = new CornerTransform(SPMobileApplication.getInstance(),findFragment.getActivity().getResources().getDimensionPixelSize(R.dimen.dp_5));
//只是绘制左上角和右上角圆角
transformation.setExceptCorner(false, false, true, true);
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
FindsMode findsMode = list.get(position);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) holder.imageView.getLayoutParams();
layoutParams.width = LinearLayout.LayoutParams.MATCH_PARENT;
layoutParams.height = findsMode.getShowBannerH();//设置算出的高度
holder.imageView.setLayoutParams(layoutParams);
//设置圆角
Glide.with(SPMobileApplication.getInstance()).
load(findsMode.getBanner()).
asBitmap().
diskCacheStrategy(DiskCacheStrategy.SOURCE).
transform(transformation).
into(holder.imageView);
期间遇到的问题
1、列表中图片没有显示出来,需要重新adapter一下才会出现
//最开始我想的是图片是需要一个固定的宽高,否则会导致界面错乱
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) holder.imageView.getLayoutParams();
layoutParams.height = findsMode.getShowBannerH();
layoutParams.width = holder.itemView.getWidth();//问题在这里,这里获取的宽度是0
holder.imageView.setLayoutParams(layoutParams);
2、顶部圆角只有1边显示出来了
圆角工具
工具博客地址:https://blog.csdn.net/mchenys/article/details/80284132
public class CornerTransform implements Transformation {
private BitmapPool mBitmapPool;
private float radius;
private boolean exceptLeftTop, exceptRightTop, exceptLeftBottom, exceptRightBotoom;
/**
* 除了那几个角不需要圆角的
*
* @param leftTop
* @param rightTop
* @param leftBottom
* @param rightBottom
*/
public void setExceptCorner(boolean leftTop, boolean rightTop, boolean leftBottom, boolean rightBottom) {
this.exceptLeftTop = leftTop;
this.exceptRightTop = rightTop;
this.exceptLeftBottom = leftBottom;
this.exceptRightBotoom = rightBottom;
}
public CornerTransform(Context context, float radius) {
this.mBitmapPool = Glide.get(context).getBitmapPool();
this.radius = radius;
}
public float getRadius() {
return radius;
}
@Override
public Resource transform(Resource resource, int outWidth, int outHeight) {
//最好是以resource的宽/高作为最后的宽/高。这样显示出来的结果不会变形
Bitmap source = resource.get();
int finalWidth, finalHeight;
float ratio; //输出目标的宽高或高宽比例
if (outWidth > outHeight) { //输出宽度>输出高度,求高宽比
ratio = (float) outHeight / (float) outWidth;
finalWidth = source.getWidth();
finalHeight = (int) ((float) source.getWidth() * ratio); //固定原图宽度,求最终高度
if (finalHeight > source.getHeight()) { //求出的最终高度>原图高度,求宽高比
ratio = (float) outWidth / (float) outHeight;
finalHeight = source.getHeight();
finalWidth = (int) ((float) source.getHeight() * ratio);//固定原图高度,求最终宽度
}
} else if (outWidth < outHeight) { //输出宽度 < 输出高度,求宽高比
ratio = (float) outWidth / (float) outHeight;
finalHeight = source.getHeight();
finalWidth = (int) ((float) source.getHeight() * ratio);//固定原图高度,求最终宽度
if (finalWidth > source.getWidth()) { //求出的最终宽度 > 原图宽度,求高宽比
ratio = (float) outHeight / (float) outWidth;
finalWidth = source.getWidth();
finalHeight = (int) ((float) source.getWidth() * ratio);
}
} else { //输出宽度=输出高度
finalHeight = source.getHeight();
finalWidth = finalHeight;
}
float radiusC = getRadius() * ((float) finalHeight / (float) outHeight);
Bitmap outBitmap = this.mBitmapPool.get(finalWidth, finalHeight, Bitmap.Config.ARGB_8888);
if (outBitmap == null) {
outBitmap = Bitmap.createBitmap(finalWidth, finalHeight, Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(outBitmap);
Paint paint = new Paint();
//关联画笔绘制的原图bitmap
BitmapShader shader = new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//计算中心位置,进行偏移
int width = (source.getWidth() - finalWidth) / 2;
int height = (source.getHeight() - finalHeight) / 2;
//将大图进行平移的操作
if (width != 0 || height != 0) {
Matrix matrix = new Matrix();
matrix.setTranslate((float) (-width), (float) (-height));
shader.setLocalMatrix(matrix);
}
paint.setShader(shader);
paint.setAntiAlias(true);
RectF rectF = new RectF(0.0F, 0.0F, (float) canvas.getWidth(), (float) canvas.getHeight());
canvas.drawRoundRect(rectF, radiusC, radiusC, paint); //先绘制圆角矩形
if (exceptLeftTop) { //左上角不为圆角
canvas.drawRect(0, 0, radiusC, radiusC, paint);
}
if (exceptRightTop) {//右上角不为圆角
canvas.drawRect(canvas.getWidth() - radiusC, 0, canvas.getWidth(), radiusC, paint);
}
if (exceptLeftBottom) {//左下角不为圆角
canvas.drawRect(0, canvas.getHeight() - radiusC, radiusC, canvas.getHeight(), paint);
}
if (exceptRightBotoom) {//右下角不为圆角
canvas.drawRect(canvas.getWidth() - radiusC, canvas.getHeight() - radiusC, canvas.getWidth(), canvas.getHeight(), paint);
}
return BitmapResource.obtain(outBitmap, this.mBitmapPool);
}
@Override
public String getId() {
return this.getClass().getName();
}
}