自定义View之MenuItemView

Posted FightSeeker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义View之MenuItemView相关的知识,希望对你有一定的参考价值。

着手开发一款应用的时候,设置或者菜单页面是可能需要的,但是,那重复的布局会很令人苦恼。新手可能会一项项的重复绘制,有经验的你或许会用到include,或者用到组合控件。除了以上的方法之外,闲来无事,写了一个通用的View(MenuItemView)。此view暂时可以展示两种功能,一是通用的项,另一种是带开关的项,截图如下:

1.自定义属性:attrs.xml

    <declare-styleable name="MenuItemView">
        <!-- 基本的参数设置-->
        <attr name="headerDrawable" format="reference" />
        <attr name="headerSize" format="dimension"/>
        <attr name="drawPadding" format="dimension" />
        <attr name="textHeader" format="string" />
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
        <attr name="arrowDrawable" format="reference" />
        <attr name="arrowSize" format="dimension" />
        <attr name="arrowColor" format="color" />
        <attr name="itemType" format="enum">
            <enum name="normalType" value="0" />
            <enum name="arrowType"  value="1" />
            <enum name="toggleType" value="2" />
        </attr>
        <!-- 当类型为switch时,绘制switch用到的参数-->
        <attr name="toggleWidth" format="dimension" />
        <attr name="toggleHeight" format="dimension" />
        <attr name="bordeWidth" format="dimension" />
        <attr name="areaColor" format="color" />
        <attr name="offColor" format="color" />
        <attr name="onColor" format="color" />
        <attr name="handlerColor" format="color" />
        <attr name="animate" format="boolean" />
        <attr name="defaultOn" format="boolean" />
        <!-- 下分割线的绘制属性 -->
        <attr name="dividerr" format="reference|color" />
        <attr name="dividerWidth" format="dimension" />
        <attr name="dividerVisibilty" format="boolean" />
    </declare-styleable>

2.MenuItemView.java源码:

package com.dandy.weight;

/**
 * Created by Administrator on 2016/7/20.
 */
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import com.dandy.album.R;

/**
 * 设置,菜单中的布局项
 * 默认控件是纵向居中显示,所有paddingTop和paddingBottom在这没有作用
 * Created by dandy on 2016/4/14.
 */
public class MenuItemView extends View

    private static final String TAG = "MenuItemView";

    /**默认控件的高**/
    private static final int HEIGHT_DEFAULT = 50;

    /**文字绘制时默认大小**/
    private static final int TEXTSZIE_DEFAULT = 14;

    /**尾部箭头图标大小**/
    private static final int ARROW_SIZE = 13;

    /***SwitchButton默认宽*/
    private static final int SWITCHBUTTON_WIDTH = 50;

    /***SwitchButton默认高*/
    private static final int SWITCHBUTTON_HEIGHT = 28;

    private static  final long DELAYDURATION = 10;

    /**头标**/
    private Drawable headerDrawable;

    /**头标大小,宽高一致**/

    private int headDrawableSize = -1;

    /**头标宽**/
    private int headerDrawableWidth;
    /**头标高**/
    private int headerDrawableHeight;

    /**绘制头标时,画布在Y轴的绘制偏移量**/
    private float headerDrawableStartDrawY;

    /**文字与图片间的距离**/
    private int drawablePadding = 0;

    /**头部文字提示**/
    private String textHeader;

    /**文字颜色**/
    private int textHeaderColor = Color.parseColor("#5a5a5a");

    /**文字大小**/
    private int textSize = -1;

    /**绘制文字的画笔**/
    private Paint textPaint;

    /** 尾部 > 图片**/
    private Drawable arrowDrawable;

    /**尾部 > 大小**/
    private int arrowSize = -1;

    /** > 绘制的X轴偏移量**/
    private float arrowStartDrawX;

    /** > 绘制的Y轴偏移量**/
    private float arrowStartDrawY;

    /**尾部宽**/
    private int arrowDrawableWidth;
    /**尾部高**/
    private int arrowDrawableHeight;

    /**绘制arrow画笔**/
    private Paint arrowPaint;

    /**arrowPaint 颜色**/
    private int arrowColor = Color.parseColor("#5a5a5a");

    private DisplayMetrics dm;

    /*以下是绘制SwitchButton所用到的参数*/

    private ItemType itemType = ItemType.NORMAL;

    /**默认宽**/
    private  int toggleWidth = -1;

    /**默认高**/
    private int toggleHeight = -1;

    /**开启颜色**/
    private int onColor = Color.parseColor("#4ebb7f");
    /**关闭颜色**/
    private int offColor = Color.parseColor("#dadbda");
    /**灰色带颜色**/
    private int areaColor = Color.parseColor("#dadbda");
    /**手柄颜色**/
    private int handlerColor = Color.parseColor("#ffffff");
    /**边框颜色**/
    private int borderColor = offColor;
    /**开关状态**/
    private boolean toggleOn = false;
    /**边框宽**/
    private int borderWidth = 2;
    /**纵轴中心**/
    private float centerY;
    /**按钮水平方向开始、结束的位置**/
    private float startX,endX;
    /**手柄x轴方向最小、最大值**/
    private float handlerMinX,handlerMaxX;
    /**手柄大小**/
    private int handlerSize;
    /**手柄在x轴的坐标位置**/
    private float handlerX;
    /**关闭时内部灰色带宽度**/
    private float areaWidth;
    /**是否使用动画效果**/
    private boolean animate = true;
    /**是否默认处于打开状态**/
    private boolean defaultOn = true;
    /**按钮半径**/
    private float radius;

    /**整个switchButton的区域**/
    private RectF toggleRectF = new RectF();

    /**绘制switchButton的画笔**/
    private Paint togglePaint;

    private OnToggleChangedListener mListener;

    private double currentDelay;

    private float downX = 0;

    /**switchButton在X轴绘制的偏移量**/
    private float switchButtonDrawStartX;

    /**switchButton在Y轴绘制的偏移量**/
    private float switchButtonDrawStartY;

    /**分割线,默认在底部绘制**/
    private Drawable dividerr;

    /**分割线绘制的宽**/
    private int dividerWidth = 2;

    /**是否需要绘制分割线**/
    private boolean dividerVisibilty = true;

    private boolean isPressed = false;

    public MenuItemView(Context context, AttributeSet attrs, int defStyleAttr) 
        super(context, attrs, defStyleAttr);
        setup(attrs);
    
    public MenuItemView(Context context, AttributeSet attrs) 
        super(context, attrs);
        setup(attrs);
    

    /**
     * 初始化控件,获取相关的控件属性
     * @param attrs
     */
    private void setup(AttributeSet attrs)

        dm = Resources.getSystem().getDisplayMetrics();

        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MenuItemView);
        if(typedArray != null)
            int count = typedArray.getIndexCount();
            for(int i = 0;i < count;i++)
                int attr = typedArray.getIndex(i);
                switch (attr)
                    case R.styleable.MenuItemView_headerDrawable:
                        headerDrawable = typedArray.getDrawable(attr);
                        break;
                    case R.styleable.MenuItemView_headerSize:
                        headDrawableSize = typedArray.getDimensionPixelSize(attr,headDrawableSize);
                        break;
                    case R.styleable.MenuItemView_drawPadding:
                        drawablePadding = typedArray.getDimensionPixelSize(attr, drawablePadding);
                        break;
                    case R.styleable.MenuItemView_textHeader:
                        textHeader = typedArray.getString(attr);
                        break;
                    case R.styleable.MenuItemView_textColor:
                        textHeaderColor = typedArray.getColor(attr, textHeaderColor);
                        break;
                    case R.styleable.MenuItemView_textSize:
                        textSize = typedArray.getDimensionPixelSize(attr, textSize);
                        break;
                    case R.styleable.MenuItemView_arrowDrawable:
                        arrowDrawable = typedArray.getDrawable(attr);
                        break;
                    case R.styleable.MenuItemView_arrowSize:
                        arrowSize = typedArray.getDimensionPixelSize(attr, arrowSize);
                        break;
                    case R.styleable.MenuItemView_arrowColor:
                        arrowColor = typedArray.getColor(attr, arrowColor);
                        break;
                    case R.styleable.MenuItemView_onColor:
                        onColor = typedArray.getColor(attr, onColor);
                        break;
                    case R.styleable.MenuItemView_offColor:
                        borderColor = offColor = typedArray.getColor(attr,offColor);
                        break;
                    case R.styleable.MenuItemView_areaColor:
                        areaColor = typedArray.getColor(attr, areaColor);
                        break;
                    case R.styleable.MenuItemView_handlerColor:
                        handlerColor = typedArray.getColor(attr, handlerColor);
                        break;
                    case R.styleable.MenuItemView_bordeWidth:
                        borderWidth = typedArray.getColor(attr, borderWidth);
                        break;
                    case R.styleable.MenuItemView_animate:
                        animate = typedArray.getBoolean(attr, animate);
                        break;
                    case R.styleable.MenuItemView_defaultOn:
                        defaultOn = typedArray.getBoolean(attr, defaultOn);
                        break;
                    case R.styleable.MenuItemView_itemType:
                        itemType = ItemType.getValue(typedArray.getInt(attr, ItemType.NORMAL.ordinal()));
                        break;
                    case R.styleable.MenuItemView_toggleWidth:
                        toggleWidth = typedArray.getDimensionPixelOffset(attr, toggleWidth);
                        break;
                    case R.styleable.MenuItemView_toggleHeight:
                        toggleHeight = typedArray.getDimensionPixelOffset(attr, toggleHeight);
                        break;
                    case R.styleable.MenuItemView_dividerr:
                        dividerr = typedArray.getDrawable(attr);
                        break;
                    case R.styleable.MenuItemView_dividerWidth:
                        dividerWidth = typedArray.getDimensionPixelOffset(attr,dividerWidth);
                        break;
                    case R.styleable.MenuItemView_dividerVisibilty:
                        dividerVisibilty = typedArray.getBoolean(attr,dividerVisibilty);
                        break;
                
            
            typedArray.recycle();
        

        if(textSize == -1)
            textSize = applyDimension(TEXTSZIE_DEFAULT);
        

        /**
         * 初始化文字画笔
         */
        textPaint = new Paint();
        textPaint.setColor(textHeaderColor);
        textPaint.setTextSize(textSize);
        textPaint.setAntiAlias(true);

        if(itemType == ItemType.TOGGLE)

            if(toggleWidth == -1)
                toggleWidth  = applyDimension(SWITCHBUTTON_WIDTH);
            

            if(toggleHeight == -1)
                toggleHeight = applyDimension(SWITCHBUTTON_HEIGHT);
            

            togglePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            togglePaint.setStyle(Paint.Style.FILL);
            togglePaint.setStrokeCap(Paint.Cap.ROUND);
            togglePaint.setAntiAlias(true);

            if(defaultOn)
                currentDelay = 1;
                toggleOn();
            else
                currentDelay = 0;
                toggleOff();
            
        else if(itemType == ItemType.ARROW)
            if(arrowSize == -1)
                arrowSize = applyDimension(ARROW_SIZE);
            
            arrowPaint = new Paint();
            arrowPaint.setColor(arrowColor);
            arrowPaint.setAntiAlias(true);
            arrowPaint.setStrokeWidth(3.0f);
        

        /**
         * 设置默认背景色
         */
        if(getBackground() == null)
            setBackgroundColor(Color.parseColor("#FFFFFF"));
        
    

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) 

        if(headerDrawable != null)
            if(headDrawableSize >= 0 )
                headerDrawableWidth = headerDrawableHeight = headDrawableSize;
            else
                headerDrawableWidth = headerDrawable.getIntrinsicWidth();
                headerDrawableHeight = headerDrawable.getIntrinsicHeight();
            
            Log.i(TAG,"[onLayout] headerDrawableWidth = "+headerDrawableWidth+",headerDrawableHeight = "+headerDrawableHeight);

            headerDrawableStartDrawY = (getHeight() - headerDrawableHeight)/ 2.0f;
            Log.i(TAG, "[onLayout] headerDrawableStartDrawY = " + headerDrawableStartDrawY);
        

        if(itemType == ItemType.ARROW)
            if(arrowDrawable != null)
                arrowDrawableWidth = arrowDrawable.getIntrinsicWidth();
                arrowDrawableHeight = arrowDrawable.getIntrinsicHeight();
            
            if(arrowSize >= 0)
                arrowDrawableWidth = arrowDrawableHeight = arrowSize;
            
            Log.i(TAG, "[onLayout] arrowDrawableWidth = " + arrowDrawableWidth + ",arrowDrawableHeight = " + arrowDrawableHeight);

            arrowStartDrawX = getWidth() - getPaddingRight() - arrowDrawableWidth;
            arrowStartDrawY = (getHeight() - arrowDrawableHeight) / 2.0f;
            Log.i(TAG, "[onLayout] arrowStartDrawX = " + arrowStartDrawX + ",arrowStartDrawY = " + arrowStartDrawY);
        else if(itemType == ItemType.TOGGLE)
            radius = Math.min(toggleWidth,toggleHeight) * 0.5f;
            centerY = radius;
            startX = centerY;
            endX = toggleWidth - radius;
            handlerMinX = startX + borderWidth;
            handlerMaxX = endX - borderWidth;
            handlerSize = toggleHeight - 4*borderWidth;
            handlerX = toggleOn?handlerMaxX:handlerMinX;
            areaWidth = 0;

            switchButtonDrawStartX = getWidth() - getPaddingRight() - toggleWidth;
            switchButtonDrawStartY = (getHeight() - toggleHeight) / 2.0f;
            Log.i(TAG, "[onLayout] switchButtonDrawStartX = " + switchButtonDrawStartX + ",switchButtonDrawStartY = " + switchButtonDrawStartY);
        

        super.onLayout(changed, left, top, right, bottom);
    

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 

        /**计算宽**/
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        if(widthMode == MeasureSpec.UNSPECIFIED || widthMode == MeasureSpec.AT_MOST)
            width = applyDimension(-1);
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
        

        /**计算高**/
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (heightMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.AT_MOST) 
            height = applyDimension(HEIGHT_DEFAULT);
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
        

        Log.i(TAG, "[onMeasure] width = " + width + ",height = " + height);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    

    @Override
    protected void onDraw(Canvas canvas) 

        Log.i(TAG, "[onDraw] start draw!");

        if(headerDrawable != null)
            drawHeaderDrawable(canvas);
        

        drawHeaderText(canvas);

        if (itemType == ItemType.ARROW) 
            drawFooterDrawable(canvas);
        else if(itemType == ItemType.TOGGLE)
            drawSwitchButton(canvas);
        

        if(dividerVisibilty)
            drawDivider(canvas);
        

        super.onDraw(canvas);
    

    @Override
    public boolean onTouchEvent(MotionEvent event) 
        switch (event.getAction())
            case MotionEvent.ACTION_DOWN:
                isPressed = true;
                if (itemType != ItemType.TOGGLE)
                    postDelayed(new Runnable() 
                        @Override
                        public void run() 
                            MenuItemView.this.setPressed(isPressed);
                        
                    , ViewConfiguration.getTapTimeout());
                else
                    downX = event.getX();
                
                break;
            case MotionEvent.ACTION_MOVE:
                isPressed = false;
                this.setPressed(false);
                break;
            case MotionEvent.ACTION_UP:
                if(itemType != ItemType.TOGGLE)
                    performClick();
                    postDelayed(new Runnable() 
                        @Override
                        public void run() 
                            MenuItemView.this.setPressed(false);
                        
                    , ViewConfiguration.getTapTimeout());
                else if(downX >= switchButtonDrawStartX)//为了扩大switchButton的响应区域
                    toggle();
                
                break;
            default:
                isPressed = false;
                this.setPressed(false);
                break;
        

        return true;
    

    /**
     * 绘制头标
     * @param canvas
     */
    private void drawHeaderDrawable(Canvas canvas)
        if(headerDrawable == null)
            throw new NullPointerException("headerDrawable was setted null !");
        
        canvas.save();
        canvas.translate(getPaddingLeft(), headerDrawableStartDrawY);
        headerDrawable.setBounds(0, 0, headerDrawableWidth, headerDrawableHeight);
        headerDrawable.draw(canvas);
        canvas.restore();
    

    /**
     * 绘制头部文字提示
     * @param canvas
     */
    private void drawHeaderText(Canvas canvas)
        canvas.save();
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        RectF targetRect = new RectF(getPaddingLeft() + headerDrawableWidth + drawablePadding,0,getWidth(),getHeight());
        int baseLine =  (int)((targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2);
        canvas.translate(getPaddingLeft() + headerDrawableWidth + drawablePadding, baseLine);
        canvas.drawText(textHeader, 0, 0, textPaint);
        canvas.restore();
    

    /**
     * 绘制尾部指示图标
     *
     * @param canvas
     */
    private void drawFooterDrawable(Canvas canvas)
        canvas.save();
        canvas.translate(arrowStartDrawX, arrowStartDrawY);
        if(arrowDrawable != null)
            arrowDrawable.setBounds(0, 0, arrowDrawableWidth, arrowDrawableHeight);
            arrowDrawable.draw(canvas);
        else
            /**
             * 自行绘制arrow图标,绘制规则是:X轴坐标在arrow中间位置开始绘制,Y轴绘制不变
             */
            final float centerY = arrowDrawableHeight / 2.0f;
            final float lineStartX = arrowDrawableWidth / 2.0f;
            final float lineEndX = arrowDrawableWidth;
            canvas.drawLine(lineStartX,0,lineEndX,centerY,arrowPaint);
            canvas.drawLine(lineStartX,arrowDrawableHeight,lineEndX,centerY,arrowPaint);
        
        canvas.restore();
    

    /**
     * 绘制switchButton
     * @param canvas
     */
    private void drawSwitchButton(Canvas canvas)
        canvas.save();
        canvas.translate(switchButtonDrawStartX,switchButtonDrawStartY);
        /**绘制整个按钮**/
        toggleRectF.set(0, 0, toggleWidth, toggleHeight);
        togglePaint.setColor(borderColor);
        canvas.drawRoundRect(toggleRectF, radius, radius,togglePaint);

        /**绘制关闭灰色区域**/
        if(areaWidth > 0 )
            final float cy = areaWidth * 0.5f;
            toggleRectF.set(handlerX - cy, centerY - cy, endX + cy, centerY + cy);
            togglePaint.setColor(offColor);
            canvas.drawRoundRect(toggleRectF,cy,cy,togglePaint);
        

        /**绘制手柄**/
        final float handlerRadius = handlerSize * 0.5f;
        toggleRectF.set(handlerX - handlerRadius, centerY - handlerRadius, handlerX + handlerRadius, centerY + handlerRadius);
        togglePaint.setColor(handlerColor);
        canvas.drawRoundRect(toggleRectF, handlerRadius, handlerRadius, togglePaint);
        canvas.restore();
    

    /**
     * 绘制分割线
     * @param canvas
     */
    private void drawDivider(Canvas canvas)
        canvas.save();
        canvas.translate(getPaddingLeft(), getHeight() - dividerWidth);
        if(dividerr == null)
            ShapeDrawable divider = new ShapeDrawable(new RectShape());
            divider.getPaint().setStrokeWidth(dividerWidth);
            divider.getPaint().setAntiAlias(true);
            divider.getPaint().setColor(Color.parseColor("#CCCCCC"));
            divider.setBounds(0, 0, getWidth(), dividerWidth);
            divider.draw(canvas);

        else
            dividerr.setBounds(0, 0, getWidth(),dividerWidth);
            dividerr.draw(canvas);
        
        canvas.restore();
    

    /**
     * 开关状态切换
     */
    public void toggle()
        toggle(animate);
    
    /**
     * 开关状态切换
     * @param animate
     */
    public void toggle(boolean animate)
        toggleOn = !toggleOn;
        takeEffect(animate);
    

    /**
     * 开启状态
     */
    public void toggleOn()
        toggleOn(animate);
    
    /**
     * 开启状态
     * @param animate
     */
    public void toggleOn(boolean animate)
        toggleOn = true;
        takeEffect(animate);
    

    /**
     * 关闭状态
     */
    public void toggleOff()
        toggleOff(animate);
    
    /**
     * 关闭状态
     * @param animate
     */
    public void toggleOff(boolean animate)
        toggleOn = false;
        takeEffect(animate);
    

    /**
     * 开始处理状态切换
     * @param animate
     */
    private void takeEffect(boolean animate)
        if(mListener != null)
            mListener.onToggle(toggleOn);
        
        if(animate)
            postDelayed(toggleRunnable, DELAYDURATION);
        else 
            caculateEffect(toggleOn ? 1 : 0);
        
    

    /**
     * 时时计算
     * @param value
     */
    private void caculateEffect(double value)

        handlerX = (float)mapValueFromRangeToRange(value,0,1.0,handlerMinX,handlerMaxX);

        areaWidth = (float)mapValueFromRangeToRange(1.0-value,0,1.0,10,handlerSize);

        final int fb = Color.blue(onColor);
        final int fr = Color.red(onColor);
        final int fg = Color.green(onColor);

        final int tb = Color.blue(offColor);
        final int tr = Color.red(offColor);
        final int tg = Color.green(offColor);

        int sb = (int) mapValueFromRangeToRange(1.0 - value, 0, 1.0, fb, tb);
        int sr = (int) mapValueFromRangeToRange(1.0 - value, 0, 1.0, fr, tr);
        int sg = (int) mapValueFromRangeToRange(1.0 - value, 0, 1.0, fg, tg);

        sb = clamp(sb, 0, 255);
        sr = clamp(sr, 0, 255);
        sg = clamp(sg, 0, 255);

        borderColor = Color.rgb(sr, sg, sb);

        postInvalidate();
    

    private int clamp(int value, int low, int high) 
        return Math.min(Math.max(value, low), high);
    
    /**
     * Map a value within a given range to another range.
     * @param value the value to map
     * @param fromLow the low end of the range the value is within
     * @param fromHigh the high end of the range the value is within
     * @param toLow the low end of the range to map to
     * @param toHigh the high end of the range to map to
     * @return the mapped value
     */
    private  double mapValueFromRangeToRange(
            double value, double fromLow, double fromHigh,
            double toLow, double toHigh) 
        double fromRangeSize = fromHigh - fromLow;
        double toRangeSize = toHigh - toLow;
        double valueScale = (value - fromLow) / fromRangeSize;
        return toLow + (valueScale * toRangeSize);
    

    private final Runnable toggleRunnable = new Runnable() 
        @Override
        public void run() 
            if(toggleOn)
                if(currentDelay <= 1)
                    caculateEffect(currentDelay);
                    postDelayed(toggleRunnable,DELAYDURATION);
                    currentDelay = currentDelay + 0.1;
                else
                    currentDelay = 1;
                
            else
                if(currentDelay >= 0)
                    caculateEffect(currentDelay);
                    postDelayed(toggleRunnable, DELAYDURATION);
                    currentDelay = currentDelay - 0.1;
                else
                    currentDelay = 0;
                
            
        
    ;

    /**
     * px2dp
     * @param value
     */
    private int applyDimension(float value)
        return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,value,dm);
    

    /**
     * 类型
     */
    private enum ItemType

        NORMAL, ARROW, TOGGLE;

        public static ItemType getValue(int index)
            for(ItemType type:values())
                if(type.ordinal() == index)
                    return type;
                
            
            return NORMAL;
        
    

    /**
     * 设置开关监听
     */
    public void setOnToggleChangedlistener(OnToggleChangedListener listener)
        this.mListener = listener;
    
    /**
     * 开关状态监听
     */
    public interface OnToggleChangedListener
        /**
         * 是否开启
         * @param on
         */
        void onToggle(boolean on);
    


3.布局就不说了,和正常的View使用就是了。

以上是关于自定义View之MenuItemView的主要内容,如果未能解决你的问题,请参考以下文章

朝花夕拾Android自定义View篇之Android事件分发及传递机制

Android 自定义view之悬浮动画

自定义view之onLayout

View 自定义属性之 LayoutInflater

View 自定义属性之 LayoutInflater

ios开发之 -- xib关联自定义view