今天我要说的是,在项目中遇到这种情况,就是在个人中心,购买的商品有五种状态,这五个图标将要是下面这样的排列如图:
要求:
1.位置1和位置2分别位于父容器的left和right,这是必须满足的条件
2.这5个View必须是平分父容器的
首先我先到了GrideView,然后发现无论怎么调整item布局都无法达到上述要求,位置5无法满足
然后,我用的是LinearLayout,写五个,发先还是不行,两边的确定了,中间区域和两边的区域的距离无法做到一致,本来先想弄个线程的布局写写就可以了,可是,浪费了一些时间,算了,还是自己定义吧!。
1.继承ViewGroup
2.重写OnMeasure()方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int modeW = MeasureSpec.getMode(widthMeasureSpec);
int modeH = MeasureSpec.getMode(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
measureChildren(widthMeasureSpec,heightMeasureSpec);
if (mDirection==HORIZONTAL&&modeW==MeasureSpec.UNSPECIFIED){
//这里没有指定大小
throw new RuntimeException("if you sure this view's weight exactly");
}
if (mDirection==VERTICAL&&modeW==MeasureSpec.UNSPECIFIED){
//这里没有指定大小
throw new RuntimeException("if you sure this view's height exactly");
}
if (modeH!=MeasureSpec.EXACTLY) {
//要测量子View的高度
switch (mDirection) {
case HORIZONTAL:
int hH = getHorizontalHeight();
setMeasuredDimension(width, hH);
break;
case VERTICAL:
int hV = getVerticalWidth();
setMeasuredDimension(width, hV);
break;
}
}else {
setMeasuredDimension(width,height);
}
}
/**
* 垂直方向时,测量View的高度
* @return
*/
private int getVerticalWidth() {
int w = 0;
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
MarginLayoutParams lp;
//获取View的MarginLayoutParams实例
if (child.getLayoutParams() instanceof ViewGroup.MarginLayoutParams){
lp = (MarginLayoutParams) child.getLayoutParams();
}else {
lp = new MarginLayoutParams(child.getLayoutParams());
}
int childW = child.getMeasuredWidth()+lp.leftMargin+lp.rightMargin;
Math.max(w,childW);
}
return w;
}
/**
* 水平方向时,View的高度
* @return
*/
private int getHorizontalHeight() {
int h = 0;
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
MarginLayoutParams lp;
//获取View的MarginLayoutParams实例
if (child.getLayoutParams() instanceof ViewGroup.MarginLayoutParams){
lp = (MarginLayoutParams) child.getLayoutParams();
}else {
lp = new MarginLayoutParams(child.getLayoutParams());
}
int childH = child.getMeasuredHeight()+lp.topMargin+lp.bottomMargin;
h=Math.max(h,childH);
}
return h;
}
3.实现onLayout()方法
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
int margin;
switch (mDirection) {
case HORIZONTAL:
margin = getHorizontalMargin(count);
//layout
layoutHorizontalChild(count,margin);
break;
case VERTICAL:
margin = getVerticalMargin(count);
layoutVerticalChild(count,margin);
break;
}
}
private void layoutHorizontalChild(int count,int margin) {
int wNum = getPaddingLeft();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
child.layout(wNum,getTopOrDownMargin(child),wNum+child.getMeasuredWidth(),getTopOrDownMargin(child)+child.getMeasuredHeight());
wNum += child.getMeasuredWidth()+margin;
}
}
private void layoutVerticalChild(int count,int margin) {
int hNum = getPaddingTop();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
child.layout(getLeftOrRightMargin(child),hNum,getLeftOrRightMargin(child)+child.getMeasuredWidth(),
hNum+child.getMeasuredHeight());
hNum += child.getMeasuredHeight()+margin;
}
}
public int getTopOrDownMargin(View child){
int h = child.getMeasuredHeight();
return (getMeasuredHeight()-h)/2;
}
public int getLeftOrRightMargin(View child){
int w = child.getMeasuredWidth();
return (getMeasuredWidth()-w)/2;
}
private int getHorizontalMargin(int count) {
int margin = getMeasuredWidth()-getPaddingLeft()-getPaddingRight();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
margin -= child.getMeasuredWidth();
}
//真正的margin
return margin/(count-1);
}
private int getVerticalMargin(int count) {
int margin = getMeasuredHeight()-getPaddingTop()-getPaddingBottom();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
margin -= child.getMeasuredHeight();
}
//真正的margin
return margin/(count-1);
}
好了,现在我们已经正确测量和layout了child,现在我们要设计数据的载入
public class Adapter<T>{
private List<Map<T,Object>> mList;
private @LayoutRes int mLayout;
private String[] key;
private @IdRes int id[];
/**
* 类似SimpleAdapter
* @param mList 带有数据的集合
* @param mLayout 布局id
* @param key Map中的key的数组
* @param id 与key一一对应的View的id
*/
public Adapter(List<Map<T, Object>> mList, int mLayout, String[] key, int[] id) {
this.mList = mList;
this.mLayout = mLayout;
this.key = key;
this.id = id;
}
private void addView(){
removeAllViews();
for (Map<T,Object> map:mList){
View view = LayoutInflater.from(getContext()).inflate(mLayout,null);
int size = id.length;
for (int i = 0; i <size ; i++) {
Object obj = map.get(key[i]);
if (obj instanceof String){
TextView tv = (TextView) view.findViewById(id[i]);
tv.setText((String) obj);
}
if (obj instanceof Integer){
ImageView img = (ImageView) view.findViewById(id[i]);
img.setImageResource((Integer) obj);
}
}
GongGeView.this.addView(view);
invalidate();
requestLayout();
}
}
}
这是一个内部类,负责将View加进父容器。
点击时间的监听
public interface ItemClickListener{
void click(View v,int position);
}
点击时间接口抛出,留给用户
public void setOnItemClickListener(final ItemClickListener mItemClickListener){
this.mItemClickListener = mItemClickListener;
int count = getChildCount();
for (int i = 0; i < count; i++) {
View v = getChildAt(i);
final int finalI = i;
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mItemClickListener==null){
return;
}
mItemClickListener.click(v, finalI);
}
});
}
}
好了,这就完成了,效果如下如图: