Material Design 最全解析_5 UI控件

6 篇文章 1 订阅
6 篇文章 1 订阅

概述

Material Design为开发者提供了一系列的UI控件,对于开发者来说实在是福音。
今天这篇博客就记录一下UI新控件方面的知识。

先看一下大纲

这里写图片描述

UI控件

Android5.0基于Material Design,提供了很多新控件,这些控件无论在功能、体验和性能上都很出色,下面一一列举各个控件的使用方法。

SnackBar

SnackBar通过在屏幕底部展示简洁的信息,为一个操作提供了一个轻量级的反馈,并且在Snackbar中还可以包含一个操作,在同一时间内,仅且只能显示一个 Snackbar,它的显示依赖于UI,不像Toast那样可以脱离应用显示。它的用法和Toast很相似,唯一不同的就是它的第一个参数不是传入Context而是传入它所依附的父视图,但是他比Toast更强大。
(Dialog > SnackBar > Toast)
gradle
compile 'com.android.support:design:23.1.1'

最简单的提示
Snackbar.make(view, "SnackBar Demo Text", Snackbar.LENGTH_LONG).show();
SnackBar Demo

设置一个Action,自带点击事件

Snackbar.make(view, "Change Text", Snackbar.LENGTH_LONG)
.setAction("OK", new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            tv.setText("New Text");
        }
}).show();

action snackbar

设置背景颜色

Snackbar sb=Snackbar.make(view, "SnackBar demo", Snackbar.LENGTH_LONG);
sb.setAction("OK", new onClickListener()());
sb.getView().setBackgroundColor(0xfff44336);
sb.show();

背景色SnackBar

设置Action文字颜色
默认的Action文字颜色是ColorAccent,也可以通过api设置sb.setActionTextColor();

其他API

sb.dismiss();消失
sb.isShown();是否在显示
sb.isShownOrQueued();是否在显示或者在等待队列
sb.setText();设置文字

显示时长

LENGTH_LONG:长时间
LENGTH_SHORT:短时间
LENGTH_INDEFINITE:无限期,知道调用dismiss或者下一个SnackBar显示

注意1.SnackBar始终从底部弹出
SnackBar调用make时传进去一个View,它会顺着这个View去找父级,一直找到CoordinatorLayout或者FrameLayout,然后在它底部弹出。如果你的布局中没有包含这两个容器的一个,它就会一直找到Widnow的DecorView,效果就是在屏幕底部弹出。
看源码:

do {
    if(view instanceof CoordinatorLayout) {
        ...            
    }
    if(view instanceof FrameLayout) {
        ...
    }
 } while(view != null);

了解这特性有两个用处,解决异常Bug,实现特殊需求。
Demo:

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="30dp">

    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        app:borderWidth="0dp"
        app:fabSize="normal" />
</android.support.design.widget.CoordinatorLayout>

snackbar 底部弹出

注意2.悬浮按钮被snackBar遮挡

<RelaticeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="30dp">

    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        app:borderWidth="0dp"
        app:fabSize="normal" />
</RelaticeLayout>

FloatingButon 被遮挡

这个问题一看很棘手,其实也很简单用一下Material design库里的CoordinatorLayout即可,Java代码完全不用动。

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="30dp">

    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        app:borderWidth="0dp"
        app:fabSize="normal" />
</android.support.design.widget.CoordinatorLayout>

CoordinatorLayout下的SnackBar

稍微总结下:

1.比toast更加好,毕竟snackbar 可以响应点击事件
2.比Dialog轻量,可以替换很多Dialog的场景
3.snackbar 同一时间有且只有一个在显示
4.snackbar 上不要有图标
5.snackbar上action 只能有一个
6.如果有悬浮按钮FloatingActionButton的话,snackbar 在弹出的时候不要覆盖这个button
7.了解为什么SnackBar是从底部弹出的

CardView

CardView曾经开始流行在Google+,后来越来越多的APP也引入了Card这样的布局方式,说到底,CardView也是一个容器布局,只是他提供了一种卡片的形式,Google所幸提供了一个CardView控件,方便大家使用这种布局,开发者可以设置大小和视图高度,圆角的角度等。
cardview

<android.support.v7.widget.CardView
    android:id="@+id/cardview"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="16dp"
    android:clickable="true"
    android:foreground="?android:attr/selectableItemBackground"
    app:cardBackgroundColor="@color/colorAccent"
    app:cardCornerRadius="4dp"
    app:cardElevation="6dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="TextView in CardView"
        android:textStyle="bold"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="26sp" />
</android.support.v7.widget.CardView>

其实不用CardView也能实现,但是CardView做了很好的封装,只需要设置几个属性,就可以实现很好的效果,并且也减少了drawable资源,而且即便你什么都不设置,它也会设置合适的默认值。

Ps:

  • 在低版本中设置了 CardElevation 之后 CardView 会自动留出空间供阴影显示,而 Lollipop 之后则需要手动设置 Margin 边距来预留空间,导致我在设置 Margin 在 Android 5.x 机器上调试好后,在 Kitkat 机器调试时发现边距非常大,严重地浪费了屏幕控件。因此,我们需要自定义两个dimen作为CardView的Margin值。

    /res/value
    /res/value-v21
    android:layout_margin=”@dimen/xxx_card_margin”

  • android:foreground=”?attr/selectableItemBackground”
    这个属性会在 Lollipop 上自动加上 Ripple 效果,在旧版本则是一个变深/变亮的效果。

  • 让点击效果更加贴近 Material Design,要实现这个效果不难,我们只需要借助Lollipop的一个新属性android:stateListAnimator
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="true" android:state_pressed="true">
          <objectAnimator
               android:duration="@android:integer/config_shortAnimTime"
               android:propertyName="translationZ"
               android:valueTo="@dimen/touch_raise"
               android:valueType="floatType" />
     </item>
     <item>
           <objectAnimator
           android:duration="@android:integer/config_shortAnimTime"
           android:propertyName="translationZ"
           android:valueTo="0dp"
           android:valueType="floatType" />
     </item>
</selector>

android:stateListAnimator="@anim/touch_raise"

Toolbar

Toolbar是在 Android 5.0 开始推出的一个 Material Design 风格的导航控件 ,Google 非常推荐大家使用 Toolbar 来作为Android客户端的导航栏,以此来取代之前的 Actionbar 。与 Actionbar 相比, Toolbar 明显要灵活的多。它不像 Actionbar 一样,一定要固定在Activity的顶部,而是可以放到界面的任意位置。除此之外,在设计 Toolbar 的时候,Google也留给了开发者很多可定制修改的余地,这些可定制修改的属性在API文档中都有详细介绍,如:

  • 设置导航栏图标;
  • 设置App的logo;
  • 支持设置标题和子标题;
  • 支持添加一个或多个的自定义控件;
  • 支持Action Menu;

使用
前面提到 Toolbar 是在 Android 5.0 才开始加上的,Google 为了将这一设计向下兼容,自然也少不了要推出兼容版的 Toolbar 。为此,我们需要在工程中引入 appcompat-v7 的兼容包,使用 android.support.v7.widget.Toolbar 进行开发。

MXL文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/color_0176da">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Clock" />
    </android.support.v7.widget.Toolbar>
</LinearLayout>

MENU文件:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@id/action_search"
        android:icon="@mipmap/ic_search"
        android:title="@string/menu_search"
        app:showAsAction="ifRoom" />
    <item
        android:id="@id/action_notification"
        android:icon="@mipmap/ic_notifications"
        android:title="@string/menu_notifications"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_item1"
        android:title="@string/item_01"
        app:showAsAction="never" />
    <item
        android:id="@+id/action_item2"
        android:title="@string/item_02"
        app:showAsAction="never" />
</menu>

Activity:

public class ToolBarActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tool_bar);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

        toolbar.setNavigationIcon(R.mipmap.ic_drawer_home);//设置导航栏图标
        toolbar.setLogo(R.mipmap.ic_launcher);//设置app logo
        toolbar.setTitle("Title");//设置主标题
        toolbar.setSubtitle("Subtitle");//设置子标题
        toolbar.setTitleTextColor(Color.rgb(250, 250, 250));//设置标题颜色
        toolbar.setSubtitleTextColor(Color.rgb(250, 250, 250));//设置子标题颜色
        toolbar.inflateMenu(R.menu.base_toolbar_menu);//设置右上角的填充菜单
        toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {

                return true;
            }
        });
    }
}

toolbar

设置更多Menu的icon:
<item name="actionOverflowButtonStyle">@style/ActionButton.Overflow.White</item>

<style name="ActionButton.Overflow.White" 
parent="android:style/Widget.Material.Light.ActionButton.Overflow">
    <item name="android:src">@mipmap/ic_more</item>
</style>

设置返回menu的icon
toolbar.setNavigationIcon(R.mipmap.ic_drawer_home);

通过着色改变颜色

Drawable drawable = getResources().getDrawable(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
drawable.setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
toolbar.setNavigationIcon(R.mipmap.ic_drawer_home);

精卫填坑

  • 坑1:在XML中设置Toolbar属性不生效
<android.support.v7.widget.Toolbar
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/color_0176da"
    android:logo="@mipmap/ic_launcher"
    android:navigationIcon="@mipmap/ic_drawer_home"
    android:subtitle="456"
    android:title="123">

解决方法:在根布局中加入自定义属性的命名空间

xmlns:toolbar="http://schemas.android.com/apk/res-auto"
<android.support.v7.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/color_0176da"
        toolbar:navigationIcon="@mipmap/ic_drawer_home"
        toolbar:logo="@mipmap/ic_launcher"
        toolbar:subtitle="456"
        toolbar:title="123">

为什么会出现这种问题呢?我猜测是因为这个控件是兼容版的控件,用 android:xxx 设置无效是的这些属性是在兼容包中,不在默认的Android SDK中,所以我们需要额外的引入。至于为什么IDE不报错,估计就是bug了吧!

  • 坑2:menu字体颜色不能改变
    在style中设置:<item name="actionMenuTextColor">#ffffff</item> 并没有用
    网上有人建议直接改全局的字体颜色
    在style中设置:<item name="android:textColorPrimary">#ffffff</item>
    但是这样其它所有文字的默认颜色都变了,慎重慎重

  • 坑3:ActionMode不能悬浮
    actionMode
    解决方法:在style中设置悬浮

    <item name="windowActionModeOverlay">true</item>

    modeoverlay

  • 坑4:自定义的View位于 title 、 subtitle 和 actionmenu 之间,这意味着,如果 title 和 subtitle 都在,且 actionmenu选项 太多的时候,留给自定义View的空间就越小

  • 坑5:必须设置为没有ActionBar
    使用Toolbar必须要求当前Activity没有ActionBar,方法有两种。

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    
    supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
    RequestWindowFeature(Window.FEATURE_NO_TITLE);

FloatingActionButton

FloatingActionButton从名字可以看出它是一个浮动的按钮,它是一个带有阴影的圆形按钮,可以通过fabSize来改变其大小,主要负责界面的基本操作,这个按钮总体来说还是比较简单的。
floatingActionButton

默认FloatingActionButton 的背景色是应用主题的 colorAccent(其实MD中的控件主题默认基本都是应用的这个主题),可以通过app:backgroundTint 属性或者setBackgroundTintList (ColorStateList tint)方法去改变背景颜色。

  • FloatingActionButton 的大小尺寸,可以用过app:fabSize 属性设置
  • android:src属性改变drawable
  • app:rippleColor设置点击button时候的颜色(水波纹效果)
  • app:borderWidth设置 button 的边框宽度
  • app:elevation设置普通状态阴影的深度(默认是 6dp)
  • app:pressedTranslationZ设置点击状态的阴影深度(默认是 12dp)
<android.support.design.widget.FloatingActionButton
        android:id="@+id/fab_search"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="20dp"
        android:clickable="true"
        android:src="@android:drawable/ic_dialog_email"
        app:borderWidth="1dp"
        app:fabSize="normal"
        app:rippleColor="#0000ff"
        app:elevation="3dp"
        app:pressedTranslationZ="6dp"/>

NavigationView可以和DrawerLayout一起结合使用
NavigationView

代码:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">
    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/navigation_header"
        app:menu="@menu/drawer" />
</android.support.v4.widget.DrawerLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="192dp"
    android:background="?attr/colorPrimaryDark"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="16dp"
    android:theme="@style/ThemeOverlay.AppCompat.Dark">

    <ImageView
        android:layout_width="72dp"
        android:layout_height="72dp"
        android:src="@mipmap/profile"
        app:border_color="@color/primary_light"
        app:border_width="2dp" />

    <TextView
        android:layout_marginTop="10dp"
        android:textSize="18sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="APP开发者"/>
</LinearLayout>

和普通的menu比,就多了单选属性

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity">
    <group android:checkableBehavior="single">
        <item
            android:id="@+id/navigation_item_example"
            android:icon="@drawable/ic_favorite"
            android:title="@string/navigation_example" />
        <item
            android:id="@+id/navigation_item_blog"
            android:icon="@drawable/ic_favorite"
            android:title="@string/navigation_my_blog" />
        <item
            android:id="@+id/navigation_item_about"
            android:icon="@drawable/ic_favorite"
            android:title="@string/navigation_about" />
    </group>
</menu>
navigationView.setNavigationItemSelectedListener(
    new NavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(MenuItem menuItem) {

            return true;
        }
    });

在Material Design中,Navigation drawer导航抽屉,被设计用于应用导航,提供了一种通用的导航方式,体现了设计的一致性。
而NavigationView的典型用途就是配合之前v4包的DrawerLayout,作为其中的Drawer部分,即导航菜单的本体部分。NavigationView是一个导航菜单框架,使用menu资源填充数据,使我们可以更简单高效的实现导航菜单。它提供了不错的默认样式、选中项高亮、分组单选、分组子标题、以及可选的Header。

TextInputLayout

使用过EditText的同学肯定知道,有一个叫hint的属性,它可以提示用户此处应该输入什么内容,然而当用户输入真实内容之后,hint的提示内容就消失了,用户的体验效果是十分不好的,TextInputLayout的出现解决了这个问题。
初始状态
初始状态

点击输入内容
点击输入内容

当用户在输入的时候hint的内容就会跑到输入内容的上边去,并且是以动画的形式,体验非常好。其中TextInputLayout中字体的颜色是style文件中的colorAccent。

看下代码:

<android.support.design.widget.TextInputLayout
    android:id="@+id/til"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:errorEnabled="true">

    <EditText
        android:id="@+id/et"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Password"/>
</android.support.design.widget.TextInputLayout>


textLayout = (TextInputLayout)findViewById(R.id.til);
textLayout.setHint("Password");

非常简单的使用方法,只是在EditText外再套一层TextInputLayout。

错误提示
TextInputLayout还有一个挺不错的设计,就是错误提示,当用户输入内容不正确时,可以在底部弹出一个错误提示。要使用错误提示,需要先设置errorEnable为true。

textInputLayout.setErrorEnabled(true);
app:errorEnable=”true

然后调用setError(“输入错误”);
错误提示

设置样式

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorAccent">#3498db</item>
</style>

TabLayout

我们在使用viewpager的时候,经常会使用TabPageIndicator来与其配合。达到很漂亮的滑动效果。但是TabPageIndicator是第三方的,而且比较老了,当然了现在很多大神都已经开始自己写TabPageIndicator来满足需求,在2015年的google大会上,新的Android Support Design库就包含了TabLayout,它可以实现TabPageIndicator的效果,而且兼容性非常好,最低可以兼容到2.2,32个赞不能再少了。
tablayout
XML代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    xmlns:app="http://schemas.android.com/apk/res-auto"  
    android:orientation="vertical">  

    <android.support.design.widget.TabLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/titleBlue"
        app:tabIndicatorColor="@color/white"
        app:tabSelectedTextColor="@color/gray"
        app:tabTextColor="@color/white" />

    <android.support.v4.view.ViewPager
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

java代码

TabLayout tabLayout;
tabLayout = (TabLayout)view.findViewById(R.id.tab_FindFragment_title);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_FIXED);
tabLayout.addTab(tabLayout.newTab().setText("Tab1"));
tabLayout.addTab(tabLayout.newTab().setText("Tab2"));
tabLayout.addTab(tabLayout.newTab().setText("Tab3"));
tabLayout.addTab(tabLayout.newTab().setText("Tab4"));

viewPager.stAdapter(adapter);
tabLayout.setViewPager(viewPager);
//tabLayout.setupWithViewPager(viewPager);

属性

tabLayout.setTabMode(TabLayout.MODE_FIXED);

MODE_FIXED:固定模式,每一个Tab等宽,不管多少都显示全部。
MODE_FIXED:

MODE_SCROLLABLE:滚动模式,适合多Tab,长短不一
MODE_SCROLLABLE

tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

GRAVITY_CENTER:居中显示
GRAVITY_CENTER

GRAVITY_FILL:充满整个宽度
GRAVITY_FILL

setIcon: tab.setIcon(R.drawable.ic_1);
setIcon
要icon横向显示,可以使用setCustomView
tab.setCustomView(getCustomView(index));
setCustomView

精卫填坑
tabLayout.setupWithViewPager(viewPager);
看源码,这个方法中调用了setTabsFromPagerAdapter(adapter);

public void setTabsFromPagerAdapter(@NonNull PagerAdapter adapter) {
  removeAllTabs();
  for (int i = 0, count = adapter.getCount(); i < count; i++) {
      addTab(newTab().setText(adapter.getPageTitle(i)));
  }
}

removeAllTabs()这个就是说把前面所有tablayout添加的view都删掉。也就是说在之前不管怎么处理view都被干掉。然后设置为PagerAdapter返回的title。
错误代码

tabLayout.addTab(tab1);
tabLayout.addTab(tab2);
tabLayout.addTab(tab3);
tabLayout.addTab(tab4);
tabLayout.setupWithViewPager(viewPager);

正确代码

tabLayout.setupWithViewPager(viewPager);
tabLayout.addTab(tab1);
tabLayout.addTab(tab2);
tabLayout.addTab(tab3);
tabLayout.addTab(tab4);

通过Adapter返回title

@Override
public CharSequence getPageTitle(int position) {
    return “xxx”;
}

Notification

Notification作为一个时间触发性的交互提示接口,让我们获得消息的时候,在状态栏,锁屏界面显示相应的消息

Google在Android5.X中,又进一步的改进了通知栏,优化了Notification,在5.X设备上一个标准的通知是这样的,长按会显示消息的来源。
Notification

  • 基本的Notification
    顶部显示横条
  • 折叠式Notification
    下拉时显示扩展模式,高度变高
  • 悬挂式Notification
    在顶部悬浮显示,提示性更强
  • 显示等级的Notification
    VISIBILITY_PUBLIC 只有在没有锁屏时会显示通知
    VISIBILITY_PRIVATE 任何情况都会显示通知
    VISIBILITY_SECRET 在安全锁和没有锁屏的情况下显示通知

AppbarLayout、CollapsingToolbarLayout、NestedScrollView、CoordinatorLayout

这几个控件就不一一说了,把他们合在一起写一个Demo一看便懂。Demo效果还是很明显的。
下载链接:http://download.csdn.net/detail/u011002668/9583550

RecyclerView

这个控件是Material Design新增控件中最复杂的,但是可能也是大家最熟悉的,因为很多人都开始使用它来替代ListView了,关于RecyclerView,张鸿洋有一片博客说的非常好了,很全面,这里我就不再说了,直接把链接发出来。
http://download.csdn.net/detail/u011002668/9583550

总结

到这里,Material Design的UI控件已经基本讲完了,下一篇也是最后一篇,会讲一下Material动画,相信也有很多东西会让大家眼前一亮。

本期节目就到这里,感谢大家收看,我们下期再见~

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值