效果图:
layout布局:
自定义SwitchVerticalSlide:
public class SwitchVerticalSlide extends FrameLayout {
private SwitchSlideListener slideListener;
private Context mContext;
public SwitchVerticalSlide(Context context) {
this(context,null);
}
public SwitchVerticalSlide(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public SwitchVerticalSlide(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext=context;
}
public void addSlideListener(SwitchSlideListener slideListener){
this.slideListener=slideListener;
}
private static final int maxSlideInterval=15;//点击时在垂直方向可抖动的误差
private float downP;
private float trackHeight;
private float trackButtonWidth;
private float trackButtonHeight;
private float downX;
private float downY;
private boolean trackLocation=true;
private boolean antiShakeFlag;//抗抖动,用于处理点击事件
private boolean isFirstDownLoad;
private View child0;
private View child1;
private float orbitalTransferLength;//滑动时改变按钮状态的滑动距离
private boolean onFinishInflateFlag;
private int onFinishInflateState;//1:打开状态,2:关闭状态
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!isFirstDownLoad){
trackHeight=getChildAt(0).getMeasuredHeight();
trackButtonWidth=getChildAt(1).getMeasuredWidth();
trackButtonHeight=getChildAt(1).getMeasuredHeight();
child0=getChildAt(0);
child1=getChildAt(1);
isFirstDownLoad=true;
orbitalTransferLength=trackHeight/5.0f;
}
}
public void onResumeFinishInflate() {
if (onFinishInflateFlag){
switch (onFinishInflateState) {
case 1:
openSwitch();
onFinishInflateState=0;
break;
case 2:
closeSwitch();
onFinishInflateState=0;
break;
}
onFinishInflateFlag=false;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
antiShakeFlag=false;
downP=event.getRawY();
downX=event.getX();
downY=event.getY();
break;
case MotionEvent.ACTION_MOVE:
if (trackLocation){
float dValue = event.getRawY() - downP;
if(isInTrackButton(downX,downY, true)){
if (dValue<0){
if(-dValue>orbitalTransferLength){
((ImageView) child1).setImageResource(R.mipmap.track_button_open);
((ImageView) child0).setImageResource(R.mipmap.track_on);
}else {
((ImageView) child1).setImageResource(R.mipmap.track_button_close);
((ImageView) child0).setImageResource(R.mipmap.track_off);
}
//抗抖动
if (antiShakeFlag|dValue<-maxSlideInterval){
//在按下点之向上滑动
antiShakeFlag=true;
float maxValue = trackButtonHeight - trackHeight;
if (dValue> maxValue){
child1.setTranslationY(dValue);
}else {
child1.setTranslationY(maxValue);
}
}
}else {
if (dValue>maxSlideInterval){
antiShakeFlag=true;
}
child1.setTranslationY(0);
}
}else{
//如果在这个区域内,垂直方向超过了10,则需要改变 antiShakeFlag 取消点击
if (Math.abs(dValue)>maxSlideInterval){
antiShakeFlag=true;
}
}
}else {
float dValue = event.getRawY() - downP;
if (isInTrackButton(downX,downY,false)){
if (dValue>0){
if(dValue>orbitalTransferLength){
((ImageView) child1).setImageResource(R.mipmap.track_button_close);
((ImageView) child0).setImageResource(R.mipmap.track_off);
}else {
((ImageView) child1).setImageResource(R.mipmap.track_button_open);
((ImageView) child0).setImageResource(R.mipmap.track_on);
}
if (antiShakeFlag|dValue>maxSlideInterval){
//在按下点之下滑动
antiShakeFlag=true;
float maxValue = trackButtonHeight - trackHeight + dValue;
if (maxValue<0){
child1.setTranslationY(maxValue);
}else {
child1.setTranslationY(0);
}
}
}else {
if (dValue<-maxSlideInterval){
antiShakeFlag=true;
}
child1.setTranslationY(trackButtonHeight-trackHeight);
}
}else {
if (Math.abs(dValue)>maxSlideInterval){
antiShakeFlag=true;
}
}
}
break;
case MotionEvent.ACTION_UP:
if (!antiShakeFlag){
//第一次按下滑动距离不超过20,视为点击
if (trackLocation){
((ImageView) child1).setImageResource(R.mipmap.track_button_open);
((ImageView) child0).setImageResource(R.mipmap.track_on);
getChildAt(1).setTranslationY(trackButtonHeight-trackHeight);
trackLocation=false;
slideListener.onSwitchSlide(true);
}else {
((ImageView) child1).setImageResource(R.mipmap.track_button_close);
((ImageView) child0).setImageResource(R.mipmap.track_off);
child1.setTranslationY(0);
trackLocation=true;
slideListener.onSwitchSlide(false);
}
}else {
if (trackLocation){
if(isInTrackButton(downX,downY, true)){
if((downP-event.getRawY())>orbitalTransferLength){
//打开开关
trackLocation=false;
child1.setTranslationY(trackButtonHeight-trackHeight);
slideListener.onSwitchSlide(true);
}else {
child1.setTranslationY(0);
}
}
}else{
if(isInTrackButton(downX,downY, false)){
if((event.getRawY()-downP)>orbitalTransferLength){
//关闭开关
trackLocation=true;
child1.setTranslationY(0);
slideListener.onSwitchSlide(false);
}else {
child1.setTranslationY(trackButtonHeight-trackHeight);
}
}
}
}
break;
}
return true;
}
public void openSwitch(){
if (child0!=null&&child1!=null) {
((ImageView) child1).setImageResource(R.mipmap.track_button_open);
((ImageView) child0).setImageResource(R.mipmap.track_on);
child1.setTranslationY(trackButtonHeight-trackHeight);
trackLocation=false;
}else {
onFinishInflateFlag=true;//完成加载后改变状态
onFinishInflateState=1;
}
}
public void closeSwitch(){
if (child0!=null&&child1!=null) {
((ImageView) child1).setImageResource(R.mipmap.track_button_close);
((ImageView) child0).setImageResource(R.mipmap.track_off);
child1.setTranslationY(0);
trackLocation=true;
}else {
onFinishInflateFlag=true;//完成加载后改变状态
onFinishInflateState=2;
}
}
/**
*
* @param downX
* @param downY
* @param down true表示按钮在下面,false表示按钮在上面
* @return true 在矩形内,false 不在矩形内
*/
private boolean isInTrackButton(float downX,float downY,boolean down){
float leftUpX=0.0f;
float rightDownX=trackButtonWidth;
float leftUpY;
float rightDownY;
if (down){
leftUpY=trackHeight-trackButtonHeight;
rightDownY=trackHeight;
}else {
leftUpY=0;
rightDownY=trackButtonHeight;
}
return downY >= leftUpY && downY <= rightDownY && downX >= leftUpX && downX <= rightDownX;
}
}
public interface SwitchSlideListener {
/**
*
* @param switchFlag true表示按钮打开,false表示按钮关闭
*/
void onSwitchSlide(boolean switchFlag);
}
onCreate处理回调结果(相当于用法):
((SwitchVerticalSlide) findViewById(R.id.control)).addSlideListener(new SwitchSlideListener() {
@Override
public void onSwitchSlide(boolean switchFlag) {
if (switchFlag){
Toast.makeText(MainActivity.this, "打开", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity.this, "关闭", Toast.LENGTH_SHORT).show();
}
}
});