从零开始:ViewPager与Fragment实现Android选项卡界面

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

简介:本文教程深入探讨了Android中的ViewPager和Fragment组件,指导开发者如何将这两个组件结合使用,创建一个动态的选项卡界面。ViewPager允许用户水平滑动浏览页面,而Fragment提供模块化的UI组件。通过添加TabLayout库,可以轻松实现Material Design风格的选项卡。文章详细介绍了设置步骤,包括添加依赖、创建Fragment和PagerAdapter、配置ViewPager和TabLayout,以及自定义选项卡外观。教程还建议注意细节,以提升应用的兼容性和用户体验。 安卓开发-Android ViewPager Fragment实现选项卡.zip

1. ViewPager视图组件介绍与实现

ViewPager是Android平台上非常常见的一款视图组件,它允许用户在一个水平方向上滑动切换页面,广泛应用于引导页、图片浏览等场景。为了实现流畅的用户体验和页面切换效果,ViewPager通常与PagerAdapter适配器一起使用。

1.1 ViewPager的基本概念

ViewPager作为一个容器,内部管理着一组子视图,即各个页面。开发者可以为ViewPager提供一组Fragment或View,用户在滑动时ViewPager会根据当前页面状态显示对应的子视图。当滑动到边缘时,系统会调用PagerAdapter的相关方法进行页面的加载和切换。

1.2 ViewPager的实现原理

ViewPager通过监听用户的滑动操作来响应页面切换。页面切换的动画效果主要依靠ViewPager的内部类ViewPageIndicator来实现,例如淡入淡出、滑动等动画。实现ViewPager的关键在于正确继承PagerAdapter并重写相关方法,如 instantiateItem() 用于加载页面, destroyItem() 用于移除页面,以及 isViewFromObject() 用于判断View和页面对象是否一一对应。

// 示例代码段,展示了ViewPager与PagerAdapter的基本使用方法
public class MyPagerAdapter extends PagerAdapter {
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        // 实例化并添加视图
        View view = LayoutInflater.from(container.getContext()).inflate(R.layout.my_view, container, false);
        container.addView(view);
        return view;
    }
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        // 移除视图
        container.removeView((View) object);
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        // 判断View和Object是否是同一个对象的引用
        return view == object;
    }

    @Override
    public int getCount() {
        // 返回页面总数
        return mPageCount;
    }
}

接下来的章节将深入探讨Fragment模块化组件的介绍与实现,让我们一起继续深入了解Android开发的高级话题。

2. Fragment模块化组件介绍与实现

在现代Android开发中,Fragment组件作为构建复杂用户界面的基本单元,提供了一种灵活的方式来实现模块化界面设计。它允许你将界面划分为可重复使用的模块,并且可以在同一个Activity中动态地添加、移除或替换Fragment,以适应不同屏幕尺寸或设备方向。本章将深入探讨Fragment的基本概念、生命周期、管理以及与Activity的交互和事务操作。

2.1 Fragment的基本概念

Fragment是一种可复用的组件,它有自己的生命周期,可以接收自己的输入事件,并且可以在运行时添加到或者从Activity中移除。Fragment必须始终嵌入到Activity中,并且它的生命周期直接受其宿主Activity的影响。在本小节中,我们将深入了解Fragment的生命周期以及Fragment与Activity之间如何进行交互。

2.1.1 Fragment的生命周期

Fragment拥有自己独立的生命周期,类似于Activity,但它的生命周期更加灵活和复杂。以下是Fragment生命周期的关键点:

  • onAttach() :Fragment与Activity关联时调用。
  • onCreate() :创建Fragment实例时调用,可以进行初始化操作。
  • onCreateView() :加载Fragment布局时调用,返回Fragment的布局视图。
  • onActivityCreate() :Fragment所在的Activity完成onCreate()时调用。
  • onStart() :Fragment可见时调用。
  • onResume() :Fragment获得用户输入焦点时调用。
  • onPause() :Fragment失去用户输入焦点时调用。
  • onStop() :Fragment不可见时调用。
  • onDestroyView() :Fragment的视图被移除时调用。
  • onDestroy() :Fragment被销毁前调用。
  • onDetach() :Fragment与Activity解绑时调用。

2.1.2 Fragment与Activity的交互

Fragment与Activity之间的交互非常重要,它允许Fragment访问Activity的资源和方法,同时也允许Activity对Fragment进行操作。这里有几个关键的交互点:

  • 获取Activity实例 :Fragment可以通过getActivity()方法获取到宿主Activity的实例。
  • 回调Activity的方法 :Fragment可以定义回调接口,由Activity实现该接口的方法来响应Fragment的请求。
  • 共享数据 :Fragment可以直接访问Activity中定义的公共字段和方法,实现数据共享。
  • 事件传递 :Activity可以为Fragment设置事件监听器,这样Fragment就可以将事件传递给Activity处理。

2.1.3 实际操作:Fragment与Activity的交互示例

假设有一个简单的界面由Activity和两个Fragment组成,现在我们来展示如何在Fragment中获取Activity实例,并在Activity中处理Fragment的事件。

// 在Fragment中获取Activity实例
class ExampleFragment : Fragment() {
    lateinit var activity: MainActivity // 假设Activity是MainActivity类的实例

    override fun onAttach(context: Context) {
        super.onAttach(context)
        if (context is MainActivity) {
            activity = context
        } else {
            throw RuntimeException("$context must implement ExampleFragmentListener")
        }
    }

    fun onSomeButtonClicked() {
        // 假设有一个按钮被点击,通知Activity处理
        activity.someButtonClicked()
    }
}

// Activity实现的回调接口
interface ExampleFragmentListener {
    fun someButtonClicked()
}

// Activity的实现
class MainActivity : AppCompatActivity(), ExampleFragmentListener {
    override fun someButtonClicked() {
        // 处理Fragment传递的事件
    }
}

在上述代码中,我们通过接口回调的方式实现了Fragment与Activity的事件交互。这种方式既保持了Fragment的独立性,又使得Activity能够有效地管理和响应Fragment的事件。

2.2 Fragment的管理与事务操作

Fragment事务(Fragment Transactions)是Fragment类中管理Fragment动态添加、移除、替换和执行其他操作的机制。管理Fragment事务,可以让用户界面的转换更加流畅,并且可以利用回退栈(Back Stack)来管理用户的导航历史。

2.2.1 Fragment的添加、移除和替换

使用FragmentManager管理Fragment事务是实现动态界面更改的基本方式。以下是常见的Fragment事务操作:

  • 添加Fragment :使用FragmentManager的 beginTransaction() 方法开始一个事务,然后用 add() 方法添加Fragment到Activity中。
  • 移除Fragment :使用 remove() 方法从Activity中移除Fragment。
  • 替换Fragment :使用 replace() 方法替换Activity中的Fragment。

2.2.2 Fragment事务的回退栈管理

Android的回退栈用于记录用户的导航历史,使得用户可以按后退键返回到之前的界面。管理Fragment事务的回退栈可以让用户在Fragment之间进行导航时获得一致的体验。

  • 回退栈操作 :当你使用 addToBackStack() 方法时,Fragment事务会被加入到回退栈中。当用户按后退键时,系统会自动回滚到最后一次Fragment事务。
  • 自定义回退栈行为 :你可以自定义回退栈的行为,比如设置事务时的动画效果,或者自定义事务回退时的行为。

2.2.3 实际操作:Fragment事务与回退栈的管理示例

假设我们有一个需要在两个Fragment之间切换的场景,我们可以使用Fragment事务来实现,并加入回退栈管理。

// 添加Fragment事务示例
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment = new ExampleFragment();

// 替换Fragment并加入回退栈管理
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
***mit();

在上述代码中,我们使用了 replace() 方法替换了容器中的Fragment,并通过 addToBackStack() 方法将此次事务加入到回退栈中。这样一来,当用户按下后退键时,系统会将替换的Fragment恢复到原来的位置。

总结

在本章中,我们详细介绍了Fragment组件的核心概念,生命周期,以及与Activity的交互和管理事务操作。在后续章节中,我们将继续深入探讨PagerAdapter的实现和使用,以及TabLayout与ViewPager结合实现选项卡的方法和细节。通过深入理解这些组件,开发者可以创建出更加流畅和用户友好的应用界面。

3. PagerAdapter适配器使用

PagerAdapter是ViewPager组件中非常关键的一个适配器,它负责为ViewPager提供页面视图的管理和数据绑定。要深入理解PagerAdapter的使用,首先需要了解其基本原理以及如何实现自定义PagerAdapter来优化性能和管理Fragment实例缓存。

3.1 PagerAdapter的基本原理

PagerAdapter为ViewPager提供了一种机制,允许开发者创建和管理多个页面视图。它是所有适配器的抽象基类,开发者需要继承并实现其中的必要方法来满足自己的需求。

3.1.1 继承PagerAdapter的要点

在创建自定义PagerAdapter时,首先需要了解继承PagerAdapter需要实现的几个核心方法:

  • instantiateItem(ViewGroup container, int position) : 此方法负责实例化指定位置的页面视图。位置参数 position 指明了是哪一个页面需要被创建。开发者通常在这个方法中创建或获取Fragment实例,并将其添加到ViewPager中。
  • destroyItem(ViewGroup container, int position, Object object) : 当页面不再被ViewPager显示时,该方法会被调用。参数 object 是与 instantiateItem 方法中返回的相同的对象。开发者需要在这个方法中将页面视图从容器中移除,并进行必要的清理工作。
  • isViewFromObject(View view, Object object) : 此方法用于判断给定的视图和对象是否关联。通常情况下, object 是一个与视图相关的Fragment实例。

3.1.2 重要方法的实现解析

让我们深入分析一下如何实现 instantiateItem destroyItem 方法,并且探讨它们在维护Fragment实例时发挥的作用。

实现 instantiateItem 方法
@Override
public Object instantiateItem(ViewGroup container, int position) {
    // 此处使用了FragmentStatePagerAdapter作为例子
    // 根据position来获取Fragment实例
    Fragment fragment = getItem(position);
    if (fragment == null) {
        // 如果fragment不存在,则创建一个新的实例
        fragment = createFragment(position);
    }
    // 如果fragment还未附加到Activity,则附加它
    if (!fragment.isAdded()) {
        getSupportFragmentManager().beginTransaction().add(container.getId(), fragment, getTag(position)).commit();
    }
    // 将Fragment实例与container关联起来
    container.addView(fragment.getView());
    // 将Fragment实例记录到一个map中,方便后续的管理
    fragmentList.put(position, fragment);
    return fragment;
}
实现 destroyItem 方法
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment) object;
    // 从container中移除视图
    container.removeView(fragment.getView());
    // 将Fragment实例从记录map中移除
    fragmentList.remove(position);
    // 如果fragment所在的Activity已经销毁或者fragment不需要保留,则进行适当的清理工作
    if (fragment.isDetached() || shouldRemoveFragment(fragment)) {
        getSupportFragmentManager().beginTransaction().remove(fragment).commit();
    }
}

3.2 实现自定义PagerAdapter

实现自定义PagerAdapter通常是为了优化Fragment实例的缓存机制,以及更好地处理状态的保存与恢复。

3.2.1 优化Fragment实例缓存机制

在使用PagerAdapter时,一个常见的问题是:如果所有的Fragment都被实例化并添加到容器中,当有大量页面时,这将导致内存消耗非常大。为了优化这个过程,可以使用 FragmentStatePagerAdapter 代替 PagerAdapter ,因为后者支持根据视图可见性来销毁未显示的Fragment。

3.2.2 状态保存与恢复的处理

当Activity或Fragment的配置发生变化时(如屏幕旋转),系统会重新创建它们。为了恢复之前的状态,需要在适配器中处理状态的保存与恢复。

处理状态保存
@Override
public void saveState(Bundle outState) {
    super.saveState(outState);
    // 将当前的Fragment列表保存到outState中
    outState.putParcelableArrayList("states", new ArrayList<>(fragmentList.keySet()));
}

@Override
public CharSequence getPageTitle(int position) {
    // 根据position返回标题
    return titles[position];
}
处理状态恢复
@Override
public void restoreState(Bundle bundle, ClassLoader classLoader) {
    super.restoreState(bundle, classLoader);
    // 如果有保存的状态,则恢复Fragment列表
    if (bundle != null && bundle.containsKey("states")) {
        ArrayList<Integer> states = bundle.getIntegerArrayList("states");
        if (states != null) {
            for (int i : states) {
                // 如果Fragment还没有被创建,则在instantiateItem中进行创建
                fragmentList.put(i, getItem(i));
            }
        }
    }
}

通过以上方法的实现,可以有效地对Fragment进行缓存,并且在Activity重建时恢复之前的状态,从而提高应用的性能和用户体验。

3.3 代码逻辑与参数说明

以上代码块展示了如何通过实现PagerAdapter的几个关键方法来优化Fragment的管理。 instantiateItem 方法负责创建和附加Fragment,而 destroyItem 方法则在Fragment不再需要时进行清理。 saveState restoreState 方法处理了Activity或Fragment重建时的状态保存和恢复。这些方法共同工作,确保了视图的平滑切换和资源的有效管理。

在自定义PagerAdapter时,开发者需要细致地考虑如何管理Fragment实例,如何处理视图的添加和移除,以及如何在配置更改时保持用户的状态。通过优化这些操作,可以显著提升应用的响应速度和稳定性。

4. TabLayout与ViewPager结合实现选项卡

4.1 TabLayout的使用与自定义

4.1.1 TabLayout的属性与方法

TabLayout是Material Design组件库中的一个重要成员,它主要用来创建顶部的标签导航栏,可以和ViewPager组件配合使用,实现页面切换时选项卡同步变化的效果。TabLayout的属性和方法非常丰富,它支持多种配置选项,使得我们可以自定义外观和行为,满足不同的设计需求。

TabLayout的主要属性包括:

  • app:tabGravity :设置标签在TabLayout中的分布方式,可选值有 fill center 等。
  • app:tabMode :设置TabLayout的模式,比如是固定的( fixed )还是可以滚动的( scrollable )。
  • app:tabIndicatorColor :设置当前选中标签下方指示器的颜色。
  • app:tabIndicatorHeight :设置指示器的高度。

常用的方法有:

  • addTab(Tab tab) :向TabLayout中添加一个新的标签。
  • addTab(Tab tab, int position) :向指定位置添加标签。
  • setSelectedTabIndicatorColor(int color) :设置选中标签指示器的颜色。
  • setupWithViewPager(ViewPager viewPager) :将TabLayout与ViewPager进行联动。

4.1.2 自定义TabLayout样式

自定义TabLayout样式可以通过XML属性直接实现,也可以通过编程方式动态地进行配置。例如,通过XML我们可以定义一个样式,使得TabLayout拥有更加丰富的视觉效果:

<com.google.android.material.tabs.TabLayout
    android:id="@+id/tabLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:tabBackground="@drawable/tab_background_selector"
    app:tabTextAppearance="@style/MyCustomTabTextAppearance"
    app:tabSelectedTextColor="@color/white"
    app:tabIndicatorColor="@color/primary"
    app:tabMode="fixed"
    app:tabGravity="fill" />

在上述代码中, tabBackground 属性引用了一个选择器 tab_background_selector 来为标签设置不同的背景状态, tabSelectedTextColor 设置了选中标签的文字颜色,而 tabIndicatorColor 定义了选中标签下的指示器颜色。

编程自定义样式时,可以通过调用TabLayout的方法来实现:

TabLayout tabLayout = findViewById(R.id.tabLayout);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_FIXED);

for (int i = 0; i < tabLayout.getTabCount(); i++) {
    TabLayout.Tab tab = tabLayout.getTabAt(i);
    if (tab != null) {
        tab.setCustomView(R.layout.custom_tab_layout);
    }
}

这里我们设置了TabLayout的分布方式为填充父容器,并且设置了模式为固定模式。通过循环为每一个标签设置自定义视图,这使得我们可以为每一个标签定义不同的布局。

4.2ViewPager与TabLayout的联动实现

4.2.1 关联ViewPager与TabLayout

要实现ViewPager与TabLayout的联动,最简单的方式是调用 setupWithViewPager 方法,让TabLayout根据ViewPager中的页面自动创建和管理标签。这一过程不仅自动同步了标签和页面,还可以处理标签的点击事件,使得用户可以点击标签切换页面。

ViewPager viewPager = findViewById(R.id.viewPager);
TabLayout tabLayout = findViewById(R.id.tabLayout);

// 设置ViewPager与TabLayout联动
tabLayout.setupWithViewPager(viewPager);

这行代码足以完成大部分需求的实现,但有时我们可能还需要更细粒度的控制。例如,我们可能需要添加一些自定义的属性到TabLayout的Tab中,或者动态地添加/删除Tab。这种情况下,我们可以使用TabLayout的 addTab 方法:

// 创建Tab
TabLayout.Tab tab = tabLayout.newTab();
tab.setText("Home");
tab.setIcon(R.drawable.home_icon);

// 将Tab添加到TabLayout中
tabLayout.addTab(tab, 0, true); // 第三个参数为true表示选中状态

// 为ViewPager设置适配器
viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));

4.2.2 动态添加和管理Tab

在某些情况下,我们可能需要动态地管理Tab,例如在运行时根据数据源的变化来添加或移除Tab。TabLayout提供了方法来处理这些需求。我们可以使用 addTab() removeTab() 方法来添加或移除Tab:

// 动态添加Tab
TabLayout.Tab newTab = tabLayout.newTab();
newTab.setText("New Tab");
newTab.setIcon(R.drawable.new_tab_icon);
tabLayout.addTab(newTab);

// 动态移除Tab
TabLayout.Tab tabToRemove = tabLayout.getTabAt(1);
if (tabToRemove != null) {
    tabLayout.removeTab(tabToRemove);
}

同时,如果我们希望对Tab的创建和添加过程有更多的控制,可以通过 TabLayout.OnTabSelectedListener 来监听Tab的选择事件,并在选中时进行特定的操作。

tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        // 处理选中的Tab事件,比如可以在这里同步ViewPager页面
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {
        // 处理未选中的Tab事件
    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {
        // 处理Tab被重新选中的事件,通常用于刷新页面内容
    }
});

这种方式的联动实现不仅提高了用户体验,同时也为开发者提供了灵活的交互设计能力。

以上是TabLayout与ViewPager结合实现选项卡的基本实现方法和一些自定义样式的技巧。在后续章节中,我们将深入探讨如何优化选项卡的外观和处理选项卡间的交互细节,使得应用更加丰富和个性化。

5. 自定义选项卡外观与细节处理

5.1 自定义选项卡的布局设计

自定义选项卡的外观和布局设计是提升用户体验的重要手段。一个好的UI设计不仅需要视觉上的美观,更需要逻辑上的合理。

5.1.1 布局文件的编写与布局结构

在自定义选项卡时,首先需要编写布局文件。例如,我们可以创建一个名为 tab_item.xml 的布局文件来定义每个选项卡的外观。

<LinearLayout xmlns:android="***"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="center"
    android:padding="10dp">

    <ImageView
        android:id="@+id/tab_icon"
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:src="@drawable/ic_tab_default" />

    <TextView
        android:id="@+id/tab_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Tab Title"
        android:textSize="12sp"
        android:textColor="@android:color/white" />
</LinearLayout>

布局文件中,我们使用了垂直的线性布局来组合图标和文字。这里可以使用 ImageView TextView 来分别显示选项卡的图标和标题。

5.1.2 自定义视图与样式设置

为了使选项卡看起来更具有特色,我们可以创建自定义视图。以下是如何在一个 Fragment 中应用自定义选项卡视图的示例代码:

public class CustomTabFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.tab_item, container, false);
        ImageView tabIcon = view.findViewById(R.id.tab_icon);
        TextView tabTitle = view.findViewById(R.id.tab_title);

        // 设置图标和标题
        tabIcon.setImageResource(R.drawable.ic_tab_home);
        tabTitle.setText("Home");

        return view;
    }
}

这段代码定义了一个自定义的 Fragment ,在 onCreateView 方法中加载了我们上面定义的 tab_item.xml 布局文件,并设置了选项卡的图标和标题。当然,图标和标题应该根据实际的选项卡进行动态设置,这里只是示例。

5.2 选项卡交互与事件处理

用户与应用的交互是应用设计中必不可少的环节,特别是对于选项卡这类元素,良好的交互设计可以提升用户满意度。

5.2.1 选项卡点击事件的响应与处理

为了处理选项卡的点击事件,我们需要在 PagerAdapter 中设置监听器,并在 onPageSelected 方法中做出反应。

myPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        // 这里可以处理滑动时的逻辑,比如渐变效果
    }

    @Override
    public void onPageSelected(int position) {
        // 这里可以处理选项卡选中时的逻辑,比如更新选中状态
        updateTabSelection(position);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        // 这里可以处理滑动状态变化的逻辑
    }
});

private void updateTabSelection(int position) {
    // 更新UI,例如改变选中标签的图标或颜色
}

updateTabSelection 方法可以被用来更新当前选中标签的UI,比如改变图标颜色或背景,以提供视觉反馈。

5.2.2 状态同步与视觉反馈优化

为了使用户在点击选项卡时获得即时的视觉反馈,我们需要同步当前选项卡的状态。这通常意味着我们需要改变选中和未选中状态下的视图样式。

// 示例代码片段,更新选项卡的状态
private void updateTabSelection(int position) {
    // 遍历所有选项卡,更新它们的状态
    for (int i = 0; i < numberOfTabs; i++) {
        View tab = getTabView(i);
        if (i == position) {
            // 当前选中的标签
            tab.setSelected(true);
        } else {
            // 未选中的标签
            tab.setSelected(false);
        }
    }
}

private View getTabView(int index) {
    // 这个方法应该根据你的实现来返回对应的视图实例
    // 它可以是直接返回一个视图,或者是一个视图对象的引用
    return null;
}

通过这样的处理,用户可以直观地看到哪个选项卡是当前活动的,从而增强了应用的易用性和直观性。

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

简介:本文教程深入探讨了Android中的ViewPager和Fragment组件,指导开发者如何将这两个组件结合使用,创建一个动态的选项卡界面。ViewPager允许用户水平滑动浏览页面,而Fragment提供模块化的UI组件。通过添加TabLayout库,可以轻松实现Material Design风格的选项卡。文章详细介绍了设置步骤,包括添加依赖、创建Fragment和PagerAdapter、配置ViewPager和TabLayout,以及自定义选项卡外观。教程还建议注意细节,以提升应用的兼容性和用户体验。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值