很久又没来看看了。。。。。。。。

-----------------------------------------------------------------------------------------------------------------------------------

Switch是Android的一个开关控件,相当于IPhone的UISwitch效果,但是该控件是4.0以后才有得,故而有些项目需要的时候不得不自己去实现该控件功能,网上主要流行的方法是继承View等控件自己在onDraw()里面绘制控件,但是不是效果不太理想就是体验性太差,另外也有修改官方Switch控件的,综合网上资料,觉得修改官方Switch控件比较靠谱,比较体验性方面性能方面都有保证,API接口大都是一致的,本人选择这种方式。


修改Switch的主要思想是:1. Switch中含有高版本SDK代码,需要去掉或者改写这样的代码 2. Switch对应declare-styleable属性声明应该在Android SDK安装目录中找到对应的源码声明片段,基本上copy过来就行了。所在路径:\Android\android-sdk\platforms\android-17\data\res


修改后的MySwitch控件接口基本与原Switch控件一致,并且除了可支持所有SDK外,增加了2项小功能:

1. 支持用Track背景图片的方式代替Texton Textoff等文字方式表现开关状态

2.支持调整控制Switch的高度


下面贴出Switch修改的关键代码:


------------------本博客如未明正声明转载,皆为原创,转载请注明出处!------------------

/**
 * <p> 
 * modified from android SDK 14(4.0) android.widget.Switch.
 * <br/>
 * <strong>new feature: </strong>
 * <ol>
 * <li>support SDK 1 or higher. </li>
 * <li>you can use track drawable instead of text to display the changes of off-on state!</li>
 * <li>you can control the Switch minimum height. </li>
 * </ol>
 * </p>
 *	
 *	@see {@link Switch}
 *	@author Wison
 */
public class MySwitch extends CompoundButton {
    // Support track drawable instead of text
    private Drawable mTrackOnDrawable;
    private Drawable mTrackOffDrawable;
    
    // Support minimum height
    private int mSwitchMinHeight;

    /**
     * Construct a new Switch with a default style determined by the given theme attribute,
     * overriding specific style attributes as requested.
     *
     * @param context The Context that will determine this widget's theming.
     * @param attrs Specification of attributes that should deviate from the default styling.
     * @param defStyle An attribute ID within the active theme containing a reference to the
     *                 default style for this widget. e.g. android.R.attr.switchStyle.
     */
    public MySwitch(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        Resources res = getResources();
        mTextPaint.density = res.getDisplayMetrics().density;
        //float scaledDensity = res.getDisplayMetrics().scaledDensity;
        //mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Switch, defStyle, 0);

        // off-on 模式: 图片模式或文字模式,图片模式是用Track背景图片表示off-on的状态,文字模式是用文字来表示off-on状态。
        mTrackOnDrawable = a.getDrawable(R.styleable.Switch_trackOn);
        mTrackOffDrawable = a.getDrawable(R.styleable.Switch_trackOff);
        if (checkTrackOffOnDrawable()) {
        	// 如果设定图片模式,则默认显示off状态
        	mTrackDrawable = mTrackOffDrawable;
		} else {
			mTrackDrawable = a.getDrawable(R.styleable.Switch_track);
		}
        
        mThumbDrawable = a.getDrawable(R.styleable.Switch_thumb);
        mTextOn = a.getText(R.styleable.Switch_textOn);
        mTextOff = a.getText(R.styleable.Switch_textOff);
        mThumbTextPadding = a.getDimensionPixelSize(R.styleable.Switch_thumbTextPadding, 0);
        mSwitchMinWidth = a.getDimensionPixelSize(R.styleable.Switch_switchMinWidth, 0);
        
        mSwitchMinHeight = a.getDimensionPixelSize(R.styleable.Switch_switchMinHeight, 0);
        
        mSwitchPadding = a.getDimensionPixelSize(R.styleable.Switch_switchPadding, 0);

        int appearance = a.getResourceId(R.styleable.Switch_switchTextAppearance, 0);
        if (appearance != 0) {
            setSwitchTextAppearance(context, appearance);
        }
        a.recycle();

        ViewConfiguration config = ViewConfiguration.get(context);
        mTouchSlop = config.getScaledTouchSlop();
        mMinFlingVelocity = config.getScaledMinimumFlingVelocity();

        // Refresh display with current params
        refreshDrawableState();
        setChecked(isChecked());
    }

    private boolean checkTrackOffOnDrawable() {
    	return mTrackOnDrawable != null && mTrackOffDrawable != null;
    }

	@SuppressLint("NewApi")
	@Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mOnLayout == null) {
            mOnLayout = makeLayout(mTextOn);
        }
        if (mOffLayout == null) {
            mOffLayout = makeLayout(mTextOff);
        }
        mTrackDrawable.getPadding(mTempRect);
        final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth());
        final int switchWidth = Math.max(mSwitchMinWidth,
                maxTextWidth * 2 + mThumbTextPadding * 4 + mTempRect.left + mTempRect.right);
        
//        final int switchHeight = mTrackDrawable.getIntrinsicHeight();
        int switchHeight;
        if (mSwitchMinHeight <= 0) {
        	switchHeight = mTrackDrawable.getIntrinsicHeight();
		} else {
			switchHeight = Math.max(mSwitchMinHeight, mTempRect.top + mTempRect.bottom);
		}
        
        mThumbWidth = maxTextWidth + mThumbTextPadding * 2;

        mSwitchWidth = switchWidth;
        mSwitchHeight = switchHeight;

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int measuredHeight = getMeasuredHeight();
        if (measuredHeight < switchHeight) {
            if (Build.VERSION.SDK_INT >= 11) {
            	setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
			} else {
				setMeasuredDimension(getMeasuredWidth(), switchHeight);
			}
        }
    }

    @Override
    public void setChecked(boolean checked) {
    	if (checkTrackOffOnDrawable()) {
    		mTrackDrawable = checked ? mTrackOnDrawable : mTrackOffDrawable;
    		refreshDrawableState();
		}
        super.setChecked(checked);
        mThumbPosition = checked ? getThumbScrollRange() : 0;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // Draw the switch
        int switchLeft = mSwitchLeft;
        int switchTop = mSwitchTop;
        int switchRight = mSwitchRight;
        int switchBottom = mSwitchBottom;
        
        if (checkTrackOffOnDrawable()) {
        	mTrackDrawable = getTargetCheckedState() ? mTrackOnDrawable : mTrackOffDrawable;
        	refreshDrawableState();
        }
        
        mTrackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);
        mTrackDrawable.draw(canvas);

        canvas.save();
        
        mTrackDrawable.getPadding(mTempRect);
        int switchInnerLeft = switchLeft + mTempRect.left;
        int switchInnerTop = switchTop + mTempRect.top;
        int switchInnerRight = switchRight - mTempRect.right;
        int switchInnerBottom = switchBottom - mTempRect.bottom;
        canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);

        mThumbDrawable.getPadding(mTempRect);
        final int thumbPos = (int) (mThumbPosition + 0.5f);
        int thumbLeft = switchInnerLeft - mTempRect.left + thumbPos;
        int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + mTempRect.right;

        mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
        mThumbDrawable.draw(canvas);

        // mTextColors should not be null, but just in case
        if (mTextColors != null) {
            mTextPaint.setColor(mTextColors.getColorForState(getDrawableState(),
                    mTextColors.getDefaultColor()));
        }
        mTextPaint.drawableState = getDrawableState();

        Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;

        if (switchText != null) {
	        canvas.translate((thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2,
	                (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2);
	        switchText.draw(canvas);
        }
        canvas.restore();
    }
}



下面是关键属性声明:

    <declare-styleable name="Switch">
        
        <!-- Drawable to use when the switch is in the checked/"on" state. -->
        <attr name="trackOn" format="reference" />
        <!-- Drawable to use when the switch is in the unchecked/"off" state. -->
        <attr name="trackOff" format="reference" />
        <!-- Minimum height for the switch component -->
        <attr name="switchMinHeight" format="dimension" />
        
        <!-- Drawable to use as the "thumb" that switches back and forth. -->
        <attr name="thumb" format="reference" />
        <!-- Drawable to use as the "track" that the switch thumb slides within. -->
        <attr name="track" format="reference" />
        <!-- Text to use when the switch is in the checked/"on" state. -->
        <attr name="textOn" format="string" />
        <!-- Text to use when the switch is in the unchecked/"off" state. -->
        <attr name="textOff" format="string" />
        <!-- Amount of padding on either side of text within the switch thumb. -->
        <attr name="thumbTextPadding" format="dimension" />
        <!-- TextAppearance style for text displayed on the switch thumb. -->
        <attr name="switchTextAppearance" format="reference" />
        <!-- Minimum width for the switch component -->
        <attr name="switchMinWidth" format="dimension" />
        <!-- Minimum space between the switch and caption text -->
        <attr name="switchPadding" format="dimension" />
    </declare-styleable>


以下是效果图:




Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐