Android 自定义 说说的图片 组件

问题来源:我们知道,说说的图片显示方式,是会跟图片的数量来决定布局方式,我们没办法写死一个界面,我们必须要根据图片的多少来决定布局方式,所以我们可以继承 viewgroup, 来根据传入的图片多少 来进行动态的布局

需求:
1.最大为9张图片,当为1-3, 5-9张图片时,以 3列的表格布局
2.当为4张图片时,以 2x2 的表格布局

实现思路: 首先,viewgroup 中有 一个 addView() 方法,向布局中添加view,我们可以通过给 ImageView.layout(left, top, right, bottom) 来决定 imageview 在父元素的布局

一.图片排列算法:

1.实现 一个 int[] findPosition(int childNum) childNUm从0开始 根据传来的第childNUm 张图片,返回一个 矩阵的坐标值

在这里插入图片描述
当 childNum == i*column + j 时 (i,j) 就是我们要找的下标

for (int i = 0; i < mRows; i++) {
    for (int j = 0; j < mColumns; j++) {
        if ((i * mColumns + j) == childNum) {
            position[0] = i;//行
            position[1] = j;//列
            break;
        }
    }
}

2.rows,columns 需要根据 图片数量来决定, 当为4的时候, columns=2 ,其他情况columns=3, 代码中通过方法 generateRowAndColumn实现

二.代码总体思路:

在 onLayout(boolean changed, int left, int top, int right, int bottom) 方法中 计算单个图片的宽度为 总宽度减去2个间隔宽度 /3

OnLayout 方法可能会调用很多次,所以加一个 flag 只当第一次调用时,才请求布局。

主要的布局逻辑代码 在私有的 refresh 方法中, 开头第一行要清除所有view, 当 传过来的urls 为null或size为0,将此viewgroup 隐藏,不然 显示,根据图片多少生成行数跟列数, 通过行数列数,用 代码中的 layoutParam()方法去生成viewgroup 的长度和宽度, 最后吧一个个 imagevie 添加进去就ok

三.完整代码

为抽象类
需要用户自定义的接口
displayImage // 显示图片
onClickImage // 单击图片的监听

public abstract class NineGridLayout extends ViewGroup {

    private static final float DEFUALT_SPACING = 15f;// 图片之间的间隔
    private static final int MAX_COUNT = 9;// 最大图片大小

    protected Context mContext;
    private float mSpacing = DEFUALT_SPACING;
    private int mColumns;
    private int mRows;
    private int mTotalWidth;
    private int mSingleWidth;

    private boolean mIsShowAll = false;
    private boolean mIsFirst = true;
    private List<String> mUrlList = new ArrayList<>();

    public NineGridLayout(Context context) {
        super(context);
        init(context);
    }

    public NineGridLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NineGridLayout);

        mSpacing = typedArray.getDimension(R.styleable.NineGridLayout_sapcing, DEFUALT_SPACING);
        typedArray.recycle();
        init(context);
    }

    private void init(Context context) {
        mContext = context;
        if (getListSize(mUrlList) == 0) {
            setVisibility(GONE);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        float width=MeasureSpec.getSize(widthMeasureSpec);
//        widthMeasureSpec=MeasureSpec.makeMeasureSpec((int)width-10,MeasureSpec.EXACTLY);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

        mTotalWidth = right - left;
        mSingleWidth = (int) ((mTotalWidth - mSpacing * 2) / 3);
        Log.e("aaa","width:"+mSingleWidth);
        if (mIsFirst) {
            notifyDataSetChanged();
            mIsFirst = false;
        } else {
            Log.e("this", "Nine 不是第一次调用");
        }

    }

    /**
     * 设置间隔
     *
     * @param spacing
     */
    public void setSpacing(float spacing) {
        mSpacing = spacing;
    }

    /**
     *
     * @param urlList
     */
    public void setUrlList(List<String> urlList) {
        if (getListSize(urlList) == 0) {
            setVisibility(GONE);
            return;
        }
        setVisibility(VISIBLE);

        mUrlList.clear();
        mUrlList.addAll(urlList);

        if (!mIsFirst) {
            notifyDataSetChanged();
        }
    }

    /**
     * 更新界面
     */
    public void notifyDataSetChanged() {
        post(new TimerTask() {
            @Override
            public void run() {
                refresh();
            }
        });
    }

    private void refresh() {
        removeAllViews();
        int size = getListSize(mUrlList);
        if (size > 0) {
            setVisibility(VISIBLE);
        } else {
            setVisibility(GONE);
        }

        generateRowAndColumn(size);
        layoutParams();

        if (size == 1) {
            String url = mUrlList.get(0);
            ImageView imageView = createImageView(0, url);
            layoutImageView(imageView, 0, url);
            return;
        }


        for (int i = 0; i < size; i++) {
            String url = mUrlList.get(i);
            ImageView imageView;
            imageView = createImageView(i, url);
            layoutImageView(imageView, i, url);
        }
    }

    /**
     * 根据行数列数生成viewgroup大小
     */
    private void layoutParams() {
        int singleHeight = mSingleWidth;

        // 根据子view数量确定高度
        LayoutParams params = getLayoutParams();
        params.height = (int) (singleHeight * mRows + mSpacing * (mRows - 1));
        setLayoutParams(params);
    }

    /**
     * 创建 imagview 并设置监听
     * @param i
     * @param url
     * @return
     */
    private ImageView createImageView(final int i, final String url) {
        ImageView imageView = new ImageView(mContext);
        imageView.setScaleType(ImageView.ScaleType.CENTER);
        imageView.setBackgroundColor(Color.GRAY);
        imageView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                onClickImage(i, url, mUrlList);
            }
        });
        return imageView;
    }

    /* 布局子view的位置
     * @param imageView
     * @param url
     */
    private void layoutImageView(ImageView imageView, int i, String url) {
        final int singleWidth = (int) ((mTotalWidth - mSpacing * (3 - 1)) / 3);
        int singleHeight = singleWidth;

        int[] position = findPosition(i);   //postion[0]代表行 1代表列
        int left = (int) ((singleWidth + mSpacing) * position[1]);
        int top = (int) ((singleHeight + mSpacing) * position[0]);
        int right = left + singleWidth;
        int bottom = top + singleHeight;

        imageView.layout(left, top, right, bottom);

        addView(imageView);

        displayImage(imageView, url);
    }

    /**
     *  返回 传来的照片下标的坐标值
     * @param childNum
     * @return
     */
    private int[] findPosition(int childNum) {
        int[] position = new int[2];
        for (int i = 0; i < mRows; i++) {
            for (int j = 0; j < mColumns; j++) {
                if ((i * mColumns + j) == childNum) {
                    position[0] = i;//行
                    position[1] = j;//列
                    break;
                }
            }
        }
        return position;
    }

    /**
     * 根据图片个数确定行列数量
     * @param length
     */
    private void generateRowAndColumn(int length) {
        if (length == 4) {
            mColumns = 2;
        } else {
            mColumns =3;
        }

        if (length <= 3) {
            mRows = 1;
        } else if (length <= 6) {
            mRows = 2;
        } else {
            mRows = 3;
        }

    }

    /**
     *
     * @param list
     * @return
     */
    private int getListSize(List<String> list) {
        if (list == null || list.size() == 0) {
            return 0;
        }
        return list.size();
    }


    protected abstract void displayImage(ImageView imageView, String url);

    protected abstract void onClickImage(int position, String url, List<String> urlList);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值