在Android开发中,自定义View对错常常见的需求。自定义View可以协助咱们完结一些特殊的作用,或者让咱们的运用更加美观。本文将介绍Android自定义View的过程,并供给示例代码。

过程一:承继View或者其子类

要自定义View,咱们首要需求创立一个新的类,并让它承继自View或者其子类。View是一切控件的基类,因而咱们可以通过承继View来创立自定义控件。

比方,咱们可以创立一个名为MyView的类,并让它承继自View:

public class MyView extends View {
    // ...
}

过程二:完结结构办法

接下来,咱们需求为自定义View完结结构办法。在结构办法中,咱们可以完结一些初始化的作业,比方设置画笔颜色、初始化属性等。

public MyView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // ... 初始化作业
}

过程三:完结onDraw办法

onDraw办法是自定义View中最重要的办法之一。在这个办法中,咱们可以运用画笔制作自己想要的图形。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // ... 制作图形
}

在完结onDraw办法时,咱们可以运用以下技巧:

  • 运用局部变量:在onDraw办法中创立对象和变量会增加内存分配和垃圾回收的负担。因而,在onDraw办法中运用局部变量可以进步功能。
  • 运用缓存:假如咱们需求频深重绘的自定义View,可以运用缓存来进步功能。可以运用Bitmap或者Canvas来进行缓存。
  • 运用线程:假如咱们需求进行一些耗时的操作,比方网络恳求、图片加载等,可以运用线程来防止堵塞UI线程。可以运用AsyncTask或者Handler来敞开线程。

以下是一个运用局部变量和缓存的示例代码:

public class MyView extends View {
    private Paint mPaint; // 画笔
    private Bitmap mBitmap; // 缓存的Bitmap
    private Canvas mCanvas; // 缓存的Canvas
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init() {
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(5);
        mPaint.setStyle(Paint.Style.STROKE);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mBitmap == null) {
            // 创立缓存的Bitmap和Canvas
            mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);
        }
        // 制作图形到缓存的Canvas上
        mCanvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2 - 5, mPaint);
        // 将缓存的Bitmap制作到View的Canvas上
        canvas.drawBitmap(mBitmap, 0, 0, null);
    }
}

过程四:处理接触事情

假如咱们的自定义View需求支撑接触事情,那么咱们还需求完结接触事情处理办法。

@Override
public boolean onTouchEvent(MotionEvent event) {
    // ... 处理接触事情
    return super.onTouchEvent(event);
}

在处理接触事情时,咱们可以运用以下技巧:

  • 运用GestureDetector:GestureDetector可以协助咱们检测手势,比方单击、双击、长按、滑动等。
  • 运用VelocityTracker:VelocityTracker可以协助咱们计算接触事情的速度和方向,比方滑动的速度和方向。
  • 运用Scroller:Scroller可以协助咱们完结滑润的滚动作用,比方ListView和ScrollView中的滚动作用。

以下是一个运用GestureDetector的示例代码:

public class MyView extends View {
    private GestureDetector mGestureDetector;
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init() {
        mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                // 处理单击事情
                return super.onSingleTapUp(e);
            }
            @Override
            public void onLongPress(MotionEvent e) {
                // 处理长按事情
                super.onLongPress(e);
            }
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                // 处理滑动事情
                return super.onScroll(e1, e2, distanceX, distanceY);
            }
        });
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 将事情交给GestureDetector处理
        return mGestureDetector.onTouchEvent(event);
    }
}

过程五:处理丈量和布局

假如咱们的自定义View需求支撑自适应巨细,那么咱们还需求处理丈量和布局。在丈量阶段,咱们需求丈量自定义View的巨细;在布局阶段,咱们需求根据丈量成果来确认自定义View的位置。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // ... 丈量自定义View的巨细
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    // ... 确认自定义View的位置
    super.onLayout(changed, left, top, right, bottom);
}

在处理丈量和布局时,咱们可以运用以下技巧:

  • 运用MeasureSpec:MeasureSpec可以协助咱们丈量自定义View的巨细,它包含了两个参数:spec和size。spec用于表示丈量模式,size用于表示丈量巨细。
  • 运用LayoutParams:LayoutParams可以协助咱们设置自定义View的布局参数,比方宽度、高度、位置等。
  • 运用MeasureSpec和LayoutParams结合运用:咱们可以运用MeasureSpec和LayoutParams结合运用来完结自定义View的自适应巨细和位置。

以下是一个运用MeasureSpec和LayoutParams结合运用的示例代码:

public class MyView extends View {
    private Paint mPaint; // 画笔
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init() {
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(5);
        mPaint.setStyle(Paint.Style.STROKE);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 指定自定义View的巨细为200dp x 200dp
        int width = MeasureSpec.makeMeasureSpec(dp2px(200), MeasureSpec.EXACTLY);
        int height = MeasureSpec.makeMeasureSpec(dp2px(200), MeasureSpec.EXACTLY);
        setMeasuredDimension(width, height);
    }
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        // 在父容器的中心放置自定义View
        int parentWidth = ((ViewGroup) getParent()).getWidth();
        int parentHeight = ((ViewGroup) getParent()).getHeight();
        int viewWidth = getMeasuredWidth();
        int viewHeight = getMeasuredHeight();
        int x = (parentWidth - viewWidth) / 2;
        int y = (parentHeight - viewHeight) / 2;
        setLeft(x);
        setTop(y);
        setRight(x + viewWidth);
        setBottom(y + viewHeight);
    }
    private int dp2px(int dp) {
        return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
    }
}

定论

本文介绍了Android自定义View的过程,并参加了一些开发技巧,包括运用局部变量、缓存、线程、GestureDetector、VelocityTracker、Scroller、MeasureSpec和LayoutParams等。希望这篇文章可以协助到你,让你更好地把握自定义View的技巧。 同时,需求注意功能和内存的问题,以及与其他控件的交互和兼容性。

引荐

android_startup: 供给一种在运用发动时可以更加简略、高效的方法来初始化组件,优化发动速度。不只支撑Jetpack App Startup的全部功能,还供给额外的同步与异步等候、线程操控与多进程支撑等功能。

AwesomeGithub: 根据Github的客户端,纯练习项目,支撑组件化开发,支撑账户暗码与认证登陆。运用Kotlin言语进行开发,项目架构是根据JetPack&DataBinding的MVVM;项目中运用了Arouter、Retrofit、Coroutine、Glide、Dagger与Hilt等流行开源技术。

flutter_github: 根据Flutter的跨平台版本Github客户端,与AwesomeGithub相对应。

android-api-analysis: 结合详细的Demo来全面解析Android相关的知识点, 协助读者可以更快的把握与了解所论述的关键。

daily_algorithm: 每日一算法,由浅入深,欢迎参加一同共勉。