Android Switch Button Drag off 点击/拖动

标签 android uibutton uiswitch

我有一些关于 Android 切换按钮和创建一些自定义行为的具体问题。所以...我需要的是只允许开关在从 OFF 位置转换到 ON 位置时可拖动。我能够得到它,这样如果我在关闭位置单击开关,它就不会转换。但是,我不想将开关从关闭位置拨到打开位置。我希望用户不得不不断地拖动它。现在您可能认为搜索栏就是我要找的东西。也许吧,但我需要拇指部分的文本过渡在进行切换时从关闭变为打开。在使用搜索栏时,这看起来并不是一个真正的选择。此外,如果用户在打开位置时单击拇指,它可以转换到关闭位置。此外,没有介于两者之间。如果用户从关闭到打开(仅拖动),他们必须一直走到最后。任何帮助表示赞赏。我的基本代码如下:

public class MainActivity extends Activity {

    private TextView switchStatus;


private Switch mySwitch;

 private Handler handler = new Handler();

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  switchStatus = (TextView) findViewById(R.id.switchStatus);
  mySwitch = (Switch) findViewById(R.id.mySwitch);

  //set the switch to ON 
  mySwitch.setChecked(true);
  //attach a listener to check for changes in state
  mySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {

   @Override
   public void onCheckedChanged(CompoundButton buttonView,
     boolean isChecked) {

    if(isChecked){
     switchStatus.setText("Switch is currently ON");
    }else{
     switchStatus.setText("Switch is currently OFF");
    }

   }
  });

  mySwitch.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        if(mySwitch.isChecked()) {
            mySwitch.setChecked(false);
        }
    }   
  }); 

  //check the current state before we display the screen
  if(mySwitch.isChecked()){
   switchStatus.setText("Switch is currently ON");
  }
  else {
   switchStatus.setText("Switch is currently OFF");
  }
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.activity_main, menu);
  return true;
 }

}

最佳答案

好吧,我想出了一个不是最优雅的解决方案,但我的作品。我扩展了开关控件并为想要对某些拖动事件起作用的对象创建了一个界面。请看下面。

public class CustomSwitch extends Switch {

   private static final String TAG = CustomSwitch.class.getSimpleName();

   private Method getThumbScrollRange;

   private int thumbScrollRange;
   private float thumbPosition;

   private boolean isMiddleOn = false;
   private boolean isMiddleOff = true;
   private boolean isOnMax = false;
   private boolean isOffMin = true;
   private boolean isMoving = false;

   private final int PIVOT_PERCENT = 50;
   private final int OFF_PERCENT_TOLERANCE = 10;
   private final int ON_PERCENT_TOLERANCE = 10;
   private final int ON_MAX_PERCENT = 100;
   private final int OFF_MIN_PERCENT = 0;

   private onDraggableSwitchListener onDraggableSwitchListener;

   public CustomSwitch(Context context) {
      this(context, null);
   }

   public CustomSwitch(Context context, AttributeSet attrs) {
      this(context, attrs, 0);
   }

   public CustomSwitch(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs);

      this.setOnTouchListener(new OnTouchListener() {
         // set via variable since the switch will trigger a move
         // action on toggle, but the on draw event will trigger
         @Override
         public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_MOVE) {
               isMoving = true;
            }
            else {
               isMoving = false;
            }
            if (onDraggableSwitchListener != null) {
               onDraggableSwitchListener.onTouchEvent(v, event);
            }
            return false;
         }
      });

      this.setOnCheckedChangeListener(new OnCheckedChangeListener() {
         @Override
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            isOnMax = isMiddleOn = isChecked;
            isOffMin = isMiddleOff = !isChecked;

            if (onDraggableSwitchListener != null) {
               onDraggableSwitchListener.onCheckedChanged(buttonView, isChecked);
            }
         }
      });

      try {
         getThumbScrollRange = Switch.class.getDeclaredMethod("getThumbScrollRange");
         getThumbScrollRange.setAccessible(true);
      }
      catch (NoSuchMethodException e) {
         Log.e(TAG, "Error", e);
      }
   }

   /**
    * Registers the {@link on}
    * */
   public void setOnDraggableSwitchListener(onDraggableSwitchListener listener) {
      onDraggableSwitchListener = listener;
   }

   @Override
   public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      try {
         thumbScrollRange = (Integer) getThumbScrollRange.invoke(this);
      }
      catch (Exception e) {
         Log.e(TAG, "", e);
      }
   }

   @Override
   protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);
      try {
         thumbPosition = getField("mThumbPosition").getFloat(this);
         int percentage = (thumbScrollRange == 0 ? 0 : ((int) ((thumbPosition / thumbScrollRange) * 100)));

         Log.v(TAG, "Percentage: " + percentage);

         if ((percentage > PIVOT_PERCENT) && !isMiddleOn && isMoving) {
            if (onDraggableSwitchListener != null) onDraggableSwitchListener.onDraggableSwitchOnMiddle(percentage);
            isMiddleOn = true;
            isOffMin = isMiddleOff = false;
            Log.v(TAG, "MIDDLE ON TRUE");
         }
         else if ((percentage < PIVOT_PERCENT) && !isMiddleOff && isMoving) {
            if (onDraggableSwitchListener != null) onDraggableSwitchListener.onDraggableSwitchOffMiddle(percentage);
            isMiddleOff = true;
            isOnMax = isMiddleOn = false;
            Log.v(TAG, "MIDDLE OFF TRUE");
         }

         if ((percentage <= (OFF_MIN_PERCENT + OFF_PERCENT_TOLERANCE)) && !isOffMin && isMoving) {
            if (onDraggableSwitchListener != null) onDraggableSwitchListener.onDraggableSwitchOffMin();
            isOffMin = true;
            Log.v(TAG, "OFF MIN TRUE");
         }
         else if ((percentage >= (ON_MAX_PERCENT - ON_PERCENT_TOLERANCE)) && !isOnMax && isMoving) {
            if (onDraggableSwitchListener != null) onDraggableSwitchListener.onDraggableSwitchOnMax();
            isOnMax = true;
            Log.v(TAG, "ON MAX TRUE");
         }
      }
      catch (IllegalArgumentException e) {
         Log.e(TAG, "", e);
      }
      catch (IllegalAccessException e) {
         Log.e(TAG, "", e);
      }
   }

   /** Cache of private fields from superclass */
   private Map<String, Field> fieldCache = new HashMap<String, Field>();

   private Field getField(String name) {

      try {
         if (!fieldCache.containsKey(name)) {
            Field f = Switch.class.getDeclaredField(name);
            f.setAccessible(true);
            fieldCache.put(name, f);
         }
         return fieldCache.get(name);
      }
      catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   public static interface onDraggableSwitchListener {

      public void onDraggableSwitchOnMax();

      public void onDraggableSwitchOffMin();

      public void onDraggableSwitchOnMiddle(int percentage);

      public void onDraggableSwitchOffMiddle(int percentage);

      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked);

      public void onTouchEvent(View v, MotionEvent event);
   }
}

您现在所要做的就是在您的布局中使用此开关,然后在您的主类中您可以设置适当的监听器。希望这对某人有所帮助(即使它非常具体)。

关于Android Switch Button Drag off 点击/拖动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26589568/

相关文章:

android-jetpack-compose - Jetpack compose Switch() Track Width、Track StrokeWidth、Thumb Diameter

android - View.resolveSizeAndState() 的第三个参数有什么用?

android - Android 上设置的默认字体

android - 使用 Apache Flex SDK4.8.0、AIR3.4 和 FDT5.6.2 编译生成 "unable to open ' {airHome}/frameworks/libs/air/airglobal.swc'"

ios - 自定义栏按钮项目无法正确检测触摸

ios - 为什么发送addTarget方法具有:才能工作

android - 我如何创建一年中所有月份的 View 或布局,如 CalendarView?

swift - 如何在同一 IBAction 中取消选择(取消突出显示)按钮

ios - 如何从 Swift 中另一个 ViewController 上的开关发送 slider 的新最大/最小值?

ios - 选择单元格时,UITableViewCell 中的 UISwitch 会卡住应用程序,不会在 UISwitch 切换时卡住