自定义View实现项目中的需求

今天我要说的是,在项目中遇到这种情况,就是在个人中心,购买的商品有五种状态,这五个图标将要是下面这样的排列如图:
这里写图片描述
要求:
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);
            }
        });
    }
}

好了,这就完成了,效果如下如图:
这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值