神刀安全网

Creating an iOS Style Swipe Button for Android

Even if you’re never touched an iPhone before, you’re probably familiar with the infamous “slide to unlock” button.

Creating an iOS Style Swipe Button for Android

The original purpose behind this button was to prevent a device from getting accidentally unlocked while in a pocket. In the mobile apps you create, there may be a similar use case where you want to give the user the option to confirm a definitive action. The Uber app for drivers has such a button which the driver swipes from left to right to confirm that they want to start a journey.

Usually the solution is to prompt the user with a popup to confirm the action, but this is not an inspired solution. Let’s try creating our own swipe button for Android.

Creating an iOS Style Swipe Button for Android

The final code for the project is on GitHub .

Getting Started

Create a new project in Android Studio with a Blank Activity .

Add a class called SwipeButton that extends the Button class and add the following to it:

import android.content.Context; import android.util.AttributeSet; import android.widget.Button;  public class SwipeButton extends Button {     public SwipeButton(Context context) {         super(context);     }      public SwipeButton(Context context, AttributeSet attrs) {         super(context, attrs);     }      public SwipeButton(Context context, AttributeSet attrs, int defStyleAttr) {         super(context, attrs, defStyleAttr);     }  } 

For the functionality required, you’ll have to play with the onTouchEvent listener of the Button. In the listener you capture when the user presses, swipes across or releases the button. Override the onTouchEvent by adding the following to the SwipeButton class:

@Override public boolean onTouchEvent(MotionEvent event) {    switch (event.getAction()) {       // when user first touches the screen we get x and y coordinate       case MotionEvent.ACTION_DOWN: {           //when user first touches the screen change the button text to desired value           break;       }       case MotionEvent.ACTION_UP: {           //when the user releases touch then revert back the text           break;       }       case MotionEvent.ACTION_MOVE: {           //here we'll capture when the user swipes from left to right and write the logic to create the swiping effect           break;       }   }    return super.onTouchEvent(event); } 

The code above handles three cases which I will cover in more detail:

  1. When the user first touches the button
  2. When the user is swiping the button.
  3. When the user releases the button after either completing the swipe or somewhere in the middle.

1. When User First Touches the Button

You need to do the following:

  1. Get the x and y coordinates of where the user touched the button from the MotionEvent object in the onTouchEvent callback.
  2. Change the text or color of the button.

Here’s the code:

public class SwipeButton extends Button {   private float x1;   //x coordinate of where user first touches the button   private float y1;   //y coordinate of where user first touches the button   private String originalButtonText;   //the text on the button   private boolean confirmThresholdCrossed;   //whether the threshold distance beyond which action is considered confirmed is crossed or not   private boolean swipeTextShown;   //whether the text currently on the button is the text shown while swiping or the original text    ...    @Override   public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {              case MotionEvent.ACTION_DOWN: {                              x1 = event.getX();               y1 = event.getY();               // when user first touches the screen we get x and y coordinate                this.originalButtonText = this.getText().toString();               //save the original text on the button                confirmThresholdCrossed = false;               //action hasn't been confirmed yet                if (!swipeTextShown) {                   this.setText(">> SWIPE TO CONFIRM >>");                   //change the text on the button to indicate that the user is supposed to swipe the button to confirm                   swipeTextShown = true;               }               break;           }           ...       }        return super.onTouchEvent(event);   }   } 

2. When User Is Swiping the Button

The following needs to happen when a user is swiping the button:

  1. Change the text if desired.
  2. Display a swiping effect by manipulating the gradient as the user swipes the button.

LinearGradient is used for displaying the swiping effect with a gradient effect of three colors. As the user swipes, this gradient moves from left to right creating the desired effect.

public class SwipeButton extends Button {    ...   private boolean swiping = false;   private float x2Start;   //whether the text currently on the button is the text shown while swiping or the original text     @Override   public boolean onTouchEvent(MotionEvent event) {     switch (event.getAction()) {       ...       case MotionEvent.ACTION_MOVE: {           //here we'll capture when the user swipes from left to right and write the logic to create the swiping effect            float x2 = event.getX();           float y2 = event.getY();            if(!swiping){               x2Start = event.getX();               //this is to capture at what x swiping started               swiping = true;           }            //if left to right sweep event on screen           if (x1 < x2 && !confirmThresholdCrossed) {               this.setBackgroundDrawable(null);                ShapeDrawable mDrawable = new ShapeDrawable(new RectShape());                int gradientColor1 = 0xFF333333;               int gradientColor2 = 0xFF666666;               int gradientColor2Width = 50;               int gradientColor3 = 0xFF888888;               double actionConfirmDistanceFraction = 0.6;               //We'll get to how to be able to customize these values for each instance of the button                 Shader shader = new LinearGradient(x2, 0, x2 - gradientColor2Width, 0,                       new int[]{gradientColor3, gradientColor2, gradientColor1},                       new float[]{0, 0.5f, 1},                       Shader.TileMode.CLAMP);                mDrawable.getPaint().setShader(shader);               this.setBackgroundDrawable(mDrawable);                 if (swipeTextShown == false) {                   this.setText(">> SWIPE TO CONFIRM >> ");                   //change text while swiping                   swipeTextShown = true;               }                if ((x2-x2Start) > (this.getWidth() * actionConfirmDistanceFraction)) {                   Log.d("CONFIRMATION", "Action Confirmed! Read on to find how to get your desired callback here");                   //confirm action when swiped upto the desired distance                   confirmThresholdCrossed = true;               }           }       }       ... 

3. When User Releases the Button

Now when user releases the button, there will be two possibilities:

  1. The user releases before confirming the action. Meaning before crossing the threshold distance the user needs to swipe for confirming the action.
  2. The user releases after confirming the action, meaning after crossing the threshold distance.

These are both covered in the following snippet:

... case MotionEvent.ACTION_UP: {   //when the user releases touch then revert back the text   swiping = false;   float x2 = event.getX();   int buttonColor = swipeButtonCustomItems.getPostConfirmationColor();   String actionConfirmText = swipeButtonCustomItems.getActionConfirmText() == null ? this.originalButtonText : swipeButtonCustomItems.getActionConfirmText();   //if you choose to not set the confirmation text, it will set to the original button text;    this.setBackgroundDrawable(null);   this.setBackgroundColor(buttonColor);   swipeTextShown =  false;     if ((x2-x2Start) <= (this.getWidth() * swipeButtonCustomItems.getActionConfirmDistanceFraction())) {       Log.d("CONFIRMATION", "Action not confirmed");       this.setText(originalButtonText);       swipeButtonCustomItems.onSwipeCancel();       confirmThresholdCrossed = false;    } else {       Log.d("CONFIRMATION", "Action confirmed");       this.setText(actionConfirmText);   }    break; } ... 

Several attributes, such as gradient colors, have been hard-coded for now. These will be set for each instance of the button, and to be able to set callback functions for when a user performs certain actions with the button.

Set Attributes

The attributes that you can customize for each instance of SwipeButton are:

  • The three gradient colors.
  • The width covered by the second gradient color.
  • Fraction of distance of the width of the Button that the user needs to swipe to confirm the action.
  • The text that appears when the user presses, or is swiping the button.

You can also provide the option to assign callbacks for cases when the user:

  • Presses the button.
  • Swipes the button up to the required distance for confirmation.
  • Releases the button without confirming.

To accept these attributes and callbacks, make another class, and make it abstract.

public abstract class SwipeButtonCustomItems {     //These are the default values if we don't choose to set them later:     public int gradientColor1 = 0xFF333333;     public int gradientColor2 = 0xFF666666;     public int gradientColor2Width = 50;     public int gradientColor3 = 0xFF888888;     public int postConfirmationColor = 0xFF888888;     public double actionConfirmDistanceFraction = 0.7;     public String buttonPressText = ">>   SWIPE TO CONFIRM   >> ";      public String actionConfirmText = null;      public int getGradientColor1() {         return gradientColor1;     }      public SwipeButtonCustomItems setGradientColor1(int gradientColor1) {         this.gradientColor1 = gradientColor1;         return this;     }      public int getGradientColor2() {         return gradientColor2;     }      public SwipeButtonCustomItems setGradientColor2(int gradientColor2) {         this.gradientColor2 = gradientColor2;         return this;     }      public int getGradientColor2Width() {         return gradientColor2Width;     }      public SwipeButtonCustomItems setGradientColor2Width(int gradientColor2Width) {         this.gradientColor2Width = gradientColor2Width;         return this;     }      public int getGradientColor3() {         return gradientColor3;     }      public SwipeButtonCustomItems setGradientColor3(int gradientColor3) {         this.gradientColor3 = gradientColor3;         return this;     }      public double getActionConfirmDistanceFraction() {         return actionConfirmDistanceFraction;     }      public SwipeButtonCustomItems setActionConfirmDistanceFraction(double actionConfirmDistanceFraction) {         this.actionConfirmDistanceFraction = actionConfirmDistanceFraction;         return this;     }      public String getButtonPressText() {         return buttonPressText;     }      public SwipeButtonCustomItems setButtonPressText(String buttonPressText) {         this.buttonPressText = buttonPressText;         return this;     }      public String getActionConfirmText() {         return actionConfirmText;     }      public SwipeButtonCustomItems setActionConfirmText(String actionConfirmText) {         this.actionConfirmText = actionConfirmText;         return this;     }      public int getPostConfirmationColor() {         return postConfirmationColor;     }      public SwipeButtonCustomItems setPostConfirmationColor(int postConfirmationColor) {         this.postConfirmationColor = postConfirmationColor;         return this;     }      //These methods listed below can be overridden in the instance of SwipeButton     public void onButtonPress(){      }      public void onSwipeCancel(){      }      abstract public void onSwipeConfirm(); } 

Now you need a setter in the main SwipeButton class which introduces an instance of this abstract class. Using the setter you can set the desired attributes and callbacks. With all cases covered and attributes and callbacks taken from the abstract class’ instance, here’s how the SwipeButton class now looks:

public class SwipeButton extends Button {      private float x1;     //x coordinate of where user first touches the button     private float y1;     //y coordinate of where user first touches the button     private String originalButtonText;     //the text on the button     private boolean confirmThresholdCrossed;     //whether the threshold distance beyond which action is considered confirmed is crossed or not     private boolean swipeTextShown;     private boolean swiping = false;     private float x2Start;     //whether the text currently on the button is the text shown while swiping or the original text      private SwipeButtonCustomItems swipeButtonCustomItems;     //in this instance of the class SwipeButtonCustomItems we can accept callbacks and other params like colors      public SwipeButton(Context context) {         super(context);     }      public SwipeButton(Context context, AttributeSet attrs) {         super(context, attrs);     }      public SwipeButton(Context context, AttributeSet attrs, int defStyleAttr) {         super(context, attrs, defStyleAttr);     }      public void setSwipeButtonCustomItems(SwipeButtonCustomItems swipeButtonCustomItems) {         //setter for swipeButtonCustomItems         this.swipeButtonCustomItems = swipeButtonCustomItems;     }      @Override     public boolean onTouchEvent(MotionEvent event) {          switch (event.getAction()) {             case MotionEvent.ACTION_DOWN: {                 // when user first touches the screen we get x and y coordinate                 x1 = event.getX();                 y1 = event.getY();                  this.originalButtonText = this.getText().toString();                  confirmThresholdCrossed = false;                  if (!swipeTextShown) {                     this.setText(swipeButtonCustomItems.getButtonPressText());                     swipeTextShown = true;                 }                  swipeButtonCustomItems.onButtonPress();                 break;             }             case MotionEvent.ACTION_MOVE: {                 //here we'll capture when the user swipes from left to right and write the logic to create the swiping effect                  float x2 = event.getX();                 float y2 = event.getY();                  if(!swiping){                     x2Start = event.getX();                     //this is to capture at what x swiping started                     swiping = true;                 }                  //if left to right sweep event on screen                 if (x1 < x2 && !confirmThresholdCrossed) {                     this.setBackgroundDrawable(null);                      ShapeDrawable mDrawable = new ShapeDrawable(new RectShape());                      int gradientColor1 = swipeButtonCustomItems.getGradientColor1();                     int gradientColor2 = swipeButtonCustomItems.getGradientColor2();                     int gradientColor2Width = swipeButtonCustomItems.getGradientColor2Width();                     int gradientColor3 = swipeButtonCustomItems.getGradientColor3();                     double actionConfirmDistanceFraction = swipeButtonCustomItems.getActionConfirmDistanceFraction();                     //Note that above we replaced the hard coded values by those from the SwipeButtonCustomItems instance.                       Shader shader = new LinearGradient(x2, 0, x2 - gradientColor2Width, 0,                             new int[]{gradientColor3, gradientColor2, gradientColor1},                             new float[]{0, 0.5f, 1},                             Shader.TileMode.CLAMP);                      mDrawable.getPaint().setShader(shader);                     this.setBackgroundDrawable(mDrawable);                       if (swipeTextShown == false) {                         this.setText(swipeButtonCustomItems.getButtonPressText());                         //change text while swiping                         swipeTextShown = true;                     }                      if ((x2-x2Start) > (this.getWidth() * actionConfirmDistanceFraction)) {                         Log.d("CONFIRMATION", "Action Confirmed!");                         //Note that below we inserted the desired callback from the SwipeButtonCustomItem instance.                         swipeButtonCustomItems.onSwipeConfirm();                         //confirm action when swiped upto the desired distance                         confirmThresholdCrossed = true;                     }                  }                  break;             }             case MotionEvent.ACTION_UP: {                 //when the user releases touch then revert back the text                 swiping = false;                 float x2 = event.getX();                 int buttonColor = swipeButtonCustomItems.getPostConfirmationColor();                 String actionConfirmText = swipeButtonCustomItems.getActionConfirmText() == null ? this.originalButtonText : swipeButtonCustomItems.getActionConfirmText();                 //if you choose to not set the confirmation text, it will set to the original button text;                  this.setBackgroundDrawable(null);                 this.setBackgroundColor(buttonColor);                 swipeTextShown =  false;                   if ((x2-x2Start) <= (this.getWidth() * swipeButtonCustomItems.getActionConfirmDistanceFraction())) {                     Log.d("CONFIRMATION", "Action not confirmed");                     this.setText(originalButtonText);                     swipeButtonCustomItems.onSwipeCancel();                     confirmThresholdCrossed = false;                  } else {                     Log.d("CONFIRMATION", "Action confirmed");                     this.setText(actionConfirmText);                 }                  break;             }         }           return super.onTouchEvent(event);     } } 

To use the SwipeButton in your activity or fragment, add the corresponding xml element to the layout xml:

<com.package.path.SwipeButton     android:id="@+id/my_swipe_button"     android:layout_width="400dp"     android:layout_height="50dp"     android:text="Button"     android:layout_below="@id/hello_world"     android:background="#888888"     android:textColor="#ffffff"     /> 

To assign callbacks and customize attributes like colors, add the following to your MainActivity :

public class MainActivity extends AppCompatActivity {    @Override   protected void onCreate(Bundle savedInstanceState) {       super.onCreate(savedInstanceState);       setContentView(R.layout.activity_main);       SwipeButton mSwipeButton = (SwipeButton) findViewById(R.id.my_swipe_button);        SwipeButtonCustomItems swipeButtonSettings = new SwipeButtonCustomItems() {           @Override           public void onSwipeConfirm() {               Log.d("NEW_STUFF", "New swipe confirm callback");           }       };        swipeButtonSettings               .setButtonPressText(">> NEW TEXT! >>")               .setGradientColor1(0xFF888888)               .setGradientColor2(0xFF666666)               .setGradientColor2Width(60)               .setGradientColor3(0xFF333333)               .setPostConfirmationColor(0xFF888888)               .setActionConfirmDistanceFraction(0.7)               .setActionConfirmText("Action Confirmed");        if (mSwipeButton != null) {           mSwipeButton.setSwipeButtonCustomItems(swipeButtonSettings);       }   } } 

Use Cases

Using this type of button interaction could be an interesting alternative to the annoying confirmation alert. I would be interested to know what use cases you would have, please add your thoughts in the comments below.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Creating an iOS Style Swipe Button for Android

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址