【问题标题】:Android Switch Button Drag off Click/Drag OnAndroid 开关按钮 拖动关闭单击/拖动打开
【发布时间】:2014-12-22 18:00:05
【问题描述】:

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

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;
 }

}

【问题讨论】:

  • 我会使用搜索栏,但我需要它看起来与切换按钮完全一样

标签: android uibutton uiswitch


【解决方案1】:

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

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);
   }
}

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

【讨论】:

  • 我正在使用您的自定义类,不幸的是在我的情况下切换响应点击并更改它的检查状态。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多