Android自定义ViewGroup实现9宫格布局
2017-07-23 22:58
495 查看
实现思想即自定义一个继承ViewGroup的view
需要实现三个类
1.NineGridView ,即自定义的ViewGroup
2.NineGridViewAdapter,数据适配器类
3.ImageInfo,图片信息的实体类
相应类的实现代码:
NineGridView
NineGridViewAdapter
ImageInfo
一般的应用场景是在列表中展示多条9宫格样式的图片,如微信朋友圈
因此需要在LIstView或RecyclerView的adapter对应的Item布局中引入NIneGridView, 在adapter中添加数据以及设置9宫格数据的适配器
使用方法:
1.布局中引入NineGridView,设置控件width,height,paddingLeft,paddingRight等信息
2.在ListView或RecyclerView的adapter中调用setImageLoader方法,确定如何加载和显示图片(就是用哪种图片框架)
3.添加图片数据信息,创建NineGridViewAdapter,将包含图片信息的数据集合list添加进去,最后调用NineGridView的setAdapter方法,
设置数据适配器。
需要实现三个类
1.NineGridView ,即自定义的ViewGroup
2.NineGridViewAdapter,数据适配器类
3.ImageInfo,图片信息的实体类
相应类的实现代码:
NineGridView
package com.gif.gifchannel.widget; import android.content.Context; import android.content.res.TypedArray; import android.support.annotation.NonNull; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.gif.gifchannel.R; import java.util.ArrayList; import java.util.List; /** * Created by Answer on 2017/7/14. */ public class NineGridView extends ViewGroup { // public static final int MODE_FILL = 0; //填充模式,类似于微信 // public static final int MODE_GRID = 1; //网格模式,类似于QQ,4张图会 2X2布局 private static ImageLoader mImageLoader; //全局的图片加载器(必须设置,否则不显示图片) private clickL click; private int singleImageSize = 250; // 单张图片时的最大大小,单位dp private float singleImageRatio = 1.0f; // 单张图片的宽高比(宽/高) private int maxImageSize = 9; // 最大显示的图片数 private int gridSpacing = 4; // 宫格间距,单位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); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NineGridView); gridSpacing = (int) a.getDimension(R.styleable.NineGridView_ngv_gridSpacing, gridSpacing); 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) { //只有1张图时 图片宽度即是总宽度 高度等于宽度 if (mImageInfo.size() == 1) { gridWidth = totalWidth; gridHeight = gridWidth; Log.d("yzpzz","wid "+gridWidth+ "height "+gridHeight); } else { //按照有几列 来计算每张图片的宽度和高度 //gridWidth 、gridHeight表示每张图片占据的宽、高 gridWidth = gridHeight = (totalWidth - gridSpacing * (columnCount - 1)) / columnCount; } //此处width height就是我们即将为控件设置的总宽度 width可在layout中给定 height需要根据图片数量计算 width = gridWidth * columnCount + gridSpacing * (columnCount - 1) + getPaddingLeft() + getPaddingRight(); height = gridHeight * rowCount + gridSpacing * (rowCount - 1) + getPaddingTop() + getPaddingBottom(); Log.d("yzp","wid "+width+ "height "+height); } 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(); //根据图片数量 创建相应个数的imageview 并根据设定的imageview的宽高以及间距 ,将imageview放置在正确的位置 for (int i = 0; i < childrenCount; i++) { //得到父控件中相应的imageview 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; Log.d("yyy","left "+left+"right "+right+ "top "+top+"bottom "+bottom); childrenView.layout(left, top, right, bottom); //imageloader是接口,调用接口中的onDisplayImage方法绘制imageview 。在使用的地方调用setImageLoader方法 //重写接口中的方法,可以使用不同的图片框架显示图片 如Glide Piccasso等 if (mImageLoader != null) { mImageLoader.onDisplayImage(getContext(), childrenView, mImageInfo.get(i).imageUrl); } } } /** 设置适配器 */ //等到adapter 得到需要显示的图片信息 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 (imageCount == 4) { rowCount = 2; columnCount = 2; } //grid模式下,显示2张图片使用 2X1 模式 if (imageCount == 2) { rowCount = 1; columnCount = 2; } if(imageCount ==1){ rowCount =1; columnCount =1; } //保证View的复用,避免重复创建 //mImageInfo=null 表示第一次创建 if (mImageInfo == null) { for (int i = 0; i < imageCount; i++) { ImageView iv = getImageView(i); if (iv == null) return; //添加相应个imageview到父控件 viewgroup中 addView(iv, generateDefaultLayoutParams()); } } else { //根据上次已有的imageview数量以及这次需要创建的imageview数量 移除或添加相应个数个imageview 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 = (NineGri 4000 dViewWrapper) child; imageView.setMoreNum(adapter.getImageInfo().size() - maxImageSize); } }*/ //将传过来的imageInfo信息赋给mImageInfo 用于判断下次是否需要全部创建 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()); click.imageClick(); } }); 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); /* *//** * @param url 图片的地址 * @return 当前框架的本地缓存图片 *//* Bitmap getCacheImage(String url);*/ } //设置图片的点击事件 public void setClick(clickL click){ this.click=click; } public interface clickL{ void imageClick(); } }
NineGridViewAdapter
package com.gif.gifchannel.widget; import android.content.Context; import android.widget.ImageView; import com.gif.gifchannel.R; import java.io.Serializable; import java.util.List; /** * Created by Answer on 2017/7/14. * 适配器类,用于添加数据以及生成imageview */ public class NineGridViewAdapter implements Serializable { protected Context context; private List<ImageInfo> imageInfo; public NineGridViewAdapter(Context context, List<ImageInfo> imageInfo) { this.context = context; this.imageInfo = imageInfo; } /** * 如果要实现图片点击的逻辑,重写此方法即可 * * @param context 上下文 * @param nineGridView 九宫格控件 * @param index 当前点击图片的的索引 * @param imageInfo 图片地址的数据集合 */ protected void onImageItemClick(Context context, NineGridView nineGridView, int index, List<ImageInfo> imageInfo) { } /** * 生成ImageView容器的方式, * 如果需要自定义图片展示效果,重写此方法即可 * * @param context 上下文 * @return 生成的 ImageView */ protected ImageView generateImageView(Context context) { ImageView imageView = new ImageView(context); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); //imageView.setImageResource(R.drawable.ic); return imageView; } public List<ImageInfo> getImageInfo() { return imageInfo; } public void setImageInfoList(List<ImageInfo> imageInfo) { this.imageInfo = imageInfo; } }
ImageInfo
package com.gif.gifchannel.widget; import java.io.Serializable; /** * Created by Answer on 2017/7/14. * 图片信息的实体类,三个参数分别为图片的URL地址 图片的高度以及宽度 */ public class ImageInfo implements Serializable { public String imageUrl; public int imageViewHeight; public int imageViewWidth; public String getImageUrl() { return imageUrl; } public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } public int getImageViewHeight() { return imageViewHeight; } public void setImageViewHeight(int imageViewHeight) { this.imageViewHeight = imageViewHeight; } public int getImageViewWidth() { return imageViewWidth; } public void setImageViewWidth(int imageViewWidth) { this.imageViewWidth = imageViewWidth; } @Override public String toString() { return "ImageInfo{" + "imageUrl='" + imageUrl + '\'' + ", imageViewHeight=" + imageViewHeight + ", imageViewWidth=" + imageViewWidth + '}'; } }自定义属性,在attrs.xml中
<declare-styleable name="NineGridView"> <attr name="ngv_gridSpacing" format="dimension"/> </declare-styleable>
一般的应用场景是在列表中展示多条9宫格样式的图片,如微信朋友圈
因此需要在LIstView或RecyclerView的adapter对应的Item布局中引入NIneGridView, 在adapter中添加数据以及设置9宫格数据的适配器
使用方法:
1.布局中引入NineGridView,设置控件width,height,paddingLeft,paddingRight等信息
<com.gif.gifchannel.widget.NineGridView android:id="@+id/ugc_item_ninegrid" android:layout_width="match_parent" android:layout_height="200dp" android:layout_below="@+id/ugc_item_content" android:layout_marginTop="12dp" android:paddingLeft="8dp" android:paddingRight="8dp" app:ngv_gridSpacing="4dp" />
2.在ListView或RecyclerView的adapter中调用setImageLoader方法,确定如何加载和显示图片(就是用哪种图片框架)
NineGridView.setImageLoader(new NineGridView.ImageLoader() { @Override public void onDisplayImage(Context context, ImageView imageView, String url) { Glide.with(context).load(url).priority(Priority.NORMAL).placeholder(R.mipmap.placehold).centerCrop().into( imageView); } });
3.添加图片数据信息,创建NineGridViewAdapter,将包含图片信息的数据集合list添加进去,最后调用NineGridView的setAdapter方法,
设置数据适配器。
List<ImageInfo> imageInfoList = new ArrayList<>(); for (int i = 0; i < ugcItem.getImages().size(); i++) { String url = ugcItem.getImages().get(i).getUrl(); ImageInfo info = new ImageInfo(); info.setImageUrl(url); imageInfoList.add(info); } NineGridViewAdapter adapter = new NineGridViewAdapter(mContext, imageInfoList); holder.ugc_item_ninegrid.setAdapter(adapter);
相关文章推荐
- android之自定义ViewGroup和自动换行的布局的实现(支持按钮间隔)
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- Android 自定义ViewGroup 实现FlowLayout,动态添加布局
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- Android自定义ViewGroup实现流式布局
- android自定义viewgroup实现等分格子布局
- android之自定义ViewGroup和自动换行的布局的实现
- 在Android中,可以自定义类,继承ViewGroup等容器类,以实现自己需要的布局显示。
- android之自定义ViewGroup和自动换行的布局的实现
- android自定义viewgroup实现等分格子布局
- android自定义viewgroup实现等分格子布局
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android自定义viewgroup实现等分格子布局
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android自定义viewgroup实现等分格子布局