zoukankan      html  css  js  c++  java
  • Android 自定义View修炼-Android开发之自定义View开发及实例详解

    在开发Android应用的过程中,难免需要自定义View,其实自定义View不难,只要了解原理,实现起来就没有那么难。

    其主要原理就是继承View,重写构造方法、onDraw,(onMeasure)等函数。我自定义了个虚拟按键的View,效果图如下:

    首先得自己写个自定义View类,这里我写了个VirtualKeyView类,继承自View类,实现了构造方法以及onDraw方法,以及实现了键盘按键的接口事件,实现代码如下:

    package com.czm.customview;
    
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.PaintFlagsDrawFilter;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.KeyEvent;
    import android.view.MotionEvent;
    import android.view.View;
    
    public class VirtualKeyView extends View{
    
        private static final boolean bDebug = true;
        private static final String TAG = VirtualKeyView.class.getSimpleName();
        
        private Context mContext;
        
        private Bitmap bmpRound;
        private Bitmap bmpRound_press;
        private Bitmap bmpOk;
        private Bitmap bmpOk_press;
    
        private int mWidth;//真实宽度
        
        private int widthBg = 584;
        //private int widthItemBg = 292;
        private int widthMid = 220;//中心宽度
        
        private int cir_Centre_X = 292;//圆心位置
        private int cir_Centre_Y = 292;//圆心位置
        private int bigRadius = 292;
        private int smallRadius = 110;
        private int smallCir_X = 182;
        private int smallCir_Y = 182;
        private float scale = 1.0f;
        
        private boolean isInit = false;
        
        private int inputPress = -1;//显示点击了哪个键
        
    
        public VirtualKeyView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
            mContext = context;
        }
        
        public VirtualKeyView(Context context, AttributeSet attrs) {
            super(context, attrs);
            // TODO Auto-generated constructor stub
            mContext = context;
        }
    
    private void initData() {
            
            mWidth = getWidth();
            scale = mWidth*1.0f/widthBg;
            
            cir_Centre_X = (int) (cir_Centre_X*scale);
            cir_Centre_Y = (int) (cir_Centre_Y*scale);
            bigRadius = (int) (bigRadius*scale);
            smallRadius = (int) (smallRadius*scale);
            smallCir_X = (int) (smallCir_X*scale);
            smallCir_Y = (int) (smallCir_Y*scale);
            
            initView();
            isInit = true;
        }
        
        private void initView() {
            if(mWidth == widthBg){
                bmpRound = Utils.decodeCustomRes(mContext, R.drawable.controller_round);
                bmpRound_press= Utils.decodeCustomRes(mContext, R.drawable.controller_round_bg_pressed);
                bmpOk= Utils.decodeCustomRes(mContext, R.drawable.controller_ok);
                bmpOk_press= Utils.decodeCustomRes(mContext, R.drawable.controller_ok_pressed);
            } else {
                int mid = (int) (widthMid*scale);
                Bitmap bitmapTmp = Utils.decodeCustomRes(mContext, R.drawable.controller_round);
                bmpRound = Bitmap.createScaledBitmap(bitmapTmp, mWidth, mWidth, true);
                bitmapTmp.recycle();
                bitmapTmp = null;
                
                bitmapTmp = Utils.decodeCustomRes(mContext, R.drawable.controller_round_bg_pressed);
                bmpRound_press = Bitmap.createScaledBitmap(bitmapTmp, mWidth, mWidth, true);
                bitmapTmp.recycle();
                bitmapTmp = null;
    
                bitmapTmp = Utils.decodeCustomRes(mContext, R.drawable.controller_ok);
                bmpOk = Bitmap.createScaledBitmap(bitmapTmp, mid, mid, true);
                bitmapTmp.recycle();
                bitmapTmp = null;
                
                bitmapTmp = Utils.decodeCustomRes(mContext, R.drawable.controller_ok_pressed);
                bmpOk_press = Bitmap.createScaledBitmap(bitmapTmp, mid, mid, true);
                bitmapTmp.recycle();
                bitmapTmp = null;
            }
            System.gc();
        }
        
        public void  recycle() {
            if (bmpRound != null && !bmpRound.isRecycled()) {
                bmpRound.recycle();
                bmpRound = null;
            }
            if (bmpRound_press != null && !bmpRound_press.isRecycled()) {
                bmpRound_press.recycle();
                bmpRound_press = null;
            }
            if (bmpOk != null && !bmpOk.isRecycled()) {
                bmpOk.recycle();
                bmpOk = null;
            }
            if (bmpOk_press != null && !bmpOk_press.isRecycled()) {
                bmpOk_press.recycle();
                bmpOk_press = null;
            }
            System.gc();
        }
        
        @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            super.onDraw(canvas);
            if(!isInit){
                initData();
            }
            canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
                    | Paint.FILTER_BITMAP_FLAG));// 抗锯齿
            drawCir(canvas);
        }
        
        private void drawCir(Canvas canvas) {
            switch (inputPress) {
            case -1:
                //无按键
                canvas.drawBitmap(bmpRound, 0, 0, null);
                canvas.drawBitmap(bmpOk, smallCir_X , smallCir_Y, null);
                break;
            case KeyEvent.KEYCODE_DPAD_CENTER:
                //中心Ok键
                canvas.drawBitmap(bmpRound, 0, 0, null);
                canvas.drawBitmap(bmpOk_press, smallCir_X , smallCir_Y, null);
                break;
            case KeyEvent.KEYCODE_DPAD_UP:
                //
                drawBg(canvas,180);
                canvas.drawBitmap(bmpOk, smallCir_X , smallCir_Y, null);
                break;
            case KeyEvent.KEYCODE_DPAD_DOWN:
                //
                drawBg(canvas,0);
                canvas.drawBitmap(bmpOk, smallCir_X , smallCir_Y, null);
                break;
            case KeyEvent.KEYCODE_DPAD_LEFT:
                //
                drawBg(canvas,90);
                canvas.drawBitmap(bmpOk, smallCir_X , smallCir_Y, null);
                break;
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                //
                drawBg(canvas,270);
                canvas.drawBitmap(bmpOk, smallCir_X , smallCir_Y, null);
                break;
                
            default:
                break;
            }
        }
        
        private void drawBg(Canvas canvas,int rotate) {
            canvas.save();    //保存canvas状态
            canvas.rotate(rotate,cir_Centre_X,cir_Centre_Y);
            canvas.drawBitmap(bmpRound_press, 0, 0, null);//这里画的是旋转后的
            canvas.restore();// 恢复canvas状态
        }
        
        public boolean onTouchEvent(MotionEvent event) {
            if (bDebug)
                Log.d(TAG, "event.getAction() = " + event.getAction());
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    // 计算圆选择的哪个字母
                    int x1 = (int) (event.getX() - cir_Centre_X);
                    int y1 = (int) (event.getY() - cir_Centre_Y);
                    if (bDebug)
                        Log.d(TAG, "x= " + x1 + ", y = " + y1);
                    int x2 = x1 * x1;
                    int y2 = y1 * y1;
                    int bigRadius2 = bigRadius * bigRadius;
                    int smallRadius2 = smallRadius * smallRadius;
                    if (x2 + y2 < bigRadius2) {
                        // 表示在画圆形之内,才有继续计算的必要
                        if (x2 + y2 < smallRadius2) {
                            // 如果再小圆内
                            setOnKeyDown(KeyEvent.KEYCODE_DPAD_CENTER);
                        } else if (y1 > x1) {
                            if (y1 > -x1) {
                                //
                                setOnKeyDown(KeyEvent.KEYCODE_DPAD_DOWN);
                            } else {
                                //
                                setOnKeyDown(KeyEvent.KEYCODE_DPAD_LEFT);
                            }
                        } else if (y1 < x1) {
                            if (y1 > -x1) {
                                //
                                setOnKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT);
                            } else {
                                //
                                setOnKeyDown(KeyEvent.KEYCODE_DPAD_UP);
                            }
                        }
                    }
                    // isShowCir = false;
                    postInvalidate();
                return true;
            }
    
            if (event.getAction() == MotionEvent.ACTION_UP) {
                    // 计算圆选择的哪个字母
    
                    int x1 = (int) (event.getX() - cir_Centre_X);
                    int y1 = (int) (event.getY() - cir_Centre_Y);
                    if (bDebug)
                        Log.d(TAG, "x= " + x1 + ", y = " + y1);
                    int x2 = x1 * x1;
                    int y2 = y1 * y1;
                    int bigRadius2 = bigRadius * bigRadius;
                    int smallRadius2 = smallRadius * smallRadius;
                    if (x2 + y2 < bigRadius2) {
                        // 表示在画圆形之内,才有继续计算的必要
                        if (x2 + y2 < smallRadius2) {
                            // 如果再小圆内
                            setOnKeyUp(KeyEvent.KEYCODE_DPAD_CENTER);
                        } else if (y1 > x1) {
                            if (y1 > -x1) {
                                //
                                setOnKeyUp(KeyEvent.KEYCODE_DPAD_DOWN);
                            } else {
                                //
                                setOnKeyUp(KeyEvent.KEYCODE_DPAD_LEFT);
                            }
                        } else if (y1 < x1) {
                            if (y1 > -x1) {
                                //
                                setOnKeyUp(KeyEvent.KEYCODE_DPAD_RIGHT);
                            } else {
                                //
                                setOnKeyUp(KeyEvent.KEYCODE_DPAD_UP);
                            }
                        }
    
                    }
                    postInvalidate();
            }
            return true;
        }
        
        private void setOnKeyDown(int keyCode) {
            if(bDebug)
                Log.d(TAG, "keyCode = "+keyCode);
            inputPress = keyCode;
            if(myIntputCallBack != null){
                myIntputCallBack.intputDown(keyCode);
            }
        }
        
        private void setOnKeyUp(int keyCode) {
            inputPress = -1;
            if(myIntputCallBack != null){
                myIntputCallBack.intputUp(keyCode);
            }
        }
        
        /******************* 输入回调函数 ********************/
        private IntputCallBack myIntputCallBack = null;
    
        public interface IntputCallBack {
            void intputDown(int keyCode);
            void intputUp(int keyCode);
        }
    
        public void setOnInputCallBack(IntputCallBack myIntputCallBack) {
            this.myIntputCallBack = myIntputCallBack;
        }
    }

    在xml布局文件里面如何使用上面自定义的View视图控件呢?很简单就是 和 使用<TextView> 一样,只需写全路径即可:本例中如下:

    在main.xml的UI布局文件中加入:

    <com.czm.customview.VirtualKeyView
            android:id="@+id/virtualKeyView"
            android:layout_marginTop="20dp"
            android:layout_width="250dp"
            android:layout_height="250dp"
            android:layout_centerHorizontal="true"
             />

    在看看 如何在java类文件中使用 该 VirtualKeyView视图控件呢,这个时候就和 普通的TextView视图一样使用了,本例中

    在MainActivity中使用如下:

    package com.czm.customview;
    
    
    import com.czm.customview.VirtualKeyView.IntputCallBack;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.KeyEvent;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    
        private VirtualKeyView virtualKeyView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            virtualKeyView = (VirtualKeyView) findViewById(R.id.virtualKeyView);
    
            virtualKeyView.setOnInputCallBack(new IntputCallBack() {
    
                @Override
                public void intputUp(int keyCode) {
    
                }
    
                @Override
                public void intputDown(int keyCode) {
                    if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
                        showToast("您按了 上 键");
                    } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
                        showToast("您按了 下 键");
                    } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
                        showToast("您按了 左 键");
                    } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
                        showToast("您按了 右 键");
                    } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
                        showToast("您按了 OK 键");
                    }
    
                }
            });
    
        }
        private void showToast(String msg){
            Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
        }
        
        @Override
        public void onDestroy() {
            super.onDestroy();
            virtualKeyView.recycle();
        }
    
    }

    Utils.java文件中的decodeCustomRes方法实现如下:

    package com.czm.customview;
    
    import java.io.InputStream;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    
    public class Utils {
        public static Bitmap decodeCustomRes(Context c, int res) {
            InputStream is = c.getResources().openRawResource(res);
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = false;
            options.inSampleSize = 1;//表示原尺寸加载图片,不缩放
            Bitmap bmp = BitmapFactory.decodeStream(is, null, options);
            return bmp;
        }
    }

    到此为止,自定义的View完毕了,Ctrl+F11即可运行查看效果啦~~

  • 相关阅读:
    npm 常用命令
    vue router 配合transition 切换动画
    非指针 复制对象和数组的两种方法
    Date()对象的设置与解析
    js map()处理数组和对象数据
    鉴别JS数据类型的全套方法
    JS数组与对象的遍历方法大全
    js异步原理与 Promise
    HTTP请求封装:Ajax与RESTful API
    "unresolved reference 'appium' "问题解决
  • 原文地址:https://www.cnblogs.com/JczmDeveloper/p/3759183.html
Copyright © 2011-2022 走看看