A world without buttons!
- Position aware views
- Beginner Level Java
- Android: Views and Layouts
- Android: Basic Layout XML design
Buttons are the dominant mechanism that apps use to trigger some behavior. Sure, it works...but I find that buttons on mobile interfaces pretty annoying to use. I believe that app should be as much as possible gesture driven. In this tutorial I trim away the hold and change buttons away from the interface.
Currently, the five buttons are add, remove, roll, change, and hold. Now that the dice graphic is touch draggable, I propose using gestures to hold dice and change dice. Specifically, i'm going to create zones in the interface that will hold the dice and switch the dice to some value.
- Butterknife refactor
- Position Listener
- State Change
In the previous tutorial, I reorganized the code to have a bit of structure.
In part 4, I introduced Presenter-View modules where all UI events call
the Presenter
object and the presenter instructs UI behavior based. By
removing 2 buttons and introducing zones, the UI events change from
- click add Button
- click remove Button
- click roll Button
click change Buttonclick hold buttonrelease dicetouch background layout
into
- click add Button
- click remove Button
- click roll Button
- dice in hold/roll/switch zone
On the View
side we change from
- updateDiceCount
- spinDice
refreshDiceLayouthighlightDiceunhighlightAllDicedisableChangeButtonenableChangeButtondisableHoldButtonenableHoldButton
into
- updateDiceCount
- spinDice
- redrawDice
The removal of buttons simplified the interface between the two layers by about a half.
To implement these changes, I modify my touch listener to inspect the position of dice to see what zone it is in.
....
@Override
public boolean onTouch(View view, MotionEvent event) {
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN :
{
parms = (RelativeLayout.LayoutParams) view.getLayoutParams();
dx = event.getRawX() - parms.leftMargin;
dy = event.getRawY() - parms.topMargin;
}
break;
case MotionEvent.ACTION_MOVE :
{
x = event.getRawX();
y = event.getRawY();
parms.leftMargin = boundifyX(x-dx);
parms.topMargin = boundifyY(y-dy);
if(inHoldZone(parms)) {
presenter.diceInZone(index, Zone.HOLD);
if(diceInLeftFlipZone(parms)) {
presenter.diceInZone(index, Zone.SWITCH_BLANK);
} else if(diceInRightFlipZone(parms)) {
presenter.diceInZone(index, Zone.SWITCH_MAGNIFY);
} else if(diceInCenterFlipZone(parms)) {
presenter.diceInZone(index, Zone.SWITCH_STAR);
}
} else {
presenter.diceInZone(index, Zone.ROLL);
}
view.setLayoutParams(parms);
}
break;
}
return true;
}
....
The presenter will set the new state for the dice and notify the View layer to redraw all dice.
public void diceInZone(int index, Zone type) {
Dice dice = diceList.get(index);
switch(type) {
case HOLD:
dice.setHold(true);
break;
case ROLL:
dice.setHold(false);
break;
case SWITCH_MAGNIFY:
dice.diceVal = Dice.Face.MAGNIFY;
break;
case SWITCH_BLANK:
dice.diceVal = Dice.Face.BLANK;
break;
case SWITCH_STAR:
dice.diceVal = Dice.Face.STAR;
break;
}
mainView.redrawDice(diceList);
updateDiceCount();
}
The method boundifyX()
is a convenient method I wrote that ensures that
when the user drags the dice around the screen, the dice remains in bounds.