Android图片九宫格控件,微信朋友圈;

注:本文是根据https://github.com/jeasonlzy/NineGridView进行扩展;

类似QQ空间,微信朋友圈,微博主页等,展示图片的九宫格控件;

原作者只有仿朋友圈样式和QQ空间样式,新增平铺样式

源码在CcMall项目中:https://github.com/CuiChenbo/CcMall/tree/master/ninegridview

什么是平铺样式、效果图如下:

一张图、2或4张图 和多张图;

一张图:两张图:

四张图:  多张图:

效果就是一张图、2或4张图时也铺满屏幕;于是就对该开源框架进行了一下扩展,下面上代码;

一、新增平铺模式;

设置平铺模式的最大高度(也就是一张图时的高度);

    public static final int MODE_TILE = 2;          //平铺网格模式

    private int tileMaxHeight = 200;                 // 平铺模式最大高度
<declare-styleable name="NineGridView">
        <attr name="ngv_singleImageSize" format="dimension"/>
        <attr name="ngv_singleImageRatio" format="float"/>
        <attr name="ngv_gridSpacing" format="dimension"/>
        <attr name="ngv_tileMaxHeight" format="dimension"/>
        <attr name="ngv_maxSize" format="integer"/>
        <attr name="ngv_mode" format="enum">
            <enum name="fill" value="0"/>
            <enum name="grid" value="1"/>
            <enum name="tile" value="2"/>
        </attr>
    </declare-styleable>

二、设置平铺模式的控件大小 ;

 2或4张时图片的高度是单张图片的0.7倍 , 多张图时高度时单张图片的0.5倍 , 当然这个是为了满足我这个项目的需求,这里也可以自定义(固定高度或宽高相等);

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // ***
        if (mImageInfo != null && mImageInfo.size() > 0) {

            if (mode == MODE_TILE) { //平铺模式
                if (mImageInfo.size() == 1) {
                    gridWidth = totalWidth;
                    gridHeight = tileMaxHeight;
                } else if (mImageInfo.size() == 2 || mImageInfo.size() == 4) {
                    gridWidth = (totalWidth - gridSpacing) / 2;
                    gridHeight = (int) (tileMaxHeight * 0.7);
                } else {
                    gridWidth = (totalWidth - gridSpacing * 2) / 3;
                    gridHeight = (int) (tileMaxHeight * 0.5);
                }
            } else {
               // ***
            }
            width = gridWidth * columnCount + gridSpacing * (columnCount - 1) + getPaddingLeft() + getPaddingRight();
            height = gridHeight * rowCount + gridSpacing * (rowCount - 1) + getPaddingTop() + getPaddingBottom();
        }
        setMeasuredDimension(width, height);
    }

三、2或4张图的排列方式;

  2张图时为1行 、 4张图时2为2行;

   public void setAdapter(@NonNull NineGridViewAdapter adapter) {
          // ***
        //grid模式下,显示4张使用2X2模式
        if (mode == MODE_GRID) {
            if (imageCount == 4) {
                rowCount = 2;
                columnCount = 2;
            }
        } else if (mode == MODE_TILE) { //平铺模式
            if (imageCount == 2) {
                rowCount = 1;
                columnCount = 2;
            } else if (imageCount == 4) {
                rowCount = 2;
                columnCount = 2;
            }
        }
        // ***
    }

当然我这边也做了其它的小修改,比如图片可以设置资源文件之类的,这些的修改都不影响原框架的使用;

此源码已上传:https://github.com/CuiChenbo/CcMall/tree/master/ninegridview

下面是全部代码:

public class NineGridView extends ViewGroup {

    public static final int MODE_FILL = 0;          //填充模式,类似于微信
    public static final int MODE_GRID = 1;          //网格模式,类似于QQ,4张图会 2X2布局
    public static final int MODE_TILE = 2;          //平铺网格模式

    private static ImageLoader mImageLoader;        //全局的图片加载器(必须设置,否者不显示图片)

    private int tileMaxHeight = 200;                 // 平铺模式最大高度
    private int singleImageSize = 250;              // 单张图片时的最大大小,单位dp
    private float singleImageRatio = 1.0f;          // 单张图片的宽高比(宽/高)
    private int maxImageSize = 9;                   // 最大显示的图片数
    private int gridSpacing = 3;                    // 宫格间距,单位dp
    private int mode = MODE_FILL;                   // 默认使用fill模式

    private int columnCount;    // 列数
    private int rowCount;       // 行数
    private int gridWidth;      // 宫格宽度
    private int gridHeight;     // 宫格高度

    private List<ImageView> imageViews;
    private List<ImageInfo> mImageInfo;
    private NineGridViewAdapter mAdapter;

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

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

    public NineGridView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        gridSpacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gridSpacing, dm);
        singleImageSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, singleImageSize, dm);
        tileMaxHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tileMaxHeight, dm);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NineGridView);
        gridSpacing = (int) a.getDimension(R.styleable.NineGridView_ngv_gridSpacing, gridSpacing);
        singleImageSize = a.getDimensionPixelSize(R.styleable.NineGridView_ngv_singleImageSize, singleImageSize);
        tileMaxHeight = a.getDimensionPixelSize(R.styleable.NineGridView_ngv_tileMaxHeight, tileMaxHeight);
        singleImageRatio = a.getFloat(R.styleable.NineGridView_ngv_singleImageRatio, singleImageRatio);
        maxImageSize = a.getInt(R.styleable.NineGridView_ngv_maxSize, maxImageSize);
        mode = a.getInt(R.styleable.NineGridView_ngv_mode, mode);
        a.recycle();

        imageViews = new ArrayList<>();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = 0;
        int totalWidth = width - getPaddingLeft() - getPaddingRight();
        if (mImageInfo != null && mImageInfo.size() > 0) {

            if (mode == MODE_TILE) { //平铺模式
                if (mImageInfo.size() == 1) {
                    gridWidth = totalWidth;
                    gridHeight = tileMaxHeight;
                } else if (mImageInfo.size() == 2 || mImageInfo.size() == 4) {
                    gridWidth = (totalWidth - gridSpacing) / 2;
                    gridHeight = (int) (tileMaxHeight * 0.7);  //自定义高度(单张图片的0.7倍)
                } else {
                    gridWidth = (totalWidth - gridSpacing * 2) / 3;
                    gridHeight = (int) (tileMaxHeight * 0.5);  //自定义高度
                    // gridHeight = gridWidth ;  //宽高相等
                }
            } else {
                if (mImageInfo.size() == 1) {
                    gridWidth = singleImageSize > totalWidth ? totalWidth : singleImageSize;
                    gridHeight = (int) (gridWidth / singleImageRatio);
                    //矫正图片显示区域大小,不允许超过最大显示范围
                    if (gridHeight > singleImageSize) {
                        float ratio = singleImageSize * 1.0f / gridHeight;
                        gridWidth = (int) (gridWidth * ratio);
                        gridHeight = singleImageSize;
                    }
                } else {
//                gridWidth = gridHeight = (totalWidth - gridSpacing * (columnCount - 1)) / columnCount;
                    //这里无论是几张图片,宽高都按总宽度的 1/3
                    gridWidth = gridHeight = (totalWidth - gridSpacing * 2) / 3;
                }
            }
            width = gridWidth * columnCount + gridSpacing * (columnCount - 1) + getPaddingLeft() + getPaddingRight();
            height = gridHeight * rowCount + gridSpacing * (rowCount - 1) + getPaddingTop() + getPaddingBottom();
        }
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (mImageInfo == null) return;
        int childrenCount = mImageInfo.size();
        for (int i = 0; i < childrenCount; i++) {
            ImageView childrenView = (ImageView) getChildAt(i);

            int rowNum = i / columnCount;
            int columnNum = i % columnCount;
            int left = (gridWidth + gridSpacing) * columnNum + getPaddingLeft();
            int top = (gridHeight + gridSpacing) * rowNum + getPaddingTop();
            int right = left + gridWidth;
            int bottom = top + gridHeight;
            childrenView.layout(left, top, right, bottom);

            if (mImageLoader != null) {
                if (mImageInfo.get(i).thumbnailUrl != null) {
                    mImageLoader.onDisplayImage(getContext(), childrenView, mImageInfo.get(i).thumbnailUrl);
                } else {
                    mImageLoader.onDisplayImage(getContext(), childrenView, mImageInfo.get(i).srcUrl);
                }
            }
        }
    }

    /**
     * 设置适配器
     */
    public void setAdapter(@NonNull NineGridViewAdapter adapter) {
        mAdapter = adapter;
        List<ImageInfo> imageInfo = adapter.getImageInfo();

        if (imageInfo == null || imageInfo.isEmpty()) {
            setVisibility(GONE);
            return;
        } else {
            setVisibility(VISIBLE);
        }

        int imageCount = imageInfo.size();
        if (maxImageSize > 0 && imageCount > maxImageSize) {
            imageInfo = imageInfo.subList(0, maxImageSize);
            imageCount = imageInfo.size();   //再次获取图片数量
        }

        //默认是3列显示,行数根据图片的数量决定
        rowCount = imageCount / 3 + (imageCount % 3 == 0 ? 0 : 1);
        columnCount = 3;
        //grid模式下,显示4张使用2X2模式
        if (mode == MODE_GRID) {
            if (imageCount == 4) {
                rowCount = 2;
                columnCount = 2;
            }
        } else if (mode == MODE_TILE) { //平铺模式
            if (imageCount == 2) {
                rowCount = 1;
                columnCount = 2;
            } else if (imageCount == 4) {
                rowCount = 2;
                columnCount = 2;
            }
        }

        //保证View的复用,避免重复创建
        if (mImageInfo == null) {
            for (int i = 0; i < imageCount; i++) {
                ImageView iv = getImageView(i);
                if (iv == null) return;
                addView(iv, generateDefaultLayoutParams());
            }
        } else {
            int oldViewCount = mImageInfo.size();
            int newViewCount = imageCount;
            if (oldViewCount > newViewCount) {
                removeViews(newViewCount, oldViewCount - newViewCount);
            } else if (oldViewCount < newViewCount) {
                for (int i = oldViewCount; i < newViewCount; i++) {
                    ImageView iv = getImageView(i);
                    if (iv == null) return;
                    addView(iv, generateDefaultLayoutParams());
                }
            }
        }
        //修改最后一个条目,决定是否显示更多
        if (adapter.getImageInfo().size() > maxImageSize) {
            View child = getChildAt(maxImageSize - 1);
            if (child instanceof NineGridViewWrapper) {
                NineGridViewWrapper imageView = (NineGridViewWrapper) child;
                imageView.setMoreNum(adapter.getImageInfo().size() - maxImageSize);
            }
        }
        mImageInfo = imageInfo;
        requestLayout();
    }

    /**
     * 获得 ImageView 保证了 ImageView 的重用
     */
    private ImageView getImageView(final int position) {
        ImageView imageView;
        if (position < imageViews.size()) {
            imageView = imageViews.get(position);
        } else {
            imageView = mAdapter.generateImageView(getContext());
            imageView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    mAdapter.onImageItemClick(getContext(), NineGridView.this, position, mAdapter.getImageInfo());
                }
            });
            imageViews.add(imageView);
        }
        return imageView;
    }

    /**
     * 设置宫格间距
     */
    public void setGridSpacing(int spacing) {
        gridSpacing = spacing;
    }

    /**
     * 设置只有一张图片时的宽
     */
    public void setSingleImageSize(int maxImageSize) {
        singleImageSize = maxImageSize;
    }

    /**
     * 设置只有一张图片时的宽高比
     */
    public void setSingleImageRatio(float ratio) {
        singleImageRatio = ratio;
    }

    /**
     * 设置最大图片数
     */
    public void setMaxSize(int maxSize) {
        maxImageSize = maxSize;
    }

    public int getMaxSize() {
        return maxImageSize;
    }

    public static void setImageLoader(ImageLoader imageLoader) {
        mImageLoader = imageLoader;
    }

    public static ImageLoader getImageLoader() {
        return mImageLoader;
    }

    public interface ImageLoader {
        /**
         * 需要子类实现该方法,以确定如何加载和显示图片
         *
         * @param context   上下文
         * @param imageView 需要展示图片的ImageView
         * @param url       图片地址
         */
        void onDisplayImage(Context context, ImageView imageView, String url);

        void onDisplayImage(Context context, ImageView imageView, Integer src);

        /**
         * @param url 图片的地址
         * @return 当前框架的本地缓存图片
         */
        Bitmap getCacheImage(String url);
    }
}

再次感谢 https://github.com/jeasonlzy/NineGridView 的开源,同时该作者还有一个优秀的网络框架https://github.com/jeasonlzy/okhttp-OkGo ;

 

 

 

 

 

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值