Android 自定义ViewGroup实现图片滑动显示

Android 同时被 2 个专栏收录
26 篇文章 0 订阅
22 篇文章 0 订阅

先看效果图:

本篇我们分为三部分来讲:

  • 图片的滑动实现
  • 动态改变缩放值和透明度
  • 实现右下角滚轮滑动
  • 补充

一、图片的滑动实现

在上图中,一个屏幕里同时可以存在三张图片,这意味着每次滑动实际只滑动了1/3的屏幕宽度。当然,我们也可以只让屏幕显示一张图片,或是同时显示5张等等。我们应该设立一个变量onPagerNum来表示当前屏幕显示的图片数量

在本文中我们令onPagerNum=3,即一个屏幕出现三张图片。下面我们要计算每个图片应分配的最大宽度,先来看下图:

从图中就能很明显的得出结论,每张图片的最大宽度viewWidth=屏幕宽度/onPagerNum-padding*2

我们来添加ImageView,并重写onLayout:

private ImageView[] images;
//获取外界传来的图片
public void setImages(int[] imgs){
    this.images=new ImageView[imgs.length];
    if(onPagerNum>1)setBlankView();
    for(int i=0;i<images.length;i++){
        images[i]=new ImageView(getContext());
        images[i].setImageResource(imgs[i]);
        this.addView(images[i]);
    }
    setImgsTypes(1f,nowPosition+1);
    //......
}

//设置空白的View
private void setBlankView(){
    View view=new View(getContext());
    this.addView(view);
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    int childCount=getChildCount();
    for(int i=0;i<childCount;i+=onPagerNum){
        for(int j=0;j<onPagerNum;j++){
            if(i+j>=childCount)break;
            View childView=getChildAt(i+j);
            //layout:相对于父布局的位置
            childView.layout(i/onPagerNum*getWidth()+j*getWidth()/onPagerNum+paddingPic ,0 ,i/onPagerNum*getWidth()+(j+1)*getWidth()/onPagerNum-paddingPic ,getHeight());
        }
    }
}

我们把六张图片前后分成两组

i/onPagerNum*getWidth():表示当前在哪一组

j*getWidth()/onPagerNum:表示在一组中的哪一个

为什么要添加空白的View:当我们移动到第一张图片时,第一张图片在中间,左边是没有图片的,所以要用空白View代替

 接下来,我们要重写onTouchEvent,并调用GestureDetector.onTouchEvent()来实现页面滑动

@Override
public boolean onTouchEvent(MotionEvent event) {
    //将触摸事件传递手势识别器
    gestureDetector.onTouchEvent(event);
    return true;
}

private GestureDetector gestureDetector=new GestureDetector(new GestureDetector.SimpleOnGestureListener(){
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2,
                            float distanceX, float distanceY) {
        //X方向滑动,view跟着滑动
        scrollBy((int)distanceX/onPagerNum,0);
        return super.onScroll(e1, e2, distanceX, distanceY);
    }
});

注意scrollBy((int)distanceX/onPagerNum,0)这个方法中的第一个参数,由于我们默认是滑动一整个屏幕的,但现在只需要滑动1/onPagerNum个屏幕,所以要除以一个onPagerNum

当前实现的效果如下:

然后我们来实现滑动一定距离松手后,自动滑动到下一张图片的功能

因为我们现在一次只滑动1/3个屏幕,所以我们立一个规定:

我们如果一次性滑动的距离超过了1/3屏幕的1/3,那么我们松手后,就会自动滑动到前一张,或者后一张,否则返回到当前图片

代码实现如下:

private ImageView[] images;
private Scroller mScroller; //用于平滑过渡
private int nowPosition=0;//当前显示哪一张图片
@Override
public boolean onTouchEvent(MotionEvent event) {
    if(images==null)return false;
    //将触摸事件传递手势识别器
    gestureDetector.onTouchEvent(event);
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            lastPosX=event.getX();
            break;
        case MotionEvent.ACTION_MOVE:
            isMoving=true;
            if(lastPosX<event.getX()){  //手指向右滑
                nowPosition=(getScrollX()+getWidth()/(3*onPagerNum))/(getWidth()/onPagerNum);
            }else{      //手指向左滑
                nowPosition=(getScrollX()+2*getWidth()/(3*onPagerNum))/(getWidth()/onPagerNum);
            }
            if(nowPosition>=images.length)nowPosition=images.length-1;
            if(nowPosition<0)nowPosition=0;
            break;
        case MotionEvent.ACTION_UP:
            isMoving=false;
            move();
            break;
    }
    return true;
}

//移动页面
private void move(){
    mScroller.startScroll(getScrollX(),0,nowPosition*getWidth()/onPagerNum-getScrollX(),0);
    invalidate();   //使用invalidate会执行回调方法computeScroll
}

@Override
public void computeScroll() {
    if (mScroller.computeScrollOffset()) {
        scrollTo(mScroller.getCurrX(), 0);
        postInvalidateDelayed(10);
    }
}

mScroller.startScroll():我们松手后,不希望一下子跳到下一张图片,而是有一个平滑过渡的移动,就需要用到Scroller类

 当前实现的效果如下:

 

二、动态改变缩放值和透明度

在第一部分中,我们实现了图片的滑动,但是显然只有单纯的滑动,整体效果并不柔和与美观。所以本部分,我们来加上一些图片的动画效果

依照我们的惯例,当我们在滑动到下一张的过程中,前一张的图片应该逐渐变小,变得透明,而后一张的图片逐渐变大,变得不透明。当我们松手后,下一张图片完全显示,上一张图片缩放到最小比例

假设默认情况下,显示在中间的图片透明度为无透明,缩放比例为1;它左右两边的图片透明度为1~255中的100,缩放比例为0.5

我们需要一个变量来实时改变透明度和缩放比例。来设想一下:手指按下去的时候,会产生一个坐标点,将它的x坐标记为lastPosX;手指向左移动,每时每刻都会产生移动后的位置坐标,即event.getX();我们用event.getX()/lastPosX会得到一个比例值,这个比例值就可以充当我们动态改变图片属性值的变量。(手指向右滑动就是lastPosX/event.getX())

代码表示如下:

@Override
public boolean onTouchEvent(MotionEvent event) {
    //将触摸事件传递手势识别器
    gestureDetector.onTouchEvent(event);
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            lastPosX=event.getX();
            break;
        case MotionEvent.ACTION_MOVE:
            //......
            if(lastPosX!=0&&event.getX()!=0){
                if(lastPosX>event.getX())setImgsTypes(event.getX()/lastPosX,pastPosition+1);
                else setImgsTypes(lastPosX/event.getX(),pastPosition-1);
            }
            break;
        case MotionEvent.ACTION_UP:
            move();
            break;
    }
    return true;
}

//移动页面
private void move(){
    //如果上一次位置比当前位置小,说明是移动到了后一张图片
    if(pastPosition<nowPosition){
        pastPosition=nowPosition;
        setImgsTypes(1f,nowPosition+1);
    //如果上一次位置比当前位置大,说明是移动到了前一张图片
    }else{
        pastPosition=nowPosition;
        setImgsTypes(1f,nowPosition-1);
    }
    //......
}

//获取外界传来的图片
public void setImages(int[] imgs){
    //......
    setImgsTypes(1f,nowPosition+1);
}

//设置图片属性
/*
* changePer:动态改变图片属性的比例
* nextPos:下一张图片的下标
* */
private void setImgsTypes(float changePer,int nextPos){
    if(images!=null){
        for(int i=0;i<images.length;i++){
            images[i].setImageAlpha(100);
            images[i].setScaleX(0.5f);
            images[i].setScaleY(0.5f);
        }
        //改变前一张图的属性
        if(255*changePer>=100)images[pastPosition].setImageAlpha((int)(255*changePer));
        if(1f*changePer>=0.5f){
            images[pastPosition].setScaleX(1f*changePer);
            images[pastPosition].setScaleY(1f*changePer);
        }
        //改变当前图的属性
        if(nextPos < images.length && nextPos>=0){
            images[nextPos].setImageAlpha(100+(int)(155*(1-changePer)));
            images[nextPos].setScaleX(0.5f+0.5f*(1-changePer));
            images[nextPos].setScaleY(0.5f+0.5f*(1-changePer));
        }
    }
}

三、实现右下角滚轮滑动

滚轮可以由外界自定义实现,内部只需要提供滑动的监听器:

public interface OnScrollListener {
    /**
     * offsetPer:x轴滑动的距离比上屏幕宽度
     */
    void onScrolled(float offsetPer);
    void onSelected(int position);
}
private OnScrollListener onScrollListener;
public void setOnPageScrollListener(OnScrollListener onScrollListener){
    this.onScrollListener=onScrollListener;
}

外部Activity中创建该监听:

public class MyViewPagerAct extends AppCompatActivity {
    private MyViewPagerViewGroup vpager;
    private int[] images = {R.mipmap.arti, R.mipmap.avatar, R.mipmap.butterfly, R.mipmap.head,R.mipmap.carousel_1,R.mipmap.bg_article};
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_viewpager);
        init();
    }

    private void init(){
        vpager=findViewById(R.id.vpager);
        vpager.setOnPageScrollListener(new MyViewPagerViewGroup.OnScrollListener() {
            @Override
            public void onScrolled(float offsetPer) {

            }
            @Override
            public void onSelected(int position) {

            }
        });
        vpager.setImages(images);
    }
}

当前滑动的小球和固定的灰色小球创建的方式不同,我们在XML布局文件中添加滑动小球的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.hualinfo.myviewtext.MyViewPagerViewGroup
        android:id="@+id/vpager"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:layout_centerInParent="true"/>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="20dp"
        android:layout_marginRight="60dp">

        <LinearLayout
            android:id="@+id/ll_p"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"></LinearLayout>

        <View
            android:id="@+id/view_point"
            android:layout_width="10dp"
            android:layout_height="10dp"
            android:layout_marginLeft="5dp"
            android:background="@drawable/black_point"/>
    </RelativeLayout>
</RelativeLayout>

我们在代码里动态生成固定的灰色小球:

public class MyViewPagerAct extends AppCompatActivity {
    private LinearLayout ll_p;
    private MyViewPagerViewGroup vpager;
    private int[] images = {R.mipmap.arti, R.mipmap.avatar, R.mipmap.butterfly, R.mipmap.head,R.mipmap.carousel_1,R.mipmap.bg_article};
    private View view_point;
    private int pointMargin,pointDiameter;  //滑动点之间的边距,滑动点的直径
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_viewpager);
        init();
    }

    private void init(){
        pointMargin=px2dp(5);
        pointDiameter=px2dp(10);
        view_point=findViewById(R.id.view_point);
        //......
        ll_p=findViewById(R.id.ll_p);
        addView();
    }

    private void addView(){ //右下角生成滑动点
        LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(pointDiameter,pointDiameter);
        params.leftMargin=pointMargin;
        for(int i=0;i<images.length;i++){
            View view=new View(this);
            view.setBackground(getDrawable(R.drawable.light_black_point));
            view.setLayoutParams(params);
            ll_p.addView(view);
        }
    }

    private int px2dp(float spValue){
        return (int)(getResources().getDisplayMetrics().scaledDensity*spValue+0.5f);
    }
}

滑动小球会随着图片的移动而移动,即在onScroll方法中改变小球的leftMargin左边距来实现移动效果

public class MyViewPagerAct extends AppCompatActivity {
    private MyViewPagerViewGroup vpager;
    private View view_point;
    private int pointMargin,pointDiameter;  //滑动点之间的边距,滑动点的直径
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_viewpager);
        init();
    }

    private void init(){
        pointMargin=px2dp(5);
        pointDiameter=px2dp(10);
        vpager=findViewById(R.id.vpager);
        view_point=findViewById(R.id.view_point);
        vpager.setOnPageScrollListener(new MyViewPagerViewGroup.OnScrollListener() {
            @Override
            public void onScrolled(float offsetPer) {
                float leftMargin=offsetPer*(pointMargin+pointDiameter)+pointMargin;
                RelativeLayout.LayoutParams params=(RelativeLayout.LayoutParams)view_point.getLayoutParams();
                params.leftMargin=(int) leftMargin;
                view_point.setLayoutParams(params);
            }
            @Override
            public void onSelected(int position) {

            }
        });
        vpager.setImages(images);
        //......
    }

    private int px2dp(float spValue){
        return (int)(getResources().getDisplayMetrics().scaledDensity*spValue+0.5f);
    }
}

在自定义ViewGroup内部调用监听方法:

@Override
public boolean onTouchEvent(MotionEvent event) {
    //将触摸事件传递手势识别器
    gestureDetector.onTouchEvent(event);
    switch (event.getAction()){
        case MotionEvent.ACTION_MOVE:
            //......            
            if(onScrollListener!=null)
                onScrollListener.onScrolled(getScrollX()*1.0f/getWidth()*onPagerNum);
            break;
    }
    return true;
}
//移动页面
private void move(){
    //......
    if (onScrollListener != null) {
        onScrollListener.onSelected(nowPosition);
    }
}

@Override
public void computeScroll() {
    //......
    if(onScrollListener!=null)onScrollListener.onScrolled(getScrollX()*1.0f/getWidth()*onPagerNum);
}

getScrollX()*1.0f/getWidth()*onPagerNum:getScrollX()*1.0f/getWidth()表示已滑动的距离比上ViewGroup宽度,最后乘以onPagerNum代表的是每滑过1/3的ViewGroup宽度,小球就移动到下一个默认的灰球位置。

这样子小球就能随着图片的滑动而滑动了。

 四、补充

如果我们想让图片每隔一段时间自动滑动到下一张,可以按以下步骤实现:

1、创建TimerTask和Timer类

Timer moveTimer=new Timer();
TimerTask moveTask=new TimerTask() {    //创建一个任务,每隔一段时间自动滑动到下一页
    @Override
    public void run() {
        if(!isMoving){    //手指是否在移动屏幕
            nowPosition=(nowPosition+1)%images.length;
            move();
        }
    }
};

2、在外部设置图片的时间,开启TimerTask任务线程,并每隔一段时间执行一次

//获取外界传来的图片
public void setImages(int[] imgs){
    //......
    moveTimer.schedule(moveTask,4000,4000);
}


下面是自定义ViewGroup的源码:

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Scroller;
import java.util.Timer;
import java.util.TimerTask;
public class MyViewPagerViewGroup extends ViewGroup {
    private ImageView[] images;
    private float lastPosX;   //最后手指在屏幕的x坐标
    private Scroller mScroller; //用于平滑过渡
    private int onPagerNum=3;      //屏幕中出现的图片数量
    private int paddingPic=80/onPagerNum;
    private int nowPosition=0,pastPosition=0;  //当前显示哪一张图片,上一次显示哪一张图片
    private boolean isMoving=false; //是否手指正在移动
    public MyViewPagerViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init(){
        mScroller=new Scroller(getContext());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            //如果是view:触发view的测量;如果是ViewGroup,触发测量ViewGroup中的子view
            measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount=getChildCount();
        for(int i=0;i<childCount;i+=onPagerNum){
            for(int j=0;j<onPagerNum;j++){
                if(i+j>=childCount)break;
                View childView=getChildAt(i+j);
                //layout:相对于父布局的位置
                childView.layout(i/onPagerNum*getWidth()+j*getWidth()/onPagerNum+paddingPic,0,i/onPagerNum*getWidth()+(j+1)*getWidth()/onPagerNum-paddingPic,getHeight());
            }
        }
    }

    private GestureDetector gestureDetector=new GestureDetector(new GestureDetector.SimpleOnGestureListener(){
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                                float distanceX, float distanceY) {
            //相对滑动:X方向滑动多少距离,view就跟着滑动多少距离
            scrollBy((int)distanceX/onPagerNum,0);
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    });

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(images==null)return false;
        //将触摸事件传递手势识别器
        gestureDetector.onTouchEvent(event);
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                lastPosX=event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                isMoving=true;
                if(lastPosX<event.getX()){  //手指向右滑
                    nowPosition=(getScrollX()+getWidth()/(3*onPagerNum))/(getWidth()/onPagerNum);
                }else{      //手指向左滑
                    nowPosition=(getScrollX()+2*getWidth()/(3*onPagerNum))/(getWidth()/onPagerNum);
                }
                if(nowPosition>=images.length)nowPosition=images.length-1;
                if(nowPosition<0)nowPosition=0;
                if(onScrollListener!=null)onScrollListener.onScrolled(getScrollX()*1.0f/getWidth()*onPagerNum);
                if(lastPosX!=0&&event.getX()!=0){
                    if(lastPosX>event.getX())setImgsTypes(event.getX()/lastPosX,pastPosition+1);
                    else setImgsTypes(lastPosX/event.getX(),pastPosition-1);
                }
                break;
            case MotionEvent.ACTION_UP:
                isMoving=false;
                move();
                break;
        }
        return true;
    }

    //移动页面
    private void move(){
        //如果上一次位置比当前位置小,说明是移动到了后一张图片
        if(pastPosition<nowPosition){
            pastPosition=nowPosition;
            setImgsTypes(1f,nowPosition+1);
        //如果上一次位置比当前位置大,说明是移动到了前一张图片
        }else{
            pastPosition=nowPosition;
            setImgsTypes(1f,nowPosition-1);
        }
        mScroller.startScroll(getScrollX(),0,nowPosition*getWidth()/onPagerNum-getScrollX(),0);
        invalidate();   //使用invalidate会执行回调方法computeScroll
        if (onScrollListener != null) {
            onScrollListener.onSelected(nowPosition);
        }
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), 0);
            if(onScrollListener!=null)onScrollListener.onScrolled(getScrollX()*1.0f/getWidth()*onPagerNum);
            postInvalidateDelayed(10);
        }
    }

    public interface OnScrollListener {
        /**
         * offsetPer:x轴滑动的距离比上屏幕宽度
         */
        void onScrolled(float offsetPer);
        void onSelected(int position);
    }
    private OnScrollListener onScrollListener;
    public void setOnPageScrollListener(OnScrollListener onScrollListener){
        this.onScrollListener=onScrollListener;
    }

    Timer moveTimer=new Timer();
    TimerTask moveTask=new TimerTask() {    //创建一个任务,每隔一段时间自动滑动到下一页
    @Override
    public void run() {
        if(!isMoving){
            nowPosition=(nowPosition+1)%images.length;
            move();
        }
    }
};

    //获取外界传来的图片
    public void setImages(int[] imgs){
        this.images=new ImageView[imgs.length];
        if(onPagerNum>1)setBlankView();
        for(int i=0;i<images.length;i++){
            images[i]=new ImageView(getContext());
            images[i].setImageResource(imgs[i]);
            this.addView(images[i]);
        }
        setImgsTypes(1f,nowPosition+1);
        moveTimer.schedule(moveTask,4000,4000);
    }

    //设置空白的View
    private void setBlankView(){
        View view=new View(getContext());
        this.addView(view);
    }

    //设置图片属性
    /*
    * changePer:动态改变图片属性的比例
    * nextPos:下一张图片的下标
    * */
    private void setImgsTypes(float changePer,int nextPos){
        if(images!=null){
            for(int i=0;i<images.length;i++){
                images[i].setImageAlpha(100);
                images[i].setScaleX(0.5f);
                images[i].setScaleY(0.5f);
            }
            //缩小
            if(255*changePer>=100)images[pastPosition].setImageAlpha((int)(255*changePer));
            if(1f*changePer>=0.5f){
                images[pastPosition].setScaleX(1f*changePer);
                images[pastPosition].setScaleY(1f*changePer);
            }
            //放大
            if(nextPos < images.length && nextPos>=0){
                images[nextPos].setImageAlpha(100+(int)(155*(1-changePer)));
                images[nextPos].setScaleX(0.5f+0.5f*(1-changePer));
                images[nextPos].setScaleY(0.5f+0.5f*(1-changePer));
            }
        }
    }
}

外部Activity类:

public class MyViewPagerAct extends AppCompatActivity {
    private LinearLayout ll_p;
    private MyViewPagerViewGroup vpager;
    private int[] images = {R.mipmap.arti, R.mipmap.avatar, R.mipmap.butterfly, R.mipmap.head,R.mipmap.carousel_1,R.mipmap.bg_article};
    private View view_point;
    private int pointMargin,pointDiameter;  //滑动点之间的边距,滑动点的直径
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_viewpager);
        init();
    }

    private void init(){
        pointMargin=px2dp(5);
        pointDiameter=px2dp(10);
        view_point=findViewById(R.id.view_point);
        vpager=findViewById(R.id.vpager);
        vpager.setOnPageScrollListener(new MyViewPagerViewGroup.OnScrollListener() {
            @Override
            public void onScrolled(float offsetPer) {
                float leftMargin=offsetPer*(pointMargin+pointDiameter)+pointMargin;
                RelativeLayout.LayoutParams params=(RelativeLayout.LayoutParams)view_point.getLayoutParams();
                params.leftMargin=(int) leftMargin;
                view_point.setLayoutParams(params);
            }
            @Override
            public void onSelected(int position) {

            }
        });
        vpager.setImages(images);
        ll_p=findViewById(R.id.ll_p);
        addView();
    }

    private void addView(){ //右下角生成滑动点
        LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(pointDiameter,pointDiameter);
        params.leftMargin=pointMargin;
        for(int i=0;i<images.length;i++){
            View view=new View(this);
            view.setBackground(getDrawable(R.drawable.light_black_point));
            view.setLayoutParams(params);
            ll_p.addView(view);
        }
    }

    private int px2dp(float spValue){
        return (int)(getResources().getDisplayMetrics().scaledDensity*spValue+0.5f);
    }
}

 

  • 0
    点赞
  • 2
    评论
  • 5
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:书香水墨 设计师:CSDN官方博客 返回首页

打赏作者

henono

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值