在一些手機遊戲中,玩家能夠經過虛擬控制盤來控制遊戲角色的行動。 無人機和玩具操控App中也有這一類控制盤的應用。java
用自定義View的方式來實現相似手柄的控件。git
相關代碼請見 github.com/RustFisher/…github
目前JoystickView特性以下ide
用自定義View的方式實現這個控制盤。建立TouchView
。ui
控制盤的基本要求是跟隨手指作出反應。爲了獲取到手指觸屏的座標,會用到View的onTouchEvent
方法。this
控件中的「觸摸球」和背景由圖片得來。在自定義view中先獲取相應的bitmap,縮放成指定的尺寸。spa
onTouchEvent
中獲取到相應的座標,計算出圖片應該出現的位置;onDraw
中根據座標進行繪製。 計算出手指位置與控制盤中心的距離等信息,經過listener傳遞出去。code
有固定和浮動這兩種風格,將來可能還會添加cdn
public enum PadStyle {
FLOATING /* 隨用戶手指從新定位 */,
FIXED /* 固定位置 */
}
複製代碼
咱們能夠不直接操做TouchView
,建立TouchViewModel
存放相關的配置。blog
private int bgResId; // 背景圖片資源ID
private int touchBmpResId; // 觸摸圖資源ID - 例如一個圓球
private int directionPicResId; // 指示當前觸摸點與圓心相對方向的圖片ID
private float mWholeViewWid; // 整個View的寬
private float mWholeViewHeight; // 整個View的高
private float mWholePadWid; // 盤的寬度,包括箭頭;並非View的總寬度
private float mWholePadHeight; // 盤的高度,包括箭頭;並非View的總寬度
private int mRoundBgRadius; // 背景圓的半徑 背景圓位置能夠變化
private int mTouchBallRadius = 100; // 觸摸球的半徑
private int mRoundBgPadding; // 背景圓到Pad邊界的px 通常是留給方向箭頭的位置
private boolean showDirectionPic = false; // 是否顯示指示圖片
private PadStyle mPadStyle = PadStyle.FIXED; // 默認爲固定位置的
private PadLocationType mPadLocationType = PadLocationType.LEFT_BOT;
// .........
複製代碼
控制盤的配置項比較多,抽象出一個DefaultController
來管理控制盤。這個控制器不是必要的。 管理器須要控制盤所在的父View,這裏用的是RelativeLayout。
建立一個「左控制盤」。將各個尺寸配置傳入。最後添加到containerView
中。
private void createLeftControlTouchView() {
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的總大小
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);
複製代碼
管理器初始化時須要一個ViewGroup來承載控制盤。
public DefaultController(Context context, RelativeLayout containerView, PadStyle padStyle) {
this.ctx = context;
this.containerView = containerView;
this.padStyle = padStyle;
}
複製代碼
初始化管理器,建立控制盤
mDefaultController =
new DefaultController(getContext(),
(RelativeLayout) root.findViewById(R.id.joystick_container));
mDefaultController.createViews();
mDefaultController.showViews(false);
複製代碼
經過控制器來設置監聽器
mDefaultController.setLeftTouchViewListener(new JoystickTouchViewListener() {
@Override
public void onTouch(float horizontalPercent, float verticalPercent) {
Log.d(TAG, "onTouch left: " + horizontalPercent + ", " + verticalPercent);
}
@Override
public void onReset() {
Log.d(TAG, "onReset: left");
}
@Override
public void onActionDown() {
Log.d(TAG, "onActionDown: left");
}
@Override
public void onActionUp() {
Log.d(TAG, "onActionUp: left");
}
});
複製代碼
至此,咱們實現了一個簡單的控制盤控件。在一些控制類應用中能夠使用這個控件。
若想要作出更優美,更吸引人的控件,須要咱們有好的審美水平。