Day15、退出程序小案例和自定义对话框

在上面我们写的ListViewDemo中,如果当我们一时手滑按了返回键,则小程序将会直接退出到模拟器主界面,那么我们需要一个退出程序对话框来提示用户是否真正要退出。在上节我们学了如何使用5中常见的对话框,但是有时候业务需求不同,为了有个漂亮的外表对话框,需要自定义对话框。

一、实现程序确认框的步骤

1.重写主Activity中的onBackPress()方法;
2.去除原有的父类的方法即super.onBackPressed();
3.编写确认对话框;
4.在确定事件里调用finish()来结束程序。
5.具体代码如下:
package com.oldtogether.adapterdemo2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

public class MainActivity4 extends ActionBarActivity implements OnItemClickListener, OnItemLongClickListener {
    // 创建数组,采用for循环进行遍历
    private int[] imageIds = new int[] { R.drawable.daxiang, R.drawable.maozi, R.drawable.nangua, R.drawable.nanguobq,
            R.drawable.tiaopi, R.drawable.xiaolian, R.drawable.xin, R.drawable.weixin, R.drawable.hongx,
            R.drawable.xm };
    private String[] titles = new String[] { "卖萌大象", "圣诞帽子", "愤怒南瓜", "难过表情", "调皮表情", "笑脸表情", "oldtogether爱心", "微信",
            "粉色少女心", "一代撸" };
    private String[] versions = new String[] { "版本:1.10", "版本:2.10", "版本:1.11", "版本:2.12", "版本:3.10", "版本:2.20",
            "版本:5.20", "版本:1.23", "版本:2.21", "版本:2.40", };
    private String[] sizes = new String[] { "大小:32.01M", "大小:32.02M", "大小:23.01M", "大小:11.01M", "大小:41.01M",
            "大小:11.01M", "大小:33.01M", "大小:33.01M", "大小:33.01M", "大小:33.01M", };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.listview);

        // 1、过的ListView对象
        ListView lv = (ListView) findViewById(R.id.lv_play);
        // 2、数据源
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < titles.length; i++) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("logo", imageIds[i]);
            map.put("title", titles[i]);
            map.put("version", versions[i]);
            map.put("size", sizes[i]);
            list.add(map);
        }
        // 3、设置适配器
        MyAdapter3 adapter3 = new MyAdapter3(this);
        adapter3.setList(list);// 传入数据
        // 4、关联适配器
        lv.setAdapter(adapter3);
        // 5、为ListView设置事件监听器(一下两个常用事件),让主MainActivity2实现接口,并重写方法
        lv.setOnItemClickListener(this);
        lv.setOnItemLongClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        /* 创建了一个意图对象,调用setClass方法表明“在那个Activity中调用那个Activity”次意图*/  
        Intent intent = new Intent();
        intent.setClass(getApplicationContext(), DetailActivity.class);

        //获得点击行的数据
        HashMap <String,Object> itemMap= (HashMap<String,Object>) parent.getItemAtPosition(position);
        intent.putExtra("index", ""+position);//获得编号
        intent.putExtra("title", ""+itemMap.get("title"));//获得标题
        startActivity(intent);
    }
    ArrayList<Integer> choice = new ArrayList<>();
    @Override
    public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        //长按之多选框
        final String [] interests={"看书","打篮球","大lol","听音乐","看电影","跑步"};//设置为final(常量)的原因是可以穿透作用域
        new AlertDialog.Builder(this)
        .setIcon(R.drawable.ic_launcher)
        .setTitle("你的爱好是什么?")
        .setMultiChoiceItems(interests,
                new boolean []{false,false,false,false,false,false},
                new DialogInterface.OnMultiChoiceClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                        //选中则添加,后悔是时还可以remove掉
                        if(isChecked){
                            choice.add(which);
                        }else{
                            choice.remove(which);
                        }
                        Toast.makeText(MainActivity4.this, "您当前的选择是:"+choice.toString(), Toast.LENGTH_LONG).show();
                    }
                })
        .setPositiveButton("确定", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(MainActivity4.this, "您最终的决定是:"+choice.toString(), Toast.LENGTH_LONG).show();
            }
        })
        .setNegativeButton("取消", null)
        .show();
        return true;
    }

    @Override
    public void onBackPressed() {
        new AlertDialog.Builder(this)
        .setIcon(R.drawable.ic_launcher)
        .setTitle("确认对话框")
        .setMessage("您真的要退出次程序吗?")
        .setPositiveButton("取消", null)
        .setNegativeButton("确定", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                finish();
            }
        }).show();
    }
}
5.运行结果

这里写图片描述
这里写图片描述

二、上面的很多Test都是在ListView中进行的,但是我们可以发现,Item项中的Button没有任何操作,只是简单的设置了背景转换器,那么如何让其生效呢??

1.在回到MyAdapter3.java,回顾ListView优化,在渲染每一行时,同样将Button对象获得,代码如下:
package com.oldtogether.adapterdemo2;

import java.util.List;
import java.util.Map;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class MyAdapter3 extends BaseAdapter {
    List<Map<String, Object>> list;
    LayoutInflater Inflater;// 反射器

    // 初始化反射器
    public MyAdapter3(Context context) {
        this.Inflater = LayoutInflater.from(context);
    }

    public void setList(List<Map<String, Object>> list) {
        this.list = list;
    }

    @Override
    public int getCount() {
        // 获取ListView的行数
        return list.size();
    }

    @Override
    public Object getItem(int index) {
        // 获得Item项的对象,其中的参数为此Item的下标,从零开始
        return list.get(index);
    }

    @Override
    public long getItemId(int id) {
        // 获得ItemId
        return id;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        // 判断convertView是否为空,其来自getView方法的形参
        if (convertView == null) {
            // 通过反射获得行布局对象
            convertView = Inflater.inflate(R.layout.item, null);
            holder = new ViewHolder();
            // 获得控件对象,并作为ViewHolder的属性
            holder.logo = (ImageView) convertView.findViewById(R.id.iv_logo);
            holder.title = (TextView) convertView.findViewById(R.id.title);
            holder.version = (TextView) convertView.findViewById(R.id.version);
            holder.size = (TextView) convertView.findViewById(R.id.size);
            holder.btn = (Button) convertView.findViewById(R.id.btn);
            // 将ViewHolder和convertView关联起来
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        // 添加数据,注意需要强转
        Map map = list.get(position);
        holder.logo.setImageResource((int) map.get("logo"));
        holder.title.setText((String) map.get("title"));
        holder.version.setText((String) map.get("version"));
        holder.size.setText((String) map.get("size"));

        holder.btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.i("zwb","点击了Item中的安装按钮"+position);//这里牵扯到左右域的问题,应该在getView方法中的第一个参数中用final来修饰
            }
        });

        return convertView;
    }

    // 自定义的ViewHolder类
    public class ViewHolder {
        ImageView logo;
        TextView title;
        TextView version;
        TextView size;
        Button btn;
    }
}
2.运行结果

这里写图片描述

三、降低依赖,降低耦合(接口隔离原则)

1.通过上面的运行结果可以看出,我们通过Log日志达到了需求,但是不能使用Toast来弹出提示信息,因为在Context上下文时,使用匿名内部类遇见了麻烦,同时资源的利用也被局限了,在程序设计时,为了便于程序的维护,为了降低类和类之间的耦合,聪明的猿们将所用到的方法封装在一个接口中,让所需要的类来实现即可。
2.首先定义一个Interface,只是简单的封装一个butClick方法,代码如下:
package com.oldtogether.adapterdemo2;

public interface IControl {
    void btnClick(int pos);
}
3.在自定义的MyAdapater3中,设置Icontrol接口的成员变量,并设置set方法,方便其他类调用;在ViewHolder中加入按钮对象并通过findViewById()此反射获得,和ConvertView绑在一起;最后在按钮点击事件中,将每一项作为参数传入到接口中的btnClick()方法中,代码如下:
package com.oldtogether.adapterdemo2;

import java.util.List;
import java.util.Map;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class MyAdapter3 extends BaseAdapter {
    List<Map<String, Object>> list;
    LayoutInflater Inflater;// 反射器

    IControl control;//声明一个接口类型的成员变量
    //并将其作为参数传进来,方便在其他类中调用
    public void setControl(IControl control) {
        this.control = control;
    }

    // 初始化反射器
    public MyAdapter3(Context context) {
        this.Inflater = LayoutInflater.from(context);
    }

    public void setList(List<Map<String, Object>> list) {
        this.list = list;
    }

    @Override
    public int getCount() {
        // 获取ListView的行数
        return list.size();
    }

    @Override
    public Object getItem(int index) {
        // 获得Item项的对象,其中的参数为此Item的下标,从零开始
        return list.get(index);
    }

    @Override
    public long getItemId(int id) {
        // 获得ItemId
        return id;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        // 判断convertView是否为空,其来自getView方法的形参
        if (convertView == null) {
            // 通过反射获得行布局对象
            convertView = Inflater.inflate(R.layout.item, null);
            holder = new ViewHolder();
            // 获得控件对象,并作为ViewHolder的属性
            holder.logo = (ImageView) convertView.findViewById(R.id.iv_logo);
            holder.title = (TextView) convertView.findViewById(R.id.title);
            holder.version = (TextView) convertView.findViewById(R.id.version);
            holder.size = (TextView) convertView.findViewById(R.id.size);
            holder.btn = (Button) convertView.findViewById(R.id.btn);
            // 将ViewHolder和convertView关联起来
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        // 添加数据,注意需要强转
        Map map = list.get(position);
        holder.logo.setImageResource((int) map.get("logo"));
        holder.title.setText((String) map.get("title"));
        holder.version.setText((String) map.get("version"));
        holder.size.setText((String) map.get("size"));

holder.btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                control.btnClick(position);//这里只是将position(每一项传进去),具体的实现才做甩到接口中去
            }
        });

        return convertView;
    }

    // 自定义的ViewHolder类
    public class ViewHolder {
        ImageView logo;
        TextView title;
        TextView version;
        TextView size;
        Button btn;
    }
}
4.让MainActivity4.java实现我们自定义的接口IControl并重新抽象方法,当然这里用简单的Toast来实现简单的代码,这里只是提供一种框架,可以填充更加复杂的逻辑代码。具体代码如下:
package com.oldtogether.adapterdemo2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

public class MainActivity4 extends ActionBarActivity implements OnItemClickListener, OnItemLongClickListener,IControl {
    // 创建数组,采用for循环进行遍历
    private int[] imageIds = new int[] { R.drawable.daxiang, R.drawable.maozi, R.drawable.nangua, R.drawable.nanguobq,
            R.drawable.tiaopi, R.drawable.xiaolian, R.drawable.xin, R.drawable.weixin, R.drawable.hongx,
            R.drawable.xm };
    private String[] titles = new String[] { "卖萌大象", "圣诞帽子", "愤怒南瓜", "难过表情", "调皮表情", "笑脸表情", "oldtogether爱心", "微信",
            "粉色少女心", "一代撸" };
    private String[] versions = new String[] { "版本:1.10", "版本:2.10", "版本:1.11", "版本:2.12", "版本:3.10", "版本:2.20",
            "版本:5.20", "版本:1.23", "版本:2.21", "版本:2.40", };
    private String[] sizes = new String[] { "大小:32.01M", "大小:32.02M", "大小:23.01M", "大小:11.01M", "大小:41.01M",
            "大小:11.01M", "大小:33.01M", "大小:33.01M", "大小:33.01M", "大小:33.01M", };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.listview);

        // 1、获得ListView对象
        ListView lv = (ListView) findViewById(R.id.lv_play);
        // 2、数据源
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < titles.length; i++) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("logo", imageIds[i]);
            map.put("title", titles[i]);
            map.put("version", versions[i]);
            map.put("size", sizes[i]);
            list.add(map);
        }
        // 3、设置适配器
        MyAdapter3 adapter3 = new MyAdapter3(this);
        adapter3.setList(list);// 传入数据
        adapter3.setControl(this);//传入IControl的成员变量,即在此引用
        // 4、关联适配器
        lv.setAdapter(adapter3);
        // 5、为ListView设置事件监听器(一下两个常用事件),让主MainActivity2实现接口,并重写方法
        lv.setOnItemClickListener(this);
        lv.setOnItemLongClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        /* 创建了一个意图对象,调用setClass方法表明“在那个Activity中调用那个Activity”次意图*/  
        Intent intent = new Intent();
        intent.setClass(getApplicationContext(), DetailActivity.class);

        //获得点击行的数据
        HashMap <String,Object> itemMap= (HashMap<String,Object>) parent.getItemAtPosition(position);
        intent.putExtra("index", ""+position);//获得编号
        intent.putExtra("title", ""+itemMap.get("title"));//获得标题
        startActivity(intent);
    }
    ArrayList<Integer> choice = new ArrayList<>();//创建一个ArrayList用来保存在Dialog中所选择的选项,同理设置为全局变量为了穿透作用域
    @Override
    public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        //长按之多选框
        final String [] interests={"看书","打篮球","大lol","听音乐","看电影","跑步"};//设置为final(常量)的原因是可以穿透作用域
        new AlertDialog.Builder(this)
        .setIcon(R.drawable.ic_launcher)
        .setTitle("你的爱好是什么?")
        /*
         * setMultiChoiceItems()方法中的三个参数
         * 第一个参数:资源数组;
         * 第二个参数:默认情况下的初始值,这里因为是多选,所以设置为boolean类型的数组;
         * 第三个参数:多选框的点击事件;
         * 
         */
        .setMultiChoiceItems(interests,
                new boolean []{false,false,false,false,false,false},
                new DialogInterface.OnMultiChoiceClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                        /*
                         * 第一个参数:dialog对象;
                         * 第二个参数:多选对话框中用户所选中的项;
                         * 第三个参数:是否选中,true为选中,false为没有选中
                         * 
                         */
                        //选中则添加,后悔是时还可以remove掉
                        if(isChecked){
                            choice.add(which);
                        }else{
                            choice.remove(which);
                        }
                        Toast.makeText(MainActivity4.this, "您当前的选择是:"+choice.toString(), Toast.LENGTH_LONG).show();
                    }
                })
        .setPositiveButton("确定", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(MainActivity4.this, "您最终的决定是:"+choice.toString(), Toast.LENGTH_LONG).show();
            }
        })
        .setNegativeButton("取消", null)
        .show();
        return true;
    }

    @Override
    public void onBackPressed() {
        new AlertDialog.Builder(this)
        .setIcon(R.drawable.ic_launcher)
        .setTitle("确认对话框")
        .setMessage("您真的要退出次程序吗?")
        .setPositiveButton("取消", null)
        .setNegativeButton("确定", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                finish();
                //System.exit(0);同理也可以退出
            }
        }).show();
    }
    //在适配器中只是调用方法,然后进行传参,在此类中实现接口并重写方法
    @Override
    public void btnClick(int pos) {
        Toast.makeText(this, "点击了item项中的安装按钮"+pos, Toast.LENGTH_LONG).show();
    }
}
5.运行结果

这里写图片描述

四、自定义对话框

1.上面学的对话框都是系统提供的,有时候当我们看见一个漂亮的对话框时,有没有像是看见一个漂亮de美眉,有追的冲动。所以我们应该学会自定义自己风格的对话框。
2.自定义对话框的步骤
第一步:自定义.xml布局文件;
第二步:获取LayoutLInflater对象;
第三步:调用inflate()方法获取View对象;
第四步:调用Builder对象的setView()方法设置View;
第五步:获取输入内容或者监听点击事件。
3.定义一个activity_main.xml,包含垂直在父容器顶部的按钮。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    tools:context="com.oldtogether.defineddialog.MainActivity" >

    <Button 
        android:id="@+id/btn_open"
        android:layout_width="wrap_content"
        android:layout_height="35dp"
        android:text="对话框"
        android:textColor="#eee"
        android:textSize="13sp"
        android:background="@drawable/btn_selector"
        android:layout_centerInParent="true"
        android:layout_alignParentTop="true"
        android:onClick="btnClick"/>

</RelativeLayout>
2.这里贴出btn_selector.xml(在drawable下自定义的xml文件)重新温习一下前面怎么用PhotoShop和draw9patch.bat制作一个高大尚的可拉伸的圆角按钮。代码如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- 不按下前的按钮 -->
    <item android:drawable="@drawable/btn_gn_n" android:state_pressed="false"/>
    <!-- 按下后的的按钮 -->
    <item android:drawable="@drawable/btn_h_h" android:state_pressed="true"/>
    <!-- 然后在item.xml中的 android:background="@drawable/btn_selector"此项设置 -->
</selector>
3.自定义的对话框,简单的来讲就是一个布局管理器,define_dialog.xml文件代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="32dp"
        android:orientation="vertical"
        android:background="#003">
        <TextView 
            android:text="提醒"
            android:textSize="18sp"
            android:textColor="#fff"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:paddingTop="5dp"/>
    </LinearLayout>

    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="vertical"
        android:background="#87CEFA"
        android:padding="10dp"
        >
        <TextView 
            android:text="恭喜您,验证码发送成功!"
            android:textSize="16sp"
            android:textColor="#191970"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"/>

        <Button
            android:id="@+id/btn_sure"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:background="@drawable/btn_selector"
            android:text="确定"
            android:textColor="#eee"
            android:textSize="13sp"/>

    </LinearLayout>


</LinearLayout>
4.将此布局加载到一个MainActivity.java文件中,并使用绑定标签de方法添加事件监听器。
package com.oldtogether.defineddialog;

import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    //采用在.xml定义标签的方法来添加时间监听器,其中此方法的参数表示Button对象
    Dialog dialog;//声明一个Dialog父类对象,方便调用dismiss()方法同时避免空指针
    public void btnClick(View v){
        LayoutInflater inflater = LayoutInflater.from(this);//通过静态方法获得反射器对象
        View myView = inflater.inflate(R.layout.define_dialog, null);//通过获的反射器获得自定义的视图对象
        //把自定义的视图对象,设置到对话框模板下(这样便改变了系统自带大题固定形式的对话框)
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setView(myView);
        //给我们自定义的btn_sure添加事件监听器(这里打破经典的传统方法)
        /*
         * 经典的传统方法
         * 1.Button btn;
         * 2.btn = (Button) findViewByid(R.id.btn_sure);
         * 3.btn.setOnClickListner().......
         */
        myView.findViewById(R.id.btn_sure).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                dialog.dismiss();//点击确实按钮的同时关闭按钮,疑惑解答:在dismiss时一般我们会觉得出现空指针,其实在点击事件发生之前对话框已经创建了,因此不会出现空指针
                Toast.makeText(MainActivity.this, "点击了确定", Toast.LENGTH_LONG).show();
            }
        });
        dialog = builder.create();//Dialog是AlertDialog的一个父类
        dialog.show();
    }
}
5.运行结果:

这里写图片描述
这里写图片描述
这里写图片描述

五、心得总结:

1.一个类只能继承一个父类,但可以实现多个接口(一个人只能有一个亲身父亲,但可以有不同的爱好);
2.重新温习了自定义适配器和适配器的优化,但是还需要写一个小Demo对ListView再次熟悉一下;
3.重点要培训面向对象的编程思维和编程技巧,怎样优化和简洁代码的同时高效性的反应客观复杂的事情。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值