In some mobile games, the player can control the actions of the game character through a virtual console. There are also applications for this type of dial in drone and toy control apps.
Use custom View way to achieve similar handle control.
The code can be found at github.com/RustFisher/…
JoystickView features
JoystickView currently has the following features
- Two kinds of style
- Fixed control panel;
- Floating follow mode; The dial moves to where your finger first clicks
- You can add an “arrow” on the background to add an effect image
- Custom “touch ball” picture and background picture
- The finger moves out of the range of the control panel and remains following
- Can get the percentage parameter of the moving position
Implementation approach
Use custom View to implement the control disk. Create the TouchView.
The basic requirement of the control panel is to follow the finger to react. To get the coordinates of the finger touch screen, we use the View’s onTouchEvent method.
The “touch ball” and background in the control are derived from the image. In the custom view first get the corresponding bitmap, scale to the specified size.
The corresponding coordinates are obtained in onTouchEvent to calculate the position of the image; OnDraw draws according to coordinates. Calculate the distance between the finger position and the center of the control disk, and transmit the information through the listener.
Code sample
Set the style
There are fixed and floating styles, which may be added in the future
public enum PadStyle {
FLOATING /* Reposition with the user finger */,
FIXED /* Fixed position */
}
Copy the code
Control panel Configuration
Instead of directly manipulating the TouchView, we can create the TouchViewModel to store the configuration.
private int bgResId; // Background image resource ID
private int touchBmpResId; // Touch graph resource ID - for example, a sphere
private int directionPicResId; // Indicates the image ID of the current touch point relative to the center of the circle
private float mWholeViewWid; // The width of the entire View
private float mWholeViewHeight; // The height of the View
private float mWholePadWid; // The width of the disk, including the arrow; It's not the total width of the View
private float mWholePadHeight; // The height of the disk, including the arrow; It's not the total width of the View
private int mRoundBgRadius; // Background circle radius background circle position can vary
private int mTouchBallRadius = 100; // Touch the radius of the ball
private int mRoundBgPadding; // The px from the background circle to the Pad boundary is usually reserved for the direction arrow
private boolean showDirectionPic = false; // Whether to display the indicator picture
private PadStyle mPadStyle = PadStyle.FIXED; // The default is fixed position
private PadLocationType mPadLocationType = PadLocationType.LEFT_BOT;
/ /...
Copy the code
Control disk manager
The controller disk has many configuration items. A DefaultController is abstracted to manage the controller disk. This controller is not necessary. The manager needs to control the parent View of the disk, using a RelativeLayout.
Create a Left drive. Pass in the size configuration. And then we add it to containerView.
private void createLeftControlTouchView(a) {
TouchViewModel model = new TouchViewModel(
R.drawable.ui_pic_joystick_left_pad,
R.drawable.ui_pic_joystick_control_ball);
model.setWholeViewSize(ctx.getResources().getDimensionPixelSize(R.dimen.ui_joystick_whole_field_wid),
ctx.getResources().getDimensionPixelSize(R.dimen.ui_joystick_whole_field_height));
model.setPadSize(ctx.getResources().getDimensionPixelSize(R.dimen.ui_joystick_pad_size),
ctx.getResources().getDimensionPixelSize(R.dimen.ui_joystick_pad_size));
int roundBgRadius = ctx.getResources().getDimensionPixelSize(R.dimen.ui_joystick_round_bg_radius);
model.setContentSize(roundBgRadius, (int) (roundBgRadius / 3.5));
model.setStyle(padStyle, PadLocationType.LEFT_BOT);
model.setRoundBgPadding(ctx.getResources().getDimensionPixelSize(R.dimen.ui_joystick_circle_bg_padding));
leftControlTouchView = new TouchView(ctx);
leftControlTouchView.init(model);
// View total size
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
ctx.getResources().getDimensionPixelSize(R.dimen.ui_joystick_whole_field_wid),
ctx.getResources().getDimensionPixelSize(R.dimen.ui_joystick_whole_field_height)
);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
leftControlTouchView.setLayoutParams(params);
}
/ /...
createLeftControlTouchView();
containerView.addView(leftControlTouchView);
Copy the code
The manager initialization requires a ViewGroup to hold the control disk.
public DefaultController(Context context, RelativeLayout containerView, PadStyle padStyle) {
this.ctx = context;
this.containerView = containerView;
this.padStyle = padStyle;
}
Copy the code
Fragments used in
Initialize the manager
Initialize the manager to create a control disk
mDefaultController =
new DefaultController(getContext(),
(RelativeLayout) root.findViewById(R.id.joystick_container));
mDefaultController.createViews();
mDefaultController.showViews(false);
Copy the code
Set the listener to obtain the operation information of the user
The listener is set through the controller
mDefaultController.setLeftTouchViewListener(new JoystickTouchViewListener() {
@Override
public void onTouch(float horizontalPercent, float verticalPercent) {
Log.d(TAG, "onTouch left: " + horizontalPercent + "," + verticalPercent);
}
@Override
public void onReset(a) {
Log.d(TAG, "onReset: left");
}
@Override
public void onActionDown(a) {
Log.d(TAG, "onActionDown: left");
}
@Override
public void onActionUp(a) {
Log.d(TAG, "onActionUp: left"); }});Copy the code
So far, we have achieved a simple control disk control. You can use this control in some control class applications.
If you want to make more beautiful, more attractive controls, we need to have a good aesthetic level.