Android自定义视图绘制:Canvas实战案例解析

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Android的Canvas工具允许开发者在屏幕上绘制图形,创建丰富视觉效果和交互体验。本案例"DrawDialDemo"深入解析了如何通过Canvas实现自定义画图,从创建画布到使用 onDraw() 方法,再到旋转图形和动态更新UI等高级技巧。通过实例演示,本案例详细讲解了仪表盘绘制的整个过程,包括指针、刻度线和数字等元素的绘制,以及如何在非UI线程中更新画布。掌握了这些技巧后,开发者将能制作出更多复杂的自定义视图,并进一步提升在Android图形编程方面的能力。 Android上canvas自定义画图案例

1. Canvas在Android图形系统中的作用

在Android应用开发中,图形系统提供了一系列强大且灵活的工具来创建和显示图形。其中,Canvas是一个基础且关键的组件,它承担着绘制操作的主要职责。通过Canvas,开发者可以将矢量图形、位图和文字等绘制到屏幕上,实现各种图形界面的视觉效果。

Canvas的工作原理

Canvas可以被看作是一个画布,它通过调用各种绘图命令(如绘制线条、矩形、圆形等)来将图形元素逐一构建起来。开发者通过指定绘图命令的参数来控制图形的形状、大小和位置。这些绘图命令是通过Paint对象来配置的,例如颜色、样式、笔触大小等。

Canvas在绘图中的重要性

在Android的View体系中,View的绘制操作最终都会调用Canvas的方法。自定义View时,重写 onDraw() 方法是实现复杂图形绘制的关键步骤。通过在 onDraw() 中使用Canvas和Paint,开发者可以创造出各种静态或动态的视觉效果。

Canvas的引入为Android的图形处理提供了高度的灵活性和强大的能力,使得开发者能够在不同的场景中实现丰富的视觉体验和用户交互。下一章,我们将深入探讨创建Bitmap作为画布的过程,以及如何在Java代码中管理Bitmap资源。

2. 创建Bitmap作为画布

2.1 Bitmap的基本概念和特性

2.1.1 Bitmap的定义与类型

Bitmap是Android中用于存储图像像素数据的一种对象。它定义了图像的尺寸、颜色配置以及图像的像素数据。在Android开发中,Bitmap是最基本的图像处理单元。

Bitmap的类型分为几种,包括但不限于: - ARGB_8888: 这是最常用的格式,每个像素由4个字节组成,分别代表透明度(Alpha)、红色(Red)、绿色(Green)和蓝色(Blue)。 - RGB_565: 这种格式每个像素占用16位,但不包含透明度信息。 - ARGB_4444: 每个像素只使用4位来表示颜色和透明度,颜色精度较低。

2.1.2 Bitmap的内存管理和性能优化

在内存管理方面,Bitmap对象通常占用较多内存,尤其是高分辨率的图片。因此,管理好Bitmap对象的创建和销毁,是避免内存泄漏和优化性能的关键。

性能优化策略包括: - 使用合适的图片格式以减少内存占用。 - 适时回收Bitmap资源,尤其是在不再需要的情况下。 - 在合适的时机(如在非UI线程)加载和处理图片,减少UI线程的负担。

2.2 在Java代码中创建和管理Bitmap

2.2.1 Bitmap的创建方法

可以通过多种方式在Java代码中创建Bitmap对象。常见的创建方法如下:

// 从资源文件创建Bitmap
Resources res = getResources();
Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.my_image);

// 从文件创建Bitmap
File file = new File(getExternalFilesDir(null), "image.png");
Bitmap bitmapFromFile = BitmapFactory.decodeFile(file.getAbsolutePath());

// 通过BitmapFactory.Options调整解码过程
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2; // 缩放图片,降低内存占用
Bitmap resizedBitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);

2.2.2 Bitmap的回收和内存释放

一旦确定Bitmap不再需要,就应该调用recycle()方法来释放与Bitmap关联的原生像素数据,从而帮助减少应用的内存占用。

if (bitmap != null && !bitmap.isRecycled()) {
    bitmap.recycle();
    bitmap = null;
}
System.gc(); // 提醒系统尽快执行垃圾回收

2.3 在Android Studio中预览和编辑Bitmap

2.3.1 使用Android Studio的图像编辑工具

在Android Studio中,我们可以利用内置的图像编辑工具来预览和编辑Bitmap。可以通过右键点击项目中的Bitmap资源文件,并选择“Open”选项。

2.3.2 预览Bitmap的效果和调整

在Android Studio的资源预览视图中,可以调整缩放比例和查看不同分辨率下的显示效果。此外,还可以进行简单的图像编辑,比如裁剪、旋转等。

// 示例代码:使用BitmapFactory.Options来调整图片的解码方式,优化内存使用
BitmapFactory.Options options = new BitmapFactory.Options();
// 设置inJustDecodeBounds为true,仅加载图片大小信息不加载图片数据
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
// 根据图片实际大小与目标大小计算inSampleSize
int sampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inSampleSize = sampleSize;
// 设置inJustDecodeBounds为false,加载实际的图片数据
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);

在上述代码中, calculateInSampleSize 方法是一个自定义函数,用于计算合适的inSampleSize值,以达到减少内存占用的目的。

通过以上步骤和代码示例,我们可以对Bitmap的基本概念、特性、内存管理、创建与回收方法以及在Android Studio中的预览和编辑有了深入的理解。在接下来的章节中,我们将继续探讨如何使用Canvas绘制基本图形,从而实现更丰富的视觉效果。

3. 使用Canvas绘制基本图形:矩形、圆形、线条和文本

Canvas是Android中用于2D绘图的基础API,而绘图的第一步便是熟悉如何使用Canvas来绘制基本图形。本章节将介绍Canvas绘图基础,以及如何在Canvas上绘制矩形、圆形、线条和文本,并对绘图性能进行优化。

3.1 Canvas绘图基础

3.1.1 Canvas类概述

Canvas是Android提供的一个API,它可以看作是绘图的画布,通过它,开发者可以绘制各种图形。在Android中,Canvas与Paint(画笔)结合使用,Paint负责定义图形的样式,而Canvas则是实际进行绘制的环境。使用Canvas进行绘制,通常涉及到几个基本步骤:获取Canvas对象、创建Paint对象、设置绘图参数以及调用Canvas的绘图方法。

Canvas canvas = new Canvas(bitmap); // 获取Canvas对象
Paint paint = new Paint(); // 创建Paint对象
paint.setColor(Color.RED); // 设置画笔颜色
canvas.drawRect(left, top, right, bottom, paint); // 绘制矩形

在上述代码中,创建了Canvas和Paint对象,并使用Paint的 setColor 方法设置了颜色,然后通过 drawRect 方法绘制了一个矩形。

3.1.2 画笔Paint类的使用

Paint类是Android中用于定义图形绘制风格的类。它不仅控制着颜色,还控制着线宽、样式、抗锯齿、文字大小等。创建Paint对象后,可以通过调用它的方法来定制绘图风格。

Paint paint = new Paint();
paint.setAntiAlias(true); // 设置抗锯齿
paint.setStrokeWidth(10); // 设置线条宽度
paint.setStyle(Paint.Style.FILL); // 设置填充样式
paint.setColor(Color.BLUE); // 设置颜色为蓝色

3.2 绘制基本图形的方法

3.2.1 绘制矩形和圆形

矩形和圆形是最基础的图形,它们的绘制方法如下:

// 绘制矩形
canvas.drawRect(left, top, right, bottom, paint);

// 绘制圆形
canvas.drawCircle(centerX, centerY, radius, paint);

其中, centerX centerY 分别为圆形的中心坐标, radius 为圆的半径。

3.2.2 绘制线条和文本

绘制线条和文本需要使用Canvas的 drawLine drawText 方法:

// 绘制线条
canvas.drawLine(startX, startY, endX, endY, paint);

// 绘制文本
canvas.drawText(text, startX, startY, paint);

其中, startX startY 是线条的起始坐标, endX endY 是线条的终点坐标。绘制文本时, startX startY 表示文本的起始绘制位置。

3.3 优化绘图性能

3.3.1 避免绘图时的性能瓶颈

绘图性能在复杂应用中尤为重要。开发者需要避免在UI线程中进行大量或复杂的绘图操作,因为这会导致界面卡顿。在Canvas绘图中,优化的一个关键点是减少绘图对象的创建。例如,如果绘制操作是周期性的,可以考虑只在第一次时创建Paint对象,之后重复使用。

3.3.2 提升图形绘制效率的策略

优化策略还包括:

  • 避免使用复杂的图形,而是将简单图形组合起来。
  • 利用Canvas的 clipRect clipPath 方法来限制绘制区域,仅对需要重绘的区域进行绘制。
  • 使用 canvas.save() canvas.restore() 来减少绘图操作的重复计算。
canvas.save(); // 保存当前状态
canvas.clipRect(left, top, right, bottom); // 限定绘制区域
// 绘制图形...
canvas.restore(); // 恢复到保存前的状态

以上策略可以有效地提升Canvas绘图的效率,保证应用的流畅运行。

在本章节中,我们学习了Canvas绘图的基础知识,包括如何绘制基本图形以及优化绘图性能。接下来的章节将介绍如何通过自定义View的onDraw方法来实现更高级的绘图功能。

4. 通过onDraw()方法实现自定义绘图

4.1 onDraw()方法的工作机制

4.1.1 了解onDraw()方法的重要性

在Android开发中,自定义视图通常需要通过继承View类并重写其onDraw()方法来实现。onDraw()方法是自定义视图中用于绘制内容的核心方法,它提供了一个Canvas对象,开发者可以利用Canvas提供的API在View上绘制各种图形和图像。掌握onDraw()方法的工作机制对于实现高质量的图形绘制至关重要。

重要性体现在以下几个方面:

  • 自定义UI组件 :通过onDraw()可以创建丰富的UI组件,以满足特定的用户界面需求。
  • 优化性能 :了解onDraw()的调用时机和参数,有助于开发者设计高效的绘图策略,避免不必要的绘图操作。
  • 响应用户交互 :onDraw()方法的重写使得View能够对用户的触摸等操作做出响应,从而实现交互式绘图。

4.1.2 onDraw()方法的调用时机和参数

onDraw()方法由系统在View需要重绘时调用。参数是Canvas类型的对象,它提供了绘图的所有必要工具。Canvas对象是一个抽象概念,它作为绘图的画布,在上面可以绘制点、线、矩形、圆形等基本图形,还可以绘制图片等。

onDraw()方法的调用时机可以由开发者触发,也可以由系统自动触发:

  • 开发者触发 :通过调用 invalidate() 方法,可以通知系统View需要重绘,从而触发onDraw()。
  • 系统触发 :如屏幕旋转、窗口大小变化、内存不足等情况都会导致系统自动调用onDraw()。

4.2 实现自定义View的onDraw()

4.2.1 自定义View的创建和布局

要实现一个自定义View,通常需要创建一个继承自View的新类,并在其构造函数中完成初始化。在布局文件中通过 <com.example.MyCustomView> 标签引入自定义View,并可以设置其属性,如宽高和布局参数。

示例代码如下:

public class MyCustomView extends View {

    public MyCustomView(Context context) {
        super(context);
        // 初始化工作
    }
    public MyCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 从XML布局文件解析属性
    }
    public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 兼容旧版SDK
    }
}

4.2.2 在onDraw()中绘制自定义图形

在onDraw()方法中,可以利用Canvas对象绘制图形。首先,通过 setBackgroundColor() 方法设置背景颜色,然后使用 drawCircle() , drawRect() , drawLine() , 和 drawText() 等方法来绘制基本图形和文本。

示例代码如下:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // 设置背景颜色
    canvas.drawColor(Color.WHITE);

    // 绘制圆形
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setColor(Color.BLUE);
    canvas.drawCircle(getWidth() / 2, getHeight() / 2, 100, paint);

    // 绘制矩形
    paint.setColor(Color.RED);
    canvas.drawRect(50, 150, 250, 250, paint);

    // 绘制线条
    paint.setColor(Color.GREEN);
    paint.setStrokeWidth(10);
    canvas.drawLine(50, 250, 250, 50, paint);

    // 绘制文本
    paint.setColor(Color.BLACK);
    paint.setTextSize(40);
    canvas.drawText("Hello World!", 100, 350, paint);
}

4.3 高级绘图技术的集成

4.3.1 图层Layer的使用

在复杂的自定义绘图中,可以使用Layer图层来优化绘图性能。在Canvas上绘制之前,可以先创建一个Layer,然后在Layer上绘制所有内容,最后将Layer一次性绘制到Canvas上。

示例代码如下:

public void drawLayers(Canvas canvas) {
    // 保存画布的当前状态
    canvas.save();
    // 创建一个新的Layer
    int width = getWidth();
    int height = getHeight();
    int layerId = canvas.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG);
    // 在Layer上绘制内容
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setColor(Color.BLUE);
    canvas.drawCircle(width / 2, height / 2, 100, paint);
    // 将Layer绘制到Canvas
    canvas.restoreToCount(layerId);
    // 恢复画布到之前保存的状态
    canvas.restore();
}

4.3.2 合成模式的探索

Canvas提供了多种合成模式(Blending Modes),通过设置Paint对象的Xfermode属性,可以改变绘制内容的颜色混合效果。

示例代码如下:

public void applyBlendingModes(Canvas canvas) {
    // 设置背景
    canvas.drawColor(Color.WHITE);
    // 设置第一个绘制对象的Paint
    Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint1.setColor(Color.RED);
    canvas.drawRect(0, 0, 100, 100, paint1);
    // 设置第二个绘制对象的Paint,并应用合成模式
    Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    paint2.setColor(Color.GREEN);
    canvas.drawRect(50, 50, 150, 150, paint2);
}

以上通过onDraw()方法实现自定义绘图章节的内容,展示了如何在Android中创建自定义View并实现自定义绘图。

5. 利用Matrix实现图形旋转

5.1 Matrix的作用和应用场景

5.1.1 Matrix类的介绍

Matrix是Android中用于2D矩阵运算的一个类,它可以执行基本的2D变换,如平移、缩放、旋转和倾斜等。这些操作可以组合使用,以实现复杂的图形变换效果。在Canvas绘图中,Matrix常用于对图形进行变换,以达到预期的视觉效果。

5.1.2 Matrix在图形变换中的应用

在Android的Canvas绘图系统中,Matrix可以应用到Bitmap、Path等图形对象上,从而实现图形的移动、旋转、缩放等变换。这样的变换能够为应用带来更加动态和富有表现力的视觉效果,比如在游戏、动画和交互式UI设计中经常可以看到。

5.2 实现图形的旋转和缩放

5.2.1 如何使用Matrix进行旋转

Matrix类中提供了 setRotate 方法,允许开发者设置旋转的角度和旋转的中心点。以下是使用Matrix进行旋转的基本步骤:

  1. 创建Matrix对象实例。
  2. 调用 setRotate 方法设置旋转角度和中心点。
  3. 使用 postRotate 方法将旋转操作应用到Canvas上。
  4. 在Canvas上调用绘制方法绘制图形。

下面的代码展示了如何对一个Bitmap进行旋转操作:

Matrix matrix = new Matrix();
matrix.setRotate(45, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
canvas.drawBitmap(bitmap, matrix, null);

在这段代码中, setRotate 方法接受三个参数:旋转角度(以度为单位)、旋转中心的X坐标和Y坐标。旋转中心默认是图形的左上角,但可以通过改变参数来设置不同的旋转中心。

5.2.2 如何使用Matrix进行缩放

除了旋转之外,Matrix还能用于图形的缩放操作。使用 setScale 方法可以实现这一目的。以下是缩放操作的基本步骤:

  1. 创建Matrix对象实例。
  2. 调用 setScale 方法设置缩放比例和中心点。
  3. 使用 postScale 方法将缩放操作应用到Canvas上。
  4. 在Canvas上调用绘制方法绘制图形。

下面的代码片段演示了如何对Bitmap进行缩放操作:

Matrix matrix = new Matrix();
matrix.setScale(2, 2, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
canvas.drawBitmap(bitmap, matrix, null);

在这段代码中, setScale 方法接收四个参数:X轴缩放比例、Y轴缩放比例、缩放中心的X坐标和Y坐标。通过调整这些参数,可以实现不同的缩放效果。

5.3 矩阵变换的高级应用

5.3.1 矩阵的链式变换操作

Matrix的强大之处在于能够组合多个变换操作来创建复杂的动画效果。通过连续调用不同的变换方法,可以创建一个链式的变换序列。例如,先旋转再缩放的组合变换可以通过如下方式实现:

Matrix matrix = new Matrix();
matrix.setRotate(45, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
matrix.postScale(2, 2, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
canvas.drawBitmap(bitmap, matrix, null);

在这个例子中,图形首先被旋转45度,然后以图形中心为基准缩放两倍。这样的链式调用使得矩阵变换非常灵活。

5.3.2 实现复杂的动画效果

通过Matrix,开发者能够实现流畅且复杂的动画效果。例如,可以为一个图形创建一个连续旋转并逐渐缩放的动画效果。这样的动画可以通过不断地在动画帧中更新矩阵状态来实现。

下面是一个简化的动画示例,使用Matrix实现连续的旋转效果:

Matrix matrix = new Matrix();
final Handler handler = new Handler();
handler.post(new Runnable() {
    public void run() {
        matrix.postRotate(1, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
        canvas.drawBitmap(bitmap, matrix, null);
        handler.postDelayed(this, 10); // 每10毫秒更新一次动画
    }
});

在这个例子中,我们利用Handler和Runnable循环调用 postRotate 方法,每次调用都会让Matrix按顺时针旋转1度,并在10毫秒后再次触发,这样连续执行即可形成连续旋转的动画效果。注意,实际应用中需要控制动画的生命周期,避免内存泄漏。

6. 高级特性及动态效果的实现

实现高级的UI效果和动态图形能够显著提升用户体验。在Android平台上,我们可以通过对Canvas的深入使用、颜色和图形操作的组合,以及性能优化策略来实现这些高级特性。

6.1 颜色混合和渐变效果

在绘制图形时,颜色混合和渐变效果可以增加视觉深度和层次感。开发者需要了解颜色的组合原理,以便在不同的视觉元素中应用这些效果。

6.1.1 颜色混合的基础知识

颜色混合是指在Canvas上绘制时,新绘制的颜色与原有颜色根据一定算法结合的过程。在Android中,可以通过 PorterDuff.Mode 指定不同的混合模式。例如:

// 例子:设置颜色混合模式
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));

上面的代码设置了Porter-Duff混合模式为 SRC_OVER ,这是默认模式,表示新绘制的颜色会覆盖原有颜色。

6.1.2 渐变效果的实现方法

渐变效果可以给UI元素带来平滑的色彩过渡,常用于背景、按钮或图形的填充。实现渐变效果,通常会用到 LinearGradient RadialGradient 类。例如,创建一个垂直线性渐变:

// 例子:创建垂直线性渐变
Shader shader = new LinearGradient(0, 0, 0, 200,
    new int[]{0xFFAAAAFF, 0xFF0000FF, 0xFFAAAAFF},
    null,
    Shader.TileMode.CLAMP);
paint.setShader(shader);

这段代码创建了一个从紫色到蓝色再到紫色的垂直渐变效果,通过 setShader 方法应用到了 Paint 对象上。

6.2 图形阴影的添加

阴影可以给UI元素带来立体感,是增强视觉效果的重要手段。在Android中,可以使用 Paint.setShadowLayer 来为图形添加阴影效果。

6.2.1 阴影实现的技术细节

为了创建阴影,可以调用 setShadowLayer 方法,并指定阴影的半径、X和Y轴的偏移量、以及阴影的颜色。例如:

// 例子:设置阴影效果
paint.setShadowLayer(10f, 5f, 5f, Color.GRAY);

这里设置了一个阴影,其中阴影半径为10像素,阴影在X和Y轴上各偏移5像素,阴影颜色为灰色。

6.2.2 阴影效果的调整与优化

调整阴影效果包括改变阴影的颜色、透明度、模糊度和偏移量等。为了优化性能,应避免在频繁重绘的组件上设置阴影,或者使用更高效的阴影实现方式,例如使用9-patch图片或者在运行时只在关键帧上绘制阴影。

6.3 动态更新UI与性能优化

在实现动态效果时,合理地更新UI和进行性能优化是保证应用流畅运行的关键。

6.3.1 使用Handler进行UI更新

使用 Handler 可以让UI更新操作在主线程上按顺序执行。这对于定时任务或动画帧更新非常有用。例如:

// 例子:使用Handler来更新UI
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        // 更新UI的代码
    }
};
mainHandler.post(myRunnable);

6.3.2 利用postInvalidate()提升响应速度

在自定义View中,调用 postInvalidate() 方法可以异步地请求View重绘,适用于动画或周期性更新UI的场景。它比直接调用 invalidate() 更快,因为它不会立即重绘视图。

// 例子:异步请求重绘视图
myCustomView.postInvalidate();

6.4 实际应用案例分析

通过结合以上技术点,我们可以创建丰富的动态效果和优化用户体验。

6.4.1 制作具有动态效果的自定义视图

在实际项目中,开发者可以根据具体需求设计和实现具有动态效果的自定义视图。例如,一个具有旋转、渐变背景和阴影的圆形进度条。这将涉及到 Canvas Paint Matrix Handler 等多个类的综合应用。

6.4.2 仪表盘绘制案例的深入分析

另一个高级案例是实现一个动态仪表盘,这通常需要结合 Canvas 绘图和动画框架(如 ObjectAnimator )来实现指针的动态变化。在实现过程中,还需要考虑性能优化,如使用 View.postInvalidateOnAnimation() 确保动画流畅运行。

通过以上各节的介绍,我们已经全面了解了在Android中实现高级视觉效果和动态UI的技术手段。在实际应用中,开发者应根据具体需求灵活运用这些技术,并通过不断优化来确保应用的性能。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Android的Canvas工具允许开发者在屏幕上绘制图形,创建丰富视觉效果和交互体验。本案例"DrawDialDemo"深入解析了如何通过Canvas实现自定义画图,从创建画布到使用 onDraw() 方法,再到旋转图形和动态更新UI等高级技巧。通过实例演示,本案例详细讲解了仪表盘绘制的整个过程,包括指针、刻度线和数字等元素的绘制,以及如何在非UI线程中更新画布。掌握了这些技巧后,开发者将能制作出更多复杂的自定义视图,并进一步提升在Android图形编程方面的能力。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值