安卓核心技术高级——动画与图形

动画类型
参考博客:https://www.cnblogs.com/ldq2016/p/5407061.html
Android系统提供了很多丰富的API去实现UI的2D与3D动画,最主要的划分可以分为如下几类:

  • View Animation: 视图动画在古老的Android版本系统中就已经提供了,只能被用来设置View的动画。

  • Drawable Animation: 这种动画(也叫Frame动画、帧动画)其实可以划分到视图动画的类别,专门用来一个一个的显示Drawable的resources,就像放幻灯片一样。

  • Property Animation: 属性动画只对Android 3.0(API 11)以上版本的Android系统才有效,这种动画可以设置给任何Object,包括那些还没有渲染到屏幕上的对象。这种动画是可扩展的,可以让你自定义任何类型和属性的动画。

属性动画(Property)

上下翻转:

	public void click(View view){
       ObjectAnimator.ofFloat(view,"rotationX",0.0f,360f).setDuration(500).start();
    }

在这里插入图片描述

组合多个动画

public void click(View view){
        PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("alpha",1f,0f,1f);
        PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("scaleX",1f,0f,1f);
        PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("scaleY",1f,0f,1f);
        ObjectAnimator.ofPropertyValuesHolder(view,p1,p2,p3).setDuration(3000).start();
    }

在这里插入图片描述

下落动画

public void musicStackClick(View view){
        final View v = view;
        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);

        ValueAnimator va = ValueAnimator.ofFloat(view.getY(),dm.heightPixels,view.getY()).setDuration(500);
        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                v.setTranslationY((Float) animation.getAnimatedValue());
            }
        });
        va.start();
    }

在这里插入图片描述

补间动画(View Animation)

Tween动画

Tween动画可以对对象进行缩小,放大,旋转,渐变,位移等操作,针对这不同的操作,Android提供了相应的接口。
有四种:

  • AlphaAnimation(透明度动画)
  • TranslateAnimation(平移动画)
  • ScaleAnimation(缩放动画)
  • RotateAnimation(旋转动画)

在res/anim目录下创建xml。
渐变:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:fillEnabled="true">
    <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="3000"/>
</set>
public void alphaClick(View view){
        Animation alpha = AnimationUtils.loadAnimation(this,
                R.anim.alpha_anim);
        imageView.startAnimation(alpha);
    }

在这里插入图片描述

旋转:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:fillEnabled="true">

    <rotate
        android:duration="2000"
        android:fromDegrees="0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="720"/>

    <rotate
        android:duration="2000"
        android:fromDegrees="360"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="2000"
        android:toDegrees="0"/>
</set>

public void rotateClick(View view){
        Animation alpha = AnimationUtils.loadAnimation(this,
                R.anim.anim_rotate);
        imageView.startAnimation(alpha);
    }

在这里插入图片描述
缩放:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:fillEnabled="true">
    <scale
        android:duration="2000"
        android:fillAfter="true"
        android:fromXScale="1"
        android:fromYScale="1"
        android:interpolator="@android:anim/decelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:toXScale="2.0"
        android:toYScale="2.0" />
</set>

public void scaleClick(View view){
        Animation alpha = AnimationUtils.loadAnimation(this,
                R.anim.anim_scale);
        imageView.startAnimation(alpha);
    }

在这里插入图片描述
平移:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:fillEnabled="true">
    <translate
        android:duration="2000"
        android:fillAfter="true"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:toXDelta="860"
        android:toYDelta="0"/>
</set>
public void translateClick(View view){
        Animation alpha = AnimationUtils.loadAnimation(this,
                R.anim.translate_anim);
        imageView.startAnimation(alpha);
    }

在这里插入图片描述

Frame动画

Frame动画是一系列图片按照顺序展示的,像gif图一样,也被称作逐帧动画,它的实现方式也非常简单,可以定义在xml中。

帧动画(Drawable Animation)


import android.graphics.drawable.AnimationDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.widget.ImageView;

public class Main2Activity extends AppCompatActivity {

    private ImageView image_frame;
    private AnimationDrawable anim;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        image_frame = (ImageView)findViewById(R.id.image_frame);
    }

    //开始帧动画
    public void startClick(View view){
        if (anim == null) {
            image_frame.setBackgroundResource(R.drawable.frame_anim);
            anim = (AnimationDrawable) image_frame.getBackground();
        }
        anim.start();
    }

    //停止帧动画
    public void stopClick(View view){
        if (anim != null && anim.isRunning()) { //如果正在运行,就停止
            anim.stop();
        }
    }

}

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@drawable/b" android:duration="500" />
    <item android:drawable="@drawable/c" android:duration="500" />
    <item android:drawable="@drawable/d" android:duration="500" />
    <item android:drawable="@drawable/e" android:duration="500" />

    <item android:drawable="@drawable/e" android:duration="500" />
    <item android:drawable="@drawable/d" android:duration="500" />
    <item android:drawable="@drawable/c" android:duration="500" />
    <item android:drawable="@drawable/b" android:duration="500" />
</animation-list>

在这里插入图片描述

监听动画的事件

public void click(View view){
        final View v = view;

        ObjectAnimator oa = ObjectAnimator.ofFloat(view,"alpha",1f,0f).setDuration(1000);
//        oa.addListener(new Animator.AnimatorListener() {
//            @Override
//            public void onAnimationStart(Animator animation) {
//                //动画开始`
//            }
//
//            @Override
//            public void onAnimationEnd(Animator animation) {
//                //动画结束
//                ViewGroup viewGroup = (ViewGroup) v.getParent();
//                if (viewGroup!=null){
//                    viewGroup.removeView(v);
//                    System.out.println("removed.");
//                }
//            }
//
//            @Override
//            public void onAnimationCancel(Animator animation) {
//                //取消动画
//
//            }
//
//            @Override
//            public void onAnimationRepeat(Animator animation) {
//                //重复
//
//            }
//        });
        oa.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                ViewGroup viewGroup = (ViewGroup) v.getParent();
                if (viewGroup!=null){
                    viewGroup.removeView(v);
                    System.out.println("removed.");
                }
            }
        });
        oa.start();
    }

在这里插入图片描述

AnimatorSet

	public void click(View view){
        ObjectAnimator a1 = ObjectAnimator.ofFloat(view,"translationX",0f,200f);
        ObjectAnimator a2 = ObjectAnimator.ofFloat(view,"translationY",0f,200f);
        ObjectAnimator a3 = ObjectAnimator.ofFloat(view,"rotation",0f,200f);
        AnimatorSet set = new AnimatorSet();
        set.setDuration(1000);
//        set.playTogether(a1,a2,a3);//同时执行
//        set.setStartDelay(300);//延迟
        set.playSequentially(a1,a2,a3); //顺序执行

        //自定义组合执行
//        set.play(a1).with(a2);
//        set.play(a3).after(a2);
        set.start();
    }

同时执行:
在这里插入图片描述
顺序执行:
在这里插入图片描述
自定义组合执行
在这里插入图片描述

插值器

参考博客:https://blog.csdn.net/qq_33706840/article/details/81475879

  • AccelerateDecelerateInterpolator 变化率开始和结束缓慢但在中间加速。
  • AccelerateInterpolator 变化率开始缓慢然后加速。
  • AnticipateInterpolator 变化开始向后然后向前。
  • AnticipateOvershootInterpolator 变化开始向后,向前晃动并超过目标值,然后最终返回到最终值。
  • BounceInterpolator 变化在结束时反弹。
  • CycleInterpolator 动画重复指定的周期数。
  • DecelerateInterpolator 变化率快速开始然后减速。
  • LinearInterpolator 变化率恒定。
  • OvershootInterpolator 变化向前晃动并超过一个值,然后返回。
  • TimeInterpolator 一个允许您实现自己的插补器的接口。

反弹效果

	public void click(View view){
        ObjectAnimator a1 = ObjectAnimator.ofFloat(view,"translationX",0f,200f);
        ObjectAnimator a2 = ObjectAnimator.ofFloat(view,"translationY",0f,200f);
        ObjectAnimator a3 = ObjectAnimator.ofFloat(view,"rotation",0f,200f);
        AnimatorSet set = new AnimatorSet();
        set.setDuration(1000);
        set.setInterpolator(new BounceInterpolator());//反弹效果

        set.play(a1).with(a3);
        set.play(a2).after(a3);
        set.start();
    }

在这里插入图片描述

动画菜单案例


import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;

import java.util.ArrayList;

public class Main3Activity extends AppCompatActivity implements View.OnClickListener{

    private int[] res = {
            R.id.image1,
            R.id.image2,
            R.id.image3,
            R.id.image4,
            R.id.image5,
            R.id.image6,
            R.id.image7,
            R.id.image8
    };
    private ArrayList<ImageView> list = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        for (int i = 0 ;i<res.length;i++){
            ImageView imageView = (ImageView)findViewById(res[i]);
            imageView.setOnClickListener(this);
            list.add(imageView);
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.image1:
                openMenu();
                break;
        }
    }

    //打开菜单
    private void openMenu() {
        for (int i = 1; i < res.length; i++) {
            ObjectAnimator a1 = ObjectAnimator.ofFloat(list.get(i),"translationX",0,150*i).setDuration(300);
            ObjectAnimator a2 = ObjectAnimator.ofFloat(list.get(i),"translationY",0,100*i).setDuration(300);

            a1.setInterpolator(new BounceInterpolator());
            a2.setInterpolator(new BounceInterpolator());
            a1.start();
            a2.start();
        }
    }


}

在这里插入图片描述

画布绘制

绘制图形

public class Main4Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }
}
package com.example.animatorapplication.graphics;

import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
import android.graphics.*;

public class MyView extends View {
    public MyView(Context context) {
        super(context);
    }

    //会在组件加载时调用
    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);

        canvas.drawColor(Color.WHITE);
        Paint paint = new Paint();//创建画笔
        //去锯齿
        paint.setAntiAlias(true);

        //设置样式,空心STROKE,实心FILL
        paint.setStyle(Paint.Style.STROKE);
        //画笔颜色
        paint.setColor(Color.RED);
        //设置画笔宽度
        paint.setStrokeWidth(3);
        //画空心圆(参数:圆心x,圆心y,半径,画笔)
        canvas.drawCircle(40,40,30,paint);
        //画空心正方形
        canvas.drawRect(10,90,70,150,paint);
        //画空心长方形
        canvas.drawRect(10,170,70,200,paint);
        //画空心椭圆
        RectF re = new RectF(10,220,70,250);
        canvas.drawOval(re,paint);
        //画一个空心三角形
        Path path = new Path();
        path.moveTo(10,330);
        path.lineTo(70,330);
        path.lineTo(40,270);
        path.close();
        canvas.drawPath(path,paint);
        //画一个空心梯形
        Path path1 = new Path();
        path1.moveTo(10,410);
        path1.lineTo(40,410);
        path1.lineTo(55,350);
        path1.lineTo(25,350);
        path1.close();
        canvas.drawPath(path1,paint);

        //设置样式,空心STROKE,实心FILL
        paint.setStyle(Paint.Style.FILL);
        //画笔颜色
        paint.setColor(Color.BLUE);
        //设置画笔宽度
        paint.setStrokeWidth(3);
        //画圆(参数:圆心x,圆心y,半径,画笔)
        canvas.drawCircle(120,40,30,paint);
        //画正方形
        canvas.drawRect(90,90,150,150,paint);
        //画长方形
        canvas.drawRect(90,170,150,200,paint);
        //画椭圆
        RectF re2 = new RectF(90,220,150,250);
        canvas.drawOval(re2,paint);
        //画一个三角形
        Path path2 = new Path();
        path2.moveTo(90,330);
        path2.lineTo(150,330);
        path2.lineTo(120,270);
        path2.close();
        canvas.drawPath(path2,paint);
        //画一个梯形
        Path path3 = new Path();
        path3.moveTo(90,410);
        path3.lineTo(120,410);
        path3.lineTo(135,350);
        path3.lineTo(105,350);
        path3.close();
        canvas.drawPath(path3,paint);

        /**
         * 绘制渐变色
         * 参数(前四个值,渐变的初始位置,起始x,y轴,结束x,y轴,
         *      渐变的颜色组合new int[]{},
         *      定义每个颜色的占比,
         *      平铺方式:镜像MIRROR)
         */
        Shader mShader = new LinearGradient(0,0,100,100,new int[]{
                Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW},null,
                Shader.TileMode.REPEAT);
        paint.setShader(mShader);
        paint.setStrokeWidth(3);
        //画圆(参数:圆心x,圆心y,半径,画笔)
        canvas.drawCircle(200,40,30,paint);
        //画正方形
        canvas.drawRect(170,90,230,150,paint);
        //画长方形
        canvas.drawRect(170,170,230,200,paint);
        //画椭圆
        RectF re3 = new RectF(170,220,230,250);
        canvas.drawOval(re3,paint);
        //画一个三角形
        Path path4 = new Path();
        path4.moveTo(170,330);
        path4.lineTo(230,330);
        path4.lineTo(200,270);
        path4.close();
        canvas.drawPath(path4,paint);
        //画一个梯形
        Path path5 = new Path();
        path5.moveTo(170,410);
        path5.lineTo(200,410);
        path5.lineTo(215,350);
        path5.lineTo(185,350);
        path5.close();
        canvas.drawPath(path5,paint);
        canvas.drawText("圆形",240,50,paint);
        canvas.drawText("正方形",240,120,paint);
        canvas.drawText("长方形",240,190,paint);
        canvas.drawText("椭圆形",240,250,paint);
        canvas.drawText("三角形",240,320,paint);
        canvas.drawText("梯形",240,390,paint);
    }
}

在这里插入图片描述

绘制图片

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;

import com.example.animatorapplication.R;

public class MyImageView extends View {
    public MyImageView(Context context) {
        super(context);
    }

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

        Paint p = new Paint();

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.a);
        canvas.drawBitmap(bitmap,0,0,p);
    }
}

在这里插入图片描述

SurfaceView

SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器。

传统View及其派生类的更新只能在UI线程,然而UI线程还同时处理其他交互逻辑,这就无法保证View更新的速度和帧率了,而SurfaceView可以用独立的线程进行绘制,因此可以提供更高的帧率。

例如游戏,摄像头取景等场景就比较适合SurfaceView来实现。
写入到Surface的内容可以直接复制到显存从而显示出来,这使得显示速度会非常快。


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceView;
import android.view.SurfaceHolder;

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {

    private SurfaceHolder holder;
    private MyThread thread;

    public MySurfaceView(Context context) {
        super(context);
        holder = this.getHolder();
        holder.addCallback(this);
    }

    class MyThread implements Runnable{

        private SurfaceHolder holder;
        public boolean isRun = true;
        public MyThread(SurfaceHolder holder){
            this.holder = holder;
            isRun = true;
        }

        @Override
        public void run() {
            int count = 0;
            Canvas canvas= null;
            while (isRun){
                try {
                    synchronized (holder){
                        canvas = holder.lockCanvas();
                        canvas.drawColor(Color.WHITE);
                        Paint p = new Paint();
                        p.setColor(Color.RED);
                        p.setStyle(Paint.Style.FILL);
                        p.setAntiAlias(true);
                        canvas.drawRect(60,60,360,360,p);
                        p.setTextSize(50);
                        canvas.drawText("当前是第"+(count++)+"秒",60,450,p);

                        Thread.sleep(1000);
                    }
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    holder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread = new MyThread(holder);
        thread.isRun = true;
        new Thread(thread).start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        thread.isRun = false;
    }
}

在这里插入图片描述

SurfaceView视频

先将文件放入sdcard
在这里插入图片描述
加权限

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEM" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;

import com.example.animatorapplication.R;

import java.io.IOException;

public class VideoActivity extends AppCompatActivity implements SurfaceHolder.Callback {

    private SurfaceView surfaceView;
    private SurfaceHolder holder;
    private MediaPlayer mp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video);
        surfaceView = (SurfaceView)findViewById(R.id.surfaceView);
        holder = surfaceView.getHolder();
        holder.addCallback(this);
        holder.setFixedSize(320,220);
    }

    public void startClick(View view) {
        mp.start();
    }

    public void pauseClick(View view) {
        mp.pause();
    }

    public void stopClick(View view) {
        mp.stop();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mp = new MediaPlayer();
        mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mp.setDisplay(holder);
        String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+"/jj.mp4";
//        raw:/storage/emulated/0/Download/jj.mp4
        System.out.println(path);
        try {
            mp.setDataSource(path);//播放视频源
            mp.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mp!=null){
            if (mp.isPlaying()){
                mp.stop();
                mp.release();
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mp!=null){
            if (mp.isPlaying()){
                mp.stop();
                mp.release();
            }
        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".graphics.VideoActivity"
    android:padding="16dp">

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="485dp"
        android:layout_height="300dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="播放"
        android:onClick="startClick"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/button2"
        app:layout_constraintTop_toBottomOf="@+id/surfaceView" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="暂停"
        android:onClick="pauseClick"
        app:layout_constraintLeft_toRightOf="@+id/button1"
        app:layout_constraintRight_toLeftOf="@+id/button3"
        app:layout_constraintTop_toBottomOf="@+id/surfaceView" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="停止"
        android:onClick="stopClick"
        android:layout_marginTop="8dp"
        app:layout_constraintLeft_toRightOf="@+id/button2"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/surfaceView"
        tools:layout_editor_absoluteY="324dp" />
</android.support.constraint.ConstraintLayout>

在这里插入图片描述

Draw 9-patch

参考博客:http://www.cnblogs.com/qianxudetianxia/archive/2011/04/17/2017591.html
与传统的png 格式图片相比, 9.png 格式图片在图片四周有一圈一个像素点组成的边沿,该边沿用于对图片的可扩展区和内容显示区进行定义。 这种格式的图片在android 环境下具有自适应调节大小的能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值