第6天

 ClearEdittext  用户登录  注册页面 



  1.自定义ClearEdittext  




/**
 * Created by asus on 2016/10/29.
 *
 * 自定义edittext 删除所有
 */
public class ClearEditText extends EditText implements View.OnFocusChangeListener, TextWatcher {
    /**
     * 删除按钮的引用
     */
    private Drawable mClearDrawable;

    public ClearEditText(Context context) {
        super(context);
        init(context);
    }
    public ClearEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    public ClearEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {

        //获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
        mClearDrawable = getCompoundDrawables()[2];
        if (mClearDrawable == null) {
            //设置按钮
            mClearDrawable = getResources().getDrawable(R.drawable.icon_delete_32);
        }

        //设置图片的固有宽高
        mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());

        setClearIconVisible(false);//默认图标隐藏

        setOnFocusChangeListener(this);//1.焦点改变的监听

        addTextChangedListener(this);//2.设入框里面内容发生改变的监听


    }

   // 1.焦点改变的监听
    @Override
    public void onFocusChange(View v, boolean hasFocus) {

        if(hasFocus){
            setClearIconVisible(getText().length() > 0);//如果里面有值则显示
        }else{
            setClearIconVisible(false);//否则隐藏
        }


    }

    //2.设入框里面内容发生改变的监听  (复写这个方法)
    @Override
    public void onTextChanged(CharSequence s, int start, int count, int after) {
        if(isFocused()){
            setClearIconVisible(s.length() > 0);

            //设置只可以输入11位
            if(s.length()>11){
                setText(s.subSequence(0,11));
                setSelection(11);
            }
        }
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }
    @Override
    public void afterTextChanged(Editable s) {
    }




    //复写onTouchEvent处理
    /**
     * 因为我们不能直接给EditText设置点击事件,所以我们用记住我们按下的位置来模拟点击事件
     * 当我们按下的位置 在  EditText的宽度 - 图标到控件右边的间距 - 图标的宽度  和
     * EditText的宽度 - 图标到控件右边的间距之间我们就算点击了图标,竖直方向就没有考虑
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        float x = event.getX();
        if(event.getAction()==MotionEvent.ACTION_UP){//如果是抬起
            //如果图片可见
            boolean touchable = x > (getWidth() - getTotalPaddingRight())
                    && (x < ((getWidth() - getPaddingRight())));
            if(touchable){
                setText("");
            }
        }

        return super.onTouchEvent(event);
    }


    //设置图标的显示和隐藏
    private void setClearIconVisible(final boolean visible) {
        mClearDrawable.setVisible(visible,false);
        final Drawable[] compoundDrawables = getCompoundDrawables();
        //设置edittext的位置
        setCompoundDrawables(
                compoundDrawables[0],
                compoundDrawables[1],
                visible ? mClearDrawable : null,
                compoundDrawables[3]);
    }
}


2.用户登录

①.保存用户信息

/**
 * Created by asus on 2016/10/29.
 *
 * 保存的用户登录的信息
 */
public class UserLocalData {


    //保存到本地sharedpreferenc
    public static void putUser(Context context, User user){
        String user_json = JSONUtil.toJSON(user);
        PreferencesUtils.putString(context, Contants.USER_JSON,user_json);
    }

    //获取对象
    public static User getUser(Context context){
        String user_json = PreferencesUtils.getString(context, Contants.USER_JSON);
        if(!TextUtils.isEmpty(user_json)){
            User user = JSONUtil.fromJson(user_json, User.class);
            return user;
        }
        return null;
    }
    //清除本地数据
    public static void clearUser(Context context){

        PreferencesUtils.putString(context, Contants.USER_JSON,"");
    }

    //保存数据的保存时间
    public static void putToken(Context context,String token){

        PreferencesUtils.putString(context, Contants.TOKEN,token);
    }


    //token
    public static  String getToken(Context context){

        String token = PreferencesUtils.getString(context, Contants.TOKEN);

        return  token;
    }

    public static void clearToken(Context context){
        PreferencesUtils.putString(context, Contants.TOKEN,"");
    }
}

②.LoginActivity登录

/**
 * Created by asus on 2016/10/29.
 */
public class LoginActivity extends AppCompatActivity {
    @ViewInject(R.id.toolbar)
    private CnToolbar mToolBar;

    @ViewInject(R.id.etxt_phone)
    private ClearEditText mEtxtPhone;

    @ViewInject(R.id.etxt_pwd)
    private ClearEditText mEtxtPwd;

    @ViewInject(R.id.btn_login)
    private Button btn_login;

    @ViewInject(R.id.txt_toReg)//注册账号
    private TextView txt_toReg;

    private OkHttpHelper okHttpHelper ;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_login);
        ViewUtils.inject(this);
        okHttpHelper = OkHttpHelper.getInstance();

        initToolBar();

        initView();

    }

    private void initView() {
        btn_login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String phone = mEtxtPhone.getText().toString().trim();
                String telRegex = "[1][358]\\d{9}";
                if(TextUtils.isEmpty(phone)){
                    ToastUtil.showToast(LoginActivity.this, "请输入手机号码");
                    return;
                }else if(!phone.matches(telRegex)){
                    ToastUtil.showToast(LoginActivity.this, "请输入正确的手机号码");
                    return;
                }

                String pwd = mEtxtPwd.getText().toString().trim();
                if(TextUtils.isEmpty(pwd)){
                    ToastUtil.showToast(LoginActivity.this, "请输入密码");
                    return;
                }

                HashMap<String,Object> params = new HashMap<>(2);
                params.put("phone",phone);
                params.put("password", DESUtil.encode(Contants.DES_KEY,pwd));//加密后的密码,服务器使用这个解密登录

                //通过请求数据会返回  1.数据(名字,图片,id,email) 2.token
                okHttpHelper.post(Contants.API.LOGIN, params, new SpotsCallBack<LoginRespMsg<User>>(LoginActivity.this,true) {

                    @Override
                    public void onSuccess(Response response, LoginRespMsg<User> userLoginRespMsg) {

                        MyApplication application =  MyApplication.getInstance();

                        application.putUser(userLoginRespMsg.getData(), userLoginRespMsg.getToken());//将数据保存到本地


                        ToastUtil.showToast(LoginActivity.this,"登录成功");

                        setResult(RESULT_OK);

                        finish();

                        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                        // 隐藏软键盘
                        imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
                    }

                    @Override
                    public void onError(Response response, int code, Exception e) {

                    }
                });
            }


        });

        //注册按钮
        txt_toReg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(LoginActivity.this, RegActivity.class);
                startActivity(intent);
            }
        });
    }

    private void initToolBar() {

        mToolBar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();//结束页面

                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                // 隐藏软键盘
                imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
            }
        });

    }


}


3.注册账号---------SmsSdk




①.注册页面

public class RegActivity extends Activity {

    private static final String TAG = "RegActivity";
    // 默认使用中国区号
    private static final String DEFAULT_COUNTRY_ID = "42";

    @ViewInject(R.id.toolbar)//toolbar
    private CnToolbar mToolBar;

    @ViewInject(R.id.txtCountry)//国家名字
    private TextView mTxtCountry;

    @ViewInject(R.id.txtCountryCode)//国家的手机编号+86
    private TextView mTxtCountryCode;

    @ViewInject(R.id.edittxt_phone)//电话号码
    private ClearEditText mEtxtPhone;


    @ViewInject(R.id.edittxt_pwd)//密码
    private ClearEditText mEtxtPwd;

    private  SMSEvenHanlder evenHanlder;//自定义gui

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_reg);
        ViewUtils.inject(this);

        initToolBar();

        initSMSSDK();

    }

    //
    private void initSMSSDK() {

        SMSSDK.initSDK(this, Contants.APPKEY, Contants.APPSRECT);
        evenHanlder = new SMSEvenHanlder();
        SMSSDK.registerEventHandler(evenHanlder);//注册


        String[] country = SMSSDK.getCountry(DEFAULT_COUNTRY_ID);//设置默认的国家和电话号码+86
        if (country != null) {

            mTxtCountryCode.setText("+"+country[1]);//编号

            mTxtCountry.setText(country[0]);//国家名字

        }
    }

    private void initToolBar() {
        mToolBar.setRightButtonText("下一步");
        mToolBar.setmRightImageButtonOnclickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //点击时提交电话和国编号到服务器
                getCode();

            }
        });

        mToolBar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });

    }


    //自定义handler 回调请求成功
    class SMSEvenHanlder extends EventHandler {
        @Override
        public void afterEvent(final int event, final int result, final Object data) {
            super.afterEvent(event, result, data);

            runOnUiThread(new Runnable() {
                public void run() {

                    if (result == SMSSDK.RESULT_COMPLETE) {
                        if (event == SMSSDK.EVENT_GET_SUPPORTED_COUNTRIES) {
                            
                            // 请求支持国家列表
                            onCountryListGot((ArrayList<HashMap<String, Object>>) data);
                            
                        } else if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE) {
                            // 请求验证码后,跳转到验证码填写页面
                            boolean smart = (Boolean) data;
                            afterVerificationCodeRequested(smart);
                        }
                    } else {
                        if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE
                                && data != null
                                && (data instanceof UserInterruptException)) {
                            // 由于此处是开发者自己决定要中断发送的,因此什么都不用做
                            return;
                        }

                        // 根据服务器返回的网络错误,给toast提示
                        try {
                            ((Throwable) data).printStackTrace();
                            Throwable throwable = (Throwable) data;

                            JSONObject object = new JSONObject(
                                    throwable.getMessage());
                            String des = object.optString("detail");
                            if (!TextUtils.isEmpty(des)) {
                                ToastUtil.showToast(RegActivity.this, des);
                                return;
                            }
                        } catch (Exception e) {
                            SMSLog.getInstance().w(e);
                        }

                    }
                }
            });
        }
    }

    //提交电话号码和国家编号code服务器
    private void getCode(){

        String phone = mEtxtPhone.getText().toString().trim().replaceAll("\\s*", "");
        String code = mTxtCountryCode.getText().toString().trim();
        String pwd = mEtxtPwd.getText().toString().trim();

        checkPhoneNum(phone,code);

        //not 86   +86  请求获取短信验证码
        SMSSDK.getVerificationCode(code,phone);

    }


    //提交时检查电话号码
    private void checkPhoneNum(String phone, String code) {
        if (code.startsWith("+")) {
            code = code.substring(1);
        }

        if (TextUtils.isEmpty(phone)) {
            ToastUtil.showToast(this, "请输入手机号码");
            return;
        }

        if (code == "86") {
            if(phone.length() != 11) {
                ToastUtil.showToast(this,"手机号码长度不对");
                return;
            }

        }

        String rule = "^1(3|5|7|8|4)\\d{9}";
        Pattern p = Pattern.compile(rule);
        Matcher m = p.matcher(phone);

        if (!m.matches()) {
            ToastUtil.showToast(this,"您输入的手机号码格式不正确");
            return;
        }

    }

    // 解析国家列表
    private void onCountryListGot(ArrayList<HashMap<String, Object>> countries) {

        for (HashMap<String, Object> country : countries) {
            String code = (String) country.get("zone");
            String rule = (String) country.get("rule");
            if (TextUtils.isEmpty(code) || TextUtils.isEmpty(rule)) {
                continue;
            }

            Log.d(TAG, "code=" + code + "rule=" + rule);
        }

    }


    /** 请求验证码后,跳转到验证码填写页面 */
    private void afterVerificationCodeRequested(boolean smart) {
                                    //如果里面包含了空白字符,换行之类的就用空格代替
        String phone = mEtxtPhone.getText().toString().trim().replaceAll("\\s*", "");
        String code = mTxtCountryCode.getText().toString().trim();
        String pwd = mEtxtPwd.getText().toString().trim();

        if (code.startsWith("+")) {
            code = code.substring(1);
        }

        Intent intent = new Intent(this,RegSecondActivity.class);
        intent.putExtra("phone",phone);
        intent.putExtra("pwd",pwd);
        intent.putExtra("countryCode",code);

        startActivity(intent);
        finish();
    }


    private String[] getCurrentCountry() {
        String mcc = getMCC();
        String[] country = null;
        if (!TextUtils.isEmpty(mcc)) {
            country = SMSSDK.getCountryByMCC(mcc);
        }

        if (country == null) {
            Log.w("SMSSDK", "no country found by MCC: " + mcc);
            country = SMSSDK.getCountry(DEFAULT_COUNTRY_ID);
        }
        return country;
    }

    private String getMCC() {
        TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
        // 返回当前手机注册的网络运营商所在国家的MCC+MNC. 如果没注册到网络就为空.
        String networkOperator = tm.getNetworkOperator();
        if (!TextUtils.isEmpty(networkOperator)) {
            return networkOperator;
        }

        // 返回SIM卡运营商所在国家的MCC+MNC. 5位或6位. 如果没有SIM卡返回空
        return tm.getSimOperator();
    }



    @Override
    protected void onDestroy() {
        super.onDestroy();
//        SMSSDK.unregisterAllEventHandler();
        Log.d("share","已经执行");
        SMSSDK.unregisterEventHandler(evenHanlder);
    }
}

     /*  //打开注册页面
        RegisterPage registerPage = new RegisterPage();
        registerPage.setRegisterCallback(new EventHandler() {
            public void afterEvent(int event, int result, Object data) {
             // 解析注册结果
                if (result == SMSSDK.RESULT_COMPLETE) {

                    HashMap<String,Object> phoneMap = (HashMap<String, Object>) data;
                    String country = (String) phoneMap.get("country");
                    String phone = (String) phoneMap.get("phone");

                // 提交用户信息(此方法可以不调用)
                // registerUser(country, phone);
                }
            }
        });
        registerPage.show(this);
*/


.验证码页面

/**
 * Created by asus on 2016/10/30.
 */
public class RegSecondActivity extends AppCompatActivity {
    @ViewInject(R.id.toolbar)//toolbar
    private CnToolbar mToolBar;

    @ViewInject(R.id.txtTip)//验证码已发送的文字显示
    private TextView mTxtTip;

    @ViewInject(R.id.btn_reSend)//重新获取验证码的按钮
    private Button mBtnResend;

    @ViewInject(R.id.edittxt_code)//edittext验证码
    private ClearEditText mEtCode;

    private String phone;
    private String pwd;
    private String countryCode;

    private SpotsDialog dialog;
    private OkHttpHelper okHttpHelper = OkHttpHelper.getInstance();
    private SMSEvenHanlder evenHanlder;

    private CountTimerView countTimerView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_reg_second);
        ViewUtils.inject(this);

        getMesFromRegActivity();//获取的电话.密码.国家区号

        initSMSSDK();

        initToolBar();//toolbar

        initTexTip();//已发送短信到---text

        initCountTimer();//定时器




    }

    /*1.初始化SMSSDK*/
    private void initSMSSDK() {
        SMSSDK.initSDK(this, Contants.APPKEY, Contants.APPSRECT);
        evenHanlder = new SMSEvenHanlder();//自定义gui
        SMSSDK.registerEventHandler(evenHanlder);//注册

        dialog = new SpotsDialog(this);
        dialog = new SpotsDialog(this, "正在校验验证码");
    }

    /*2.点击完成按钮提交服务器*/
    private void submitCode() {

        String vCode = mEtCode.getText().toString().trim();//验证码

        if (TextUtils.isEmpty(vCode)) {
            //如果为null返回
            ToastUtil.showToast(this, R.string.smssdk_write_identify_code + "");
            return;
        }


        //提交验证码验证(国家编号,电话,验证码)
        SMSSDK.submitVerificationCode(countryCode, phone, vCode);
        dialog.show();
    }

    /*3.sdk回调*/
    class SMSEvenHanlder extends EventHandler {
        @Override
        public void afterEvent(final int event, final int result, final Object data) {

            runOnUiThread(new Runnable() {
                public void run() {
                    //回调的时候就隐藏dialog
                    if (dialog != null && dialog.isShowing())
                        dialog.dismiss();
                    Log.d("回调了","回调了2");

                    if (result == SMSSDK.RESULT_COMPLETE) {//如果请求完成之后

                        if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE) {

                            /*4.验证成功,提交信息到注册服务器,或者执行另外操作*/
                            doReg();
                            dialog.setMessage("正在提交注册信息");
                            dialog.show();

                        }else{
                            if (dialog != null && dialog.isShowing())
                                dialog.dismiss();
                            ToastUtil.showToast(RegSecondActivity.this,"不是提交");
                        }
                    } else {
                        if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE
                                && data != null
                                && (data instanceof UserInterruptException)) {
                            // 由于此处是开发者自己决定要中断发送的,因此什么都不用做
                            ToastUtil.showToast(RegSecondActivity.this,"中断发送");
                            Log.d("回调了","中断发送");
                            return;
                        }

                        // 根据服务器返回的网络错误,给toast提示
                        if (dialog != null && dialog.isShowing())
                            dialog.dismiss();
                        ToastUtil.showToast(RegSecondActivity.this,"网络错误");

                        try {
                            ((Throwable) data).printStackTrace();
                            Throwable throwable = (Throwable) data;

                            JSONObject object = new JSONObject(
                                    throwable.getMessage());
                            String des = object.optString("detail");
                            if (!TextUtils.isEmpty(des)) {
                                ToastUtil.showToast(RegSecondActivity.this, des);
                                return;
                            }
                        } catch (Exception e) {
                            SMSLog.getInstance().w(e);
                        }

                    }
                }
            });
        }
    }

    private void doReg() {
        HashMap<String, Object> parmas = new HashMap<>(2);
        parmas.put("phone", phone);
        parmas.put("password", DESUtil.encode(Contants.DES_KEY, pwd));

        okHttpHelper.post(Contants.API.REG,parmas, new SpotsCallBack<LoginRespMsg<User>>(this,false) {

            @Override
            public void onSuccess(Response response, LoginRespMsg<User> userLoginRespMsg) {

                if(dialog !=null && dialog.isShowing())
                    dialog.dismiss();

                if(userLoginRespMsg.getStatus()==LoginRespMsg.STATUS_ERROR){
                    ToastUtil.showToast(RegSecondActivity.this,"注册失败:"+userLoginRespMsg.getMessage());
                    startActivity(new Intent(RegSecondActivity.this,LoginActivity.class));
                    RegSecondActivity.this.finish();
                    return;

                }

                //保存数据 ( email,名字,等)  和  token
                MyApplication application =MyApplication.getInstance();
                application.putUser(userLoginRespMsg.getData(), userLoginRespMsg.getToken());

                //回到MainActivity
                startActivity(new Intent(RegSecondActivity.this,MainActivity.class));

                finish();
            }


            @Override
            public void onError(Response response, int code, Exception e) {
                if(dialog !=null && dialog.isShowing())
                    dialog.dismiss();

                //回到MainActivity
                startActivity(new Intent(RegSecondActivity.this,MainActivity.class));

                finish();
            }

            @Override
            public void onTokenError(Response response, int code) {
                super.onTokenError(response, code);
            }
        });

    }


    private void initToolBar() {
        mToolBar.setRightButtonText("完成");

        //完成按钮
        mToolBar.setmRightImageButtonOnclickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                submitCode();//点击完成提交给服务器对比验证码
            }
        });

        //上一步按钮
        mToolBar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(RegSecondActivity.this,RegActivity.class));
                finish();
            }
        });

    }

    //重新获取验证码
    @OnClick(R.id.btn_reSend)
    public void reSendCode(View view) {

        SMSSDK.getVerificationCode("+" + countryCode, phone);//重新获取验证码

        countTimerView = new CountTimerView(mBtnResend, R.string.smssdk_resend_identify_code);
        countTimerView.start();

        dialog.setMessage("正在重新获取验证码");
        dialog.show();
    }

    private void initCountTimer() {
        CountTimerView timerView = new CountTimerView(mBtnResend);
        timerView.start();
    }

    private void getMesFromRegActivity() {
        phone = getIntent().getStringExtra("phone");
        pwd = getIntent().getStringExtra("pwd");
        countryCode = getIntent().getStringExtra("countryCode");
    }

    private void initTexTip() {
        String formatedPhone = "+" + countryCode + " " + splitPhoneNum(phone);
        String text = getString(R.string.smssdk_send_mobile_detail) + formatedPhone;
        mTxtTip.setText(Html.fromHtml(text));//将smssdk中的html格式代码进行格式化成字符串
    }


    /**
     * 分割电话号码
     */
    private String splitPhoneNum(String phone) {
        StringBuilder builder = new StringBuilder(phone);
        builder.reverse();
        for (int i = 4, len = builder.length(); i < len; i += 5) {
            builder.insert(i, ' ');
        }
        builder.reverse();
        return builder.toString();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        SMSSDK.unregisterEventHandler(evenHanlder);
    }


}

③.按钮计时器

/**
 * Created by asus on 2016/10/30.
 */
public class CountTimerView extends CountDownTimer {

    public static final int TIME_COUNT = 61000;//时间防止从59s开始显示(以倒计时60s为例子)
    private TextView btn;//传入进来的按钮(textView的子类是button)
    private int endStrRid;//显示的文字

    /**
     * 参数 millisInFuture       倒计时总时间(如60S,120s等)
     * 参数 countDownInterval    渐变时间(每次倒计1s)
     * 参数 btn   点击的按钮(因为Button是TextView子类,为了通用我的参数设置为TextView)
     * 参数 endStrRid   倒计时结束后,按钮对应显示的文字
     */
    public CountTimerView(long millisInFuture, long countDownInterval, TextView btn, int endStrRid) {
        super(millisInFuture, countDownInterval);
        this.btn = btn;
        this.endStrRid = endStrRid;
    }

    public CountTimerView(TextView btn, int endStrRid) {
        super(TIME_COUNT, 1000);//设置总时间为61s,渐变1s
        this.btn = btn;
        this.endStrRid = endStrRid;
    }

    public CountTimerView(TextView btn) {
        super(TIME_COUNT, 1000);
        this.btn = btn;
        this.endStrRid = R.string.smssdk_resend_identify_code;//重新获取验证码
    }


    //倒计时中
    @Override
    public void onTick(long millisUntilFinished) {
        btn.setEnabled(false);
        btn.setText(millisUntilFinished / 1000 + " 秒后可重新发送");
    }

    //倒计时完成调用
    @Override
    public void onFinish() {
        btn.setText(endStrRid);
        btn.setEnabled(true);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值