转载请注明出处:http://blog.csdn.net/forwardyzk/article/details/42526343
当开发的时候,使用开关的时候,效果不能不满足我们的需求,要表现出滑动的效果。我们就可以自定义开关。
思路:
1.把开关分为两部分,一部分是开关的背景,另一部分是滑动按钮。
2.测量开关的长和宽,当然是在onMeasure中进行处理
3.在onTouchEvent()根据触摸开关进行滑动位置进行监听,在onDraw()中进行绘画。
当然也要绘画两部分:开关背景和滑动按钮
4.对触摸位置和滑动位置进行判断
1.触摸位置要在开关背景的范围内。
2.在绘画的时候,滑动按钮不能超出开关背景的范围。
在onTouchEvent()方法中调用invalidate()方法,会根据位置的变化不断的在onDraw()方法中绘画按钮。
设置开关的背景和滑动按钮
onXPosition和offXPosition为开关状态的变化之间,滑动按钮左侧的X坐标不能必须在两者之间。
public void setImageResource(int switchOnBg, int slipBtn) { Log.d(TAG, "setImageResource"); switch_bg = BitmapFactory.decodeResource(getResources(), switchOnBg); slip_Btn = BitmapFactory.decodeResource(getResources(), slipBtn); onXPosition = switch_bg.getWidth() - slip_Btn.getWidth(); offXPosition = 0; }
在OnTouchEvent()中监听手势滑动的位置
public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { // 按下,判断按下的位置在开关上,才可以做后面的操作 case MotionEvent.ACTION_DOWN: Log.d(TAG, "MotionEvent.ACTION_DOWN"); if (event.getX() > switch_bg.getWidth() || event.getY() > switch_bg.getHeight()) { return false; } isSlipping = true; currentX = event.getX(); break; // 滑动,记录当前的按下的位置 case MotionEvent.ACTION_MOVE: Log.d(TAG, "MotionEvent.ACTION_MOVE"); currentX = event.getX(); break; // 松开,设置开关的监听器,设置开关的状态 case MotionEvent.ACTION_UP: Log.d(TAG, "MotionEvent.ACTION_UP"); isSlipping = false; // 松开前开关的状态 boolean previousSwitchState = isSwitchOn; // 如果当前的位置在开关背景中间位置的右侧,表示的是开的状态,否则为关 if (event.getX() >= (switch_bg.getWidth() / 2)) { isSwitchOn = true; } else { isSwitchOn = false; } // 如果设置了监听器,则调用此方法 if (onSwitchListener != null && (previousSwitchState != isSwitchOn)) { onSwitchListener.onSwitched(isSwitchOn); } break; default: break; } // 重新绘制控件 invalidate();// 不要忘了重绘开关 return true; }
在最后不要忘了调用invalidate(),否则不会进行绘画开关。
判断了触摸的范围必须在开关上
在onDraw()绘画开关
protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); Log.d(TAG, "onDraw"); Matrix matrix = new Matrix(); Paint paint = new Paint(); // 滑动按钮的X方向左侧坐标 float left_SlipBtn; // 把开关的背景画出来 canvas.drawBitmap(switch_bg, matrix, paint); // 判断当前是否正在滑动 if (isSlipping) { if (currentX > switch_bg.getWidth()) { left_SlipBtn = switch_bg.getWidth() - slip_Btn.getWidth(); } else { // 保持滑动的位置是滑动按钮的中间位置 left_SlipBtn = currentX - slip_Btn.getWidth() / 2; } } else { // 根据当前的开关状态设置滑动按钮的位置 if (isSwitchOn) { left_SlipBtn = onXPosition; } else { left_SlipBtn = offXPosition; } } // 对滑动按钮左侧和右侧进行判断,不能超过背景的范围 if (left_SlipBtn < 0) { left_SlipBtn = 0; } else if (left_SlipBtn > switch_bg.getWidth() - slip_Btn.getWidth()) { left_SlipBtn = switch_bg.getWidth() - slip_Btn.getWidth(); } // 绘制滑动开关 canvas.drawBitmap(slip_Btn, left_SlipBtn, 0, paint); }
canvas.drawBitmap(switch_bg, matrix, paint)绘画开关背景
canvas.drawBitmap(slip_Btn, left_SlipBtn, 0, paint)绘画滑动按钮
滑动按钮滑动的时,保持不能超过开关背景的范围,保持点击的位置在滑动按钮的中间位置。
使用步骤:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/main_button_switch" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:layout_marginLeft="15dp" android:paddingBottom="3dp" android:paddingLeft="25dp" android:paddingRight="25dp" android:paddingTop="3dp" android:text="切换状态" android:textSize="15sp" /> <com.example.view.MySlipSwitch android:id="@+id/main_myslipswitch" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="20dp" /> </RelativeLayout>
在MainActivity.java中使用
public class MainActivity extends Activity { private Button switch_Btn; private MySlipSwitch slipswitch_MSL; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); setListener(); } public void initView() { slipswitch_MSL = (MySlipSwitch) findViewById(R.id.main_myslipswitch); slipswitch_MSL.setImageResource(R.drawable.switch_bkg_switch, R.drawable.switch_btn_slip); slipswitch_MSL.setSwitchState(true); switch_Btn = (Button) findViewById(R.id.main_button_switch); } public void setListener() { //设置开关状态变化监听器 slipswitch_MSL.setOnSwitchListener(new OnSwitchListener() { @Override public void onSwitched(boolean isSwitchOn) { // TODO Auto-generated method stub if (isSwitchOn) { Toast.makeText(getApplicationContext(), "开关已经开启", 0).show(); } else { Toast.makeText(getApplicationContext(), "开关已经关闭", 0).show(); } } }); switch_Btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { slipswitch_MSL.setSwitchState(!slipswitch_MSL.getSwitchState()); if (slipswitch_MSL.getSwitchState()) { Toast.makeText(getApplicationContext(), "开关已经开启", 0).show(); } else { Toast.makeText(getApplicationContext(), "开关已经关闭", 0).show(); } } }); } }
点击切换按钮,获取开关的状态
设置滑动开关状态的的监听器,滑动的位置影响到了开关的状态,有响应的监听。
源码下载: http://download.csdn.net/detail/forwardyzk/8341363
效果图: