Android - JoystickView 虛擬手柄,控制盤,自定義UI

在一些手機遊戲中,玩家能夠經過虛擬控制盤來控制遊戲角色的行動。 無人機和玩具操控App中也有這一類控制盤的應用。java

用自定義View的方式來實現相似手柄的控件。git

效果圖

相關代碼請見 github.com/RustFisher/…github

JoystickView特性

目前JoystickView特性以下ide

  • 2種風格
    • 固定控制盤;
    • 浮動跟隨模式;控制盤會移動到手指第一次點擊的地方
  • 能夠在背景上添加「箭頭」,即添加效果圖片
  • 自定義的「觸摸球」圖片和背景圖片
  • 手指移出了控制盤範圍,仍然可以保持追隨
  • 能獲取到移動位置的百分比參數

實現思路

用自定義View的方式實現這個控制盤。建立TouchViewui

控制盤的基本要求是跟隨手指作出反應。爲了獲取到手指觸屏的座標,會用到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;
    }
複製代碼

Fragment中使用

初始化管理器

初始化管理器,建立控制盤

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");
            }
        });
複製代碼

至此,咱們實現了一個簡單的控制盤控件。在一些控制類應用中能夠使用這個控件。

若想要作出更優美,更吸引人的控件,須要咱們有好的審美水平。

相關文章
相關標籤/搜索