android 朋友圈9宫格实现

icon9宫格效果.png

项目优化

2019-10-10
1、有人提出经常new ImageView耗内存, 我现在直接new 9个ImageView,可重复使用这几个ImageView
2、修复图片数量为4/7个的时候,高度没计算正确问题

使用方式
 holder.pengYouQuanFlagLayout.setImgList(findBean);
        <!--朋友圈-->
        <com.tpshop.mall.widget.PengYouQuanFlagLayout
            android:id="@+id/find_fragment_pengyouquan"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/dp_9" />
注意

addView,removeView,都会重新调用onMeasure,onLayout

优化点

onMeasure地方只用来测量高度,onLayout地方只用来布局位置信息

      <!--朋友圈-->
    <declare-styleable name="PengYouQuanFlagView">
        <attr name="pengInterval" format="dimension" />
        <attr name="muiPengWidth" format="dimension" />
        <attr name="muiPengHeight" format="dimension" />
        <attr name="sinPengWidth" format="dimension" />
        <attr name="sinPengHeight" format="dimension" />
    </declare-styleable>
public abstract class PengYouQuanFlagView extends ViewGroup {
    protected abstract void displayImage(int position, ImageView imageView, String url);

    protected abstract void onClickImage(int position, String url, ImageView imageView, List<String> imgList);

    private int customInterval = 15;//默认的间距
    private int muiHeight, muiWidth = 0, sinHeight = 0, sinWidth = 0;//多图的时候高度,宽度,单图时候宽高
    private List<String> imgList = new ArrayList<>();//图片的集合
    private Context mContext = null;
    private List<ImageView> imageViewList;

    public PengYouQuanFlagView(Context context) {
        this(context, null);
    }

    public PengYouQuanFlagView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PengYouQuanFlagView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        //初始化自定义属性
        initAttrs(context, attrs);
    }

    private void initAttrs(Context context, AttributeSet attributeSet) {
        TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.PengYouQuanFlagView);
        customInterval = (int) typedArray.getDimension(R.styleable.PengYouQuanFlagView_pengInterval, getResources().getDimensionPixelSize(R.dimen.dp_7));//默认的边距
        muiHeight = (int) typedArray.getDimension(R.styleable.PengYouQuanFlagView_muiPengHeight, getResources().getDimensionPixelSize(R.dimen.dp_93));//多图的时候高度
        muiWidth = (int) typedArray.getDimension(R.styleable.PengYouQuanFlagView_muiPengWidth, getResources().getDimensionPixelSize(R.dimen.dp_93));//多图的时候高度
        sinWidth = (int) typedArray.getDimension(R.styleable.PengYouQuanFlagView_muiPengHeight, getResources().getDimensionPixelSize(R.dimen.dp_230));//单图的时候宽度
        sinHeight = (int) typedArray.getDimension(R.styleable.PengYouQuanFlagView_muiPengHeight, getResources().getDimensionPixelSize(R.dimen.dp_193));//单图的时候高度
        imageViewList = new ArrayList<>();

        for (int i = 0; i < 9; i++) {
            imageViewList.add(creatImageView(i));
        }

        typedArray.recycle();
    }

    /**
     * @date: 2019/5/21 0021
     * @author: gaoxiaoxiong
     * @description:设置图片地址链接
     **/
    public void setImgList(FindBean findBean) {
        imgList.clear();
        imgList.addAll(findBean.getImgs());
        resetLayout();
    }

    /**
     * @date: 2019/5/21 0021
     * @author: gaoxiaoxiong
     * @description: 重新添加布局
     **/
    protected void resetLayout() {
        removeAllViews();
        for (int i = 0; i < imgList.size(); i++) {
            ImageView imageView = imageViewList.get(i);
            addView(imageView);
            displayImage(i, imageView, imgList.get(i));
        }
    }

    /**
     * @date: 2019/5/21 0021
     * @author: gaoxiaoxiong
     * @description:创建图片
     **/
    public ImageView creatImageView(int position) {
        int childCount = imgList.size();
        ImageView imageView = new ImageView(mContext);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        if (childCount == 1) {
            params.width = sinWidth;
            params.height = sinHeight;
        } else {
            params.width = muiWidth;
            params.height = muiHeight;
        }
        imageView.setLayoutParams(params);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                onClickImage(position, imgList.get(position), (ImageView) view, imgList);
            }
        });
        return imageView;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int mParentMearWidht = MeasureSpec.getSize(widthMeasureSpec);
        int line = 1;
        int currentWidth = 0, childHeight = 0;//子view的宽度;,子view的高度
        int childCount = getChildCount();
        if (childCount<=0){
            return;
        }
        for (int i = 0; i < childCount; i++) {
            View imageView = getChildAt(i);
            measureChild(imageView, widthMeasureSpec, heightMeasureSpec);
            int imageWidth = 0;
            //中间的图片
            if (i == 1 || i == 4 || i == 7) {
                imageWidth = imageView.getMeasuredWidth() + customInterval * 2;
            } else {//不是中间的图片
                imageWidth = imageView.getMeasuredWidth();
            }
            childHeight = imageView.getMeasuredHeight() + customInterval * 2;
            if (mParentMearWidht - currentWidth >= imageWidth) {
                currentWidth = currentWidth + imageWidth;
            } else {//需要换行
                line = line + 1;
                currentWidth = 0;
            }
        }
        //再次校验高度是否正确
        View imageView = getChildAt(0);
        int liYingHeight = 0;
        if (childCount >= 0 && childCount <= 3) {
            liYingHeight = (imageView.getMeasuredHeight() + customInterval * 2) * 1;
        } else if (childCount >= 4 && childCount <= 6) {
            //理应高度
            liYingHeight = (imageView.getMeasuredHeight() + customInterval * 2) * 2;
        } else if (childCount >= 7) {
            //理应高度
            liYingHeight = (imageView.getMeasuredHeight() + customInterval * 2) * 3;
        }
        //代码计算高度
        int jisuanHeight = childHeight * line;
        if (liYingHeight != jisuanHeight) {
            if (childCount >= 0 && childCount <= 3) {
                line = 1;
            } else if (childCount >= 4 && childCount <= 6) {
                line = 2;
            } else if (childCount >= 7) {
                line = 3;
            }
        }

        setMeasuredDimension(mParentMearWidht, childHeight * line);
    }


    @Override
    protected void onLayout(boolean b, int i0, int i1, int i2, int i3) {
        int childCount = getChildCount();
        //整个View的宽度
        int mParentWidth = this.getMeasuredWidth();
        int left = 0, top = 0;
        for (int i = 0; i < childCount; i++) {
            View imageView = getChildAt(i);
            //获取子View的宽高,判断一行是否可以放的下,如果放不下,需要换行
            int childHeight = imageView.getMeasuredHeight();
            int childWidth = imageView.getMeasuredWidth();
            if (mParentWidth - left >= childWidth) {
                imageView.layout(left, top, left + childWidth, top + childHeight);
                left = left + childWidth + customInterval;
            } else {
                left = 0;
                top = top + childHeight + customInterval;
                imageView.layout(left, top, left + childWidth, top + childHeight);
                left = childWidth + customInterval;
            }
        }
    }
}

这里将显示图片的方式移到这里处理

public class PengYouQuanFlagLayout extends PengYouQuanFlagView{
    private String TAG = PengYouQuanFlagLayout.class.getSimpleName();
    private Context mContext;
    public PengYouQuanFlagLayout(Context context) {
        this(context,null);
    }

    public PengYouQuanFlagLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
    }

    @Override
    protected void displayImage(int position, ImageView imageView, String url) {
        if (mContext!=null){
            Glide.with(mContext).load(url).into(imageView);
        }
    }

    @Override
    protected void onClickImage(int position, String url, ImageView imageView, List<String> imgList) {
        //处理图片地方
    }
}
感悟

1、需要先addView,增加childCount个数,addView完后,不需要requestLayout(),因为addView已经帮你操作了
2、为啥每次addView都要重新onMeasure,onLayout,只测量一次不好么?
因为每次新增一个图片进来后,我们布局的位置和宽度都会发生变化,所以每次addView一次进来,都需要重新测量。
3、假如我将ImageView动态设置的宽高是198px,当我在onLayout布局的时候,即调用imageView.layout(left, top,right, bottom);方法,如果我right - left < 198 或 bottom - top < 198 都会导致界面显示不完全。我们可以想象一下,我们的画的imageView是在一个盒子里面,如果盒子太小了,就会导致界面变小。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容