掌握Android自定义View与独家优化技巧_android

在Android应用开发中,自定义View是一种强大的工具,可以帮助你创建独特的用户界面元素。本文将详细介绍如何创建自定义View,并提供优化技巧,以确保你的自定义View在性能和用户体验方面表现出色。

什么是自定义View

自定义View是Android开发中的重要概念,允许你创建不同于标准UI组件的用户界面元素。这些自定义View可以是各种形状、颜色和交互方式,完全满足你的设计需求。

自定义View优点

自定义View具有多方面的优点,包括:

  1. 创造性和定制性:自定义View允许你创建完全独特的用户界面元素,无限扩展Android原生UI组件的功能和外观。
  2. 灵活性:自定义View可以满足各种复杂的设计需求,从简单的动画效果到高度定制的绘图应用。
  3. 可重用性:一旦创建自定义View,它可以在应用中多次重复使用,提高代码的可维护性和可重用性。
  4. 分离关注点:自定义View可以帮助你将应用的不同部分分开,使代码更易于管理和测试。
  5. 提高性能:通过正确优化自定义View,可以提高性能,减少不必要的绘制操作,以及利用硬件加速。
  6. 掌握用户界面:自定义View让你有更多控制权,可以实现独特的用户体验和创新的界面设计。

创建自定义View

步骤1: 继承View类或其子类

要创建自定义View,首先需要继承自Android的View类或其子类,如ViewGroup。根据需要,你还可以继承更具体的子类,如TextViewImageView等。以下是一个简单的示例:

public class MyCustomView extends View {
    public MyCustomView(Context context) {
        super(context);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
步骤2: 重写onMeasure方法

你需要重写onMeasure方法来定义自定义View的尺寸。这个方法决定了View的宽度和高度,通常基于View的内容和布局需求计算测量值。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int desiredWidth = // 计算所需宽度;
    int desiredHeight = // 计算所需高度;

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int width, height;

    if (widthMode == MeasureSpec.EXACTLY) {
        // 确切的宽度
        width = widthSize;
    } else if (widthMode == MeasureSpec.AT_MOST) {
        // 宽度不超过所需尺寸
        width = Math.min(desiredWidth, widthSize);
    } else {
        // 未指定宽度
        width = desiredWidth;
    }

    if (heightMode == MeasureSpec.EXACTLY) {
        // 确切的高度
        height = heightSize;
    } else if (heightMode == MeasureSpec.AT_MOST) {
        // 高度不超过所需尺寸
        height = Math.min(desiredHeight, heightSize);
    } else {
        // 未指定高度
        height = desiredHeight;
    }

    setMeasuredDimension(width, height);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
步骤3: 重写onDraw方法

onDraw方法用于绘制自定义View的内容。在这里,你可以使用Canvas对象进行绘制操作,包括绘制形状、文本、位图等。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    // 绘制自定义UI
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
步骤4: 在XML布局中使用自定义View

你可以在XML布局文件中使用你的自定义View,就像使用标准的UI组件一样。

<com.example.myapp.MyCustomView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
  • 1.
  • 2.
  • 3.
步骤5: 在Java代码中操作自定义View

你可以在Java代码中获取对自定义View的引用,并进一步自定义和操作它。

MyCustomView customView = findViewById(R.id.my_custom_view);
// 进行自定义操作,例如设置属性或监听器
  • 1.
  • 2.

自定义View注意事项

在创建自定义View时,需要考虑以下注意事项:

  1. 性能问题:自定义View的绘制操作可能影响应用的性能,因此需要谨慎优化,避免不必要的重绘。
  2. 测量和布局:正确实现onMeasureonLayout方法,以确保自定义View在布局中正确地排列和测量。
  3. 绘制顺序:了解绘制顺序,确保子View在父View之上正确绘制,避免遮挡或重叠。
  4. 触摸事件处理:处理触摸事件以实现交互,需要正确处理触摸事件的分发和处理。
  5. 内存管理:确保及时释放不再需要的资源,如位图,以防止内存泄漏。
  6. 适配屏幕尺寸:考虑在不同屏幕尺寸和密度下的表现,以确保用户界面适应不同的设备。
  7. 自定义属性:如果需要,可以定义和处理自定义属性,以便在XML布局中配置自定义View。

优化自定义View

使用硬件加速

启用硬件加速可以提高自定义View的绘制性能。在XML布局文件中,可以使用以下属性启用硬件加速:

android:layerType="hardware"
  • 1.
避免不必要的绘制

只在数据发生变化时进行绘制,可以减少CPU和GPU的负载。在onDraw方法中添加必要的条件检查,以确定是否需要重新绘制。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    if (dataChanged) {
        // 重新绘制
        // ...
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
使用合适的绘制方法

根据需求选择适当的绘制方法,以提高性能。例如,如果你只需绘制一个位图,可以使用Canvas.drawBitmap()方法。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    // 绘制位图
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
    canvas.drawBitmap(bitmap, 0, 0, null);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
处理触摸事件

如果需要自定义View响应触摸事件,可以重写onTouchEvent方法,处理触摸事件逻辑。

@Override
public boolean onTouchEvent(MotionEvent event) {
    // 处理触摸事件逻辑
    return true; // 或者返回super.onTouchEvent(event)根据需要
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
使用自定义绘制缓存

使用自定义绘制缓存可以减少不必要的重绘操作。在自定义View的类中,你可以创建一个Canvas和一个Bitmap,然后在Canvas上绘制内容。这样,在onDraw方法中,你只需要将Bitmap绘制到屏幕上,而不必每次都重新绘制内容。

public class MyCustomView extends View {
    private Bitmap cacheBitmap;
    private Canvas cacheCanvas;
    private Paint paint;

    public MyCustomView(Context context) {
        super(context);
        init();
    }

    public MyCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setColor(Color.RED);
        cacheBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        cacheCanvas = new Canvas(cacheBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 绘制缓存的Bitmap到屏幕
        canvas.drawBitmap(cacheBitmap, 0, 0, null);
    }

    public void updateView() {
        // 在cacheCanvas上绘制内容
        cacheCanvas.drawRect(0, 0, getWidth(), getHeight(), paint);

        // 通知系统重绘
        invalidate();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
使用图层合成

使用图层合成可以创建多个图层,然后将它们合成成一个单一的图像。这对于创建复杂的自定义View和特效非常有用。以下是一个示例,使用Canvas.saveLayer方法创建一个图层:

public class MyCustomView extends View {
    private Paint paint;

    public MyCustomView(Context context) {
        super(context);
        init();
    }

    public MyCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint = new Paint();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int width = getWidth();
        int height = getHeight();

        int saveFlags = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG |
                        Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
                        Canvas.CLIP_TO_LAYER_SAVE_FLAG;
        int layerId = canvas.saveLayer(0, 0, width, height, null, saveFlags);

        // 在图层上绘制内容
        paint.setColor(Color.RED);
        canvas.drawRect(0, 0, width / 2, height, paint);

        paint.setColor(Color.BLUE);
        canvas.drawRect(width / 2, 0, width, height, paint);

        // 合并图层
        canvas.restoreToCount(layerId);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
考虑多线程绘制

将自定义View的绘制操作移到后台线程,以提高性能和响应性。下面是一个使用AsyncTask的示例,将绘制操作放在后台线程中:

public class MyCustomView extends View {
    // ...

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 绘制UI
    }

    public void drawInBackground() {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                // 在后台线程上绘制UI
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                // 更新UI
                invalidate();
            }
        }.execute();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
使用自定义View组合

将多个自定义View组合到一个更大的自定义View中,以提高可维护性和可重用性。以下是一个示例,其中MyCustomViewGroup包含了多个子自定义View:

public class MyCustomViewGroup extends ViewGroup {
    public MyCustomViewGroup(Context context) {
        super(context);
        init();
    }

    private void init() {
        // 添加子自定义View
        MyCustomView view1 = new MyCustomView(getContext());
        MyCustomView view2 = new MyCustomView(getContext());
        // ...
        addView(view1);
        addView(view2);
        // ...
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // 布局子自定义View
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

总结

自定义View是Android应用开发中的关键工具,允许开发人员创建独特的用户界面元素。通过继承View类、重写onMeasure和onDraw等方法,以及应用性能优化技巧,你可以打造出高性能和令人印象深刻的自定义用户界面。

最后大家分享一份全套的Android学习资料,给那些想学习 Android 的小伙伴们一点帮助!

适用于:
  • 任何想学习Android开发但不知道从哪里开始的人
  • 也适用于已经开始进行Android开发但想要变得更好的任何人
一、Android所有方向的学习路线

为了成为更好的 Android 开发者,这里为大家提供了总的路线图。它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。如果下面这个学习路线能帮助大家成为一个更好的 Android 开发者,那么我的使命也就完成了:

包括:Android应用开发、系统开发、音视频开发、Flutter开发、小程序开发、UI界面、车载系统开发等等

掌握Android自定义View与独家优化技巧_面试_02

二、学习软件

工欲善其事必先利其器。学习Android常用的Android Studio视频教程和Android Studio最新的安装包都在这里了,给大家节省了很多时间。

掌握Android自定义View与独家优化技巧_面试_03


掌握Android自定义View与独家优化技巧_android_04

三、进阶学习视频

我们在学习的时候,往往书籍源码难以理解,阅读困难,这时候视频教程教程是就很适合了,生动形象加上案例实战,科学有趣才能更方便的学习下去。

掌握Android自定义View与独家优化技巧_flutter_05

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

掌握Android自定义View与独家优化技巧_android_06

五、经典书籍阅读

阅读Android经典书籍可以帮助读者提高技术水平,开拓视野,掌握核心技术,提高解决问题的能力,同时也可以借鉴他人的经验。对于想要深入学习Android开发的读者来说,阅读Android经典书籍是非常有必要的。

掌握Android自定义View与独家优化技巧_面试_07

六、面试资料

我们学习Android必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

掌握Android自定义View与独家优化技巧_flutter_08

掌握Android自定义View与独家优化技巧_学习_09