Android仿朋友圈的九宫格

136 阅读2分钟
Android仿朋友圈的九宫格

仿朋友圈的九宫格功能,很常见,几乎每个app都有这个功能。

一、思路:

自定义控件NineGridLayout

二、效果图:

在这里插入图片描述

三、关键代码:
/**
 * 九宫格布局显示图片
 * 1    显示1张图片的时候可以按照自适应或者长宽比
 * 2    显示2张及2张以上都是正方形
 * 3    4张图片显示排列方式是 2*2
 */
public abstract class NineGridLayout extends ViewGroup {
    private static final float DEFUALT_SPACING = 3f;
    private float image_ratio = 1.7f;//默认图片长宽比例
    private int oneImageWidth;//一张图的宽度
    private int oneImageHeight;//一张图的高度
    protected Context mContext;
    private float mSpacing = DEFUALT_SPACING;
    private int mColumns;
    private int mRows;
    private int mTotalWidth;
    private int mSingleWidth;
    private boolean isNeedClick = true ; // 是否需要item的点击处理

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


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

    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);
        oneImageWidth = (int) typedArray.getDimension(R.styleable.NineGridLayout_oneImageWidth, 0);
        oneImageHeight = (int) typedArray.getDimension(R.styleable.NineGridLayout_oneImageHeight, 0);
        image_ratio =   typedArray.getFloat(R.styleable.NineGridLayout_image_ratio, image_ratio);
        typedArray.recycle();
        init(context);
    }

    public void setItemIsNeedClick(boolean isNeedClick){
        this.isNeedClick = isNeedClick;
    }

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



    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        mTotalWidth = right - left;
        mSingleWidth = (int) ((mTotalWidth - mSpacing * (3 - 1)) / 3);
        if (mIsFirst) {//只绘制一次
            notifyDataSetChanged();
            mIsFirst = false;
        }
    }

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

    /**
     * 设置是否显示所有图片(超过最大数时)
     *
     * @param isShowAll
     */
    public void setIsShowAll(boolean isShowAll) {
        mIsShowAll = isShowAll;
    }

    public void setUrlList(List<PhotoInfo> urlList) {
        if (getListSize(urlList) == 0) {
            setVisibility(GONE);
            return;
        }
        setVisibility(VISIBLE);

        mUrlList.clear();
        mUrlList.addAll(urlList);
        if (!mIsFirst) {//由于使用在RecyclerView中牵扯到复用布局,所以需要判断当前布局是不是第一次使用,是的话就直接绘制,不是的话就移除掉恰他的布局再绘制
            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);
            return;
        }

        if (size == 1) {
            PhotoInfo photoInfo = mUrlList.get(0);

            RatioImageView imageView = createImageView(0, photoInfo.getImg());

            getRealOneImageSize();
            imageView.layout(0, 0, oneImageWidth, oneImageHeight);
            LayoutParams params = getLayoutParams();
            params.height = oneImageHeight;
            setLayoutParams(params);
            addView(imageView);
            displayImage(0,imageView, photoInfo.getImg());
            return;
        }

        generateChildrenLayout(size);
        layoutParams();

//        for (int i = 0; i < size; i++) {
//            PhotoInfo photoInfo = mUrlList.get(i);
//            RatioImageView imageView = createImageView(i, photoInfo.getSmallImg());
//            layoutImageView(imageView, i, photoInfo.getSmallImg());
//        }
        //demo简单起见,只用img。实际项目可以设多一个SmallImg
        for (int i = 0; i < size; i++) {
            PhotoInfo photoInfo = mUrlList.get(i);
            RatioImageView imageView = createImageView(i, photoInfo.getImg());
            layoutImageView(imageView, i, photoInfo.getImg());
        }
    }

    private void getRealOneImageSize() {
        if(oneImageWidth==0){
            oneImageWidth = mSingleWidth;
        }

        if(oneImageHeight==0){
            oneImageHeight = (int) (oneImageWidth * image_ratio);
        }
    }

    private void layoutParams() {
        int singleHeight = mSingleWidth;

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

    private RatioImageView createImageView(final int i, final String url) {
        final RatioImageView imageView = new RatioImageView(mContext);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        if(isNeedClick){
            imageView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    onClickImage(i, url, mUrlList,imageView);
                }
            });
        }
        return imageView;
    }

    /**
     * @param imageView
     * @param url
     */
    private void layoutImageView(RatioImageView imageView, int i, String url) {
        final int singleWidth = (int) ((mTotalWidth - mSpacing * (3 - 1)) / 3);
        int singleHeight = singleWidth;

        int[] position = findPosition(i);
        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(i,imageView, url);
    }

    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;
    }
四、项目demo源码结构图:

在这里插入图片描述

有问题或者需要完整源码demo的可以看简介联系我,也可以私信我,我每天都看私信的