textview.setText()造成焦点丢失

在自定义控件开发中,发现特定代码逻辑可能导致控件焦点丢失。当文本为空或为null时隐藏标题,这一操作似乎是触发焦点丢失的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在做自定义控件的时候,发现构造函数里面如果设置这行代码,就会造成自定义控件焦点丢失,目前不清楚原因

        if (text.equals("") || text == null) {
            title.setVisibility(View.GONE);
        }
package com.example.kucun2.data; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import androidx.annotation.NonNull; import androidx.room.Database; import androidx.room.Room; import androidx.room.RoomDatabase; import androidx.room.migration.Migration; import androidx.sqlite.db.SupportSQLiteDatabase; import com.example.kucun2.entity.User; import java.io.File; @Database(entities = {User.class}, version = 2, exportSchema = false ) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); private static volatile AppDatabase INSTANCE; public static AppDatabase getDatabase(Context context) { return Room.databaseBuilder(context, AppDatabase.class, "users.db") .addMigrations(MIGRATION_1_2) .addCallback(new RoomDatabase.Callback() { @Override public void onOpen(@NonNull SupportSQLiteDatabase db) { // 确保视图存在 db.execSQL("CREATE VIEW IF NOT EXISTS user_summary AS SELECT id, name FROM users"); } }) .fallbackToDestructiveMigrationOnDowngrade() .build(); } private static void migrateFromLegacy(Context context) { // 旧数据库迁移逻辑 SQLiteDatabase legacyDb = SQLiteDatabase.openDatabase( context.getDatabasePath("users.db").getPath(), null, SQLiteDatabase.OPEN_READONLY); Cursor cursor = legacyDb.rawQuery("SELECT * FROM users", null); // 数据迁移到Room数据库 UserDao dao = INSTANCE.userDao(); // 使用事务保证迁移完整性 INSTANCE.runInTransaction(() -> { while (cursor.moveToNext()) { User user = new User(cursor.getInt(0), cursor.getString(1), cursor.getString(2), cursor.getString(3), cursor.getInt(4) ); dao.insert(user); } cursor.close(); legacyDb.close(); }); } private static final Migration MIGRATION_1_2 = new Migration(1, 2) { @Override public void migrate(@NonNull SupportSQLiteDatabase db) { // 示例:添加新字段 // 示例:创建视图(不修改表结构) db.execSQL("CREATE TABLE users_temp (id INTEGER PRIMARY KEY, " + "name TEXT, " + "andy TEXT, " + "pass TEXT, " + "role INTEGER)" + ""); // 3. 迁移数据 db.execSQL("INSERT INTO users_temp (id, name, andy, pass, role) " + "SELECT id, name, andy, pass, role FROM users"); // 4. 删除旧表并重命名 db.execSQL("DROP TABLE users"); db.execSQL("ALTER TABLE users_temp RENAME TO users"); // 5. 维护视图 db.execSQL("DROP VIEW IF EXISTS user_summary"); db.execSQL("CREATE VIEW user_summary AS SELECT id, name FROM users"); } }; public static void deleteDatabase(Context context) { // 1. 关闭现有连接 if (INSTANCE != null) { INSTANCE.close(); INSTANCE = null; } // 2. 删除物理文件 context.deleteDatabase("users.db"); // 3. 清理残留文件(WAL/SHM) File databaseDir = context.getDatabasePath("users.db").getParentFile(); if (databaseDir != null) { for (File file : databaseDir.listFiles()) { if (file.getName().startsWith("users.db")) { file.delete(); } } } } }package com.example.kucun2.ui.moban; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.graphics.Rect; import android.os.Bundle; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.DecelerateInterpolator; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import com.example.kucun2.Http.HttpApi; import com.example.kucun2.Http.ReturnMethod; import com.example.kucun2.R; import com.example.kucun2.data.AppDatabase; import com.example.kucun2.entity.User; import com.example.kucun2.manager.AuthManager; import java.io.File; public class MainActivity extends AppCompatActivity implements View.OnClickListener, View.OnFocusChangeListener, ViewTreeObserver.OnGlobalLayoutListener, TextWatcher { private String TAG = "ifu25"; private ImageButton mIbNavigationBack; private LinearLayout mLlLoginPull; private View mLlLoginLayer; private LinearLayout mLlLoginOptions; private EditText mEtLoginUsername; private EditText mEtLoginPwd; private LinearLayout mLlLoginUsername; private ImageView mIvLoginUsernameDel; private Button mBtLoginSubmit; private LinearLayout mLlLoginPwd; private ImageView mIvLoginPwdDel; private ImageView mIvLoginLogo; private LinearLayout mLayBackBar; private TextView mTvLoginForgetPwd; private Button mBtLoginRegister; private CheckBox cbAgree; //全局Toast private Toast mToast; private int mLogoHeight; private int mLogoWidth; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); initView(); } //初始化视图 private void initView() { //登录层、下拉层、其它登录方式层 mLlLoginPull = findViewById(R.id.ll_login_pull); mLlLoginOptions = findViewById(R.id.ll_login_options); //导航栏+返回按钮 mLayBackBar = findViewById(R.id.ly_retrieve_bar); mIbNavigationBack = findViewById(R.id.ib_navigation_back); //logo mIvLoginLogo = findViewById(R.id.iv_login_logo); //username mLlLoginUsername = findViewById(R.id.ll_login_username); mEtLoginUsername = findViewById(R.id.et_login_username); mIvLoginUsernameDel = findViewById(R.id.iv_login_username_del); //passwd mLlLoginPwd = findViewById(R.id.ll_login_pwd); mEtLoginPwd = findViewById(R.id.et_login_pwd); mIvLoginPwdDel = findViewById(R.id.iv_login_pwd_del); //提交、注册 mBtLoginSubmit = findViewById(R.id.bt_login_submit); //忘记密码 mTvLoginForgetPwd = findViewById(R.id.tv_login_forget_pwd); mTvLoginForgetPwd.setOnClickListener(this); //注册点击事件 mLlLoginPull.setOnClickListener(this); mIbNavigationBack.setOnClickListener(this); mEtLoginUsername.setOnClickListener(this); mIvLoginUsernameDel.setOnClickListener(this); mBtLoginSubmit.setOnClickListener(this); mEtLoginPwd.setOnClickListener(this); mIvLoginPwdDel.setOnClickListener(this); findViewById(R.id.ib_login_weibo).setOnClickListener(this); findViewById(R.id.ib_login_qq).setOnClickListener(this); findViewById(R.id.ib_login_wx).setOnClickListener(this); //注册其它事件 mLayBackBar.getViewTreeObserver().addOnGlobalLayoutListener(this); mEtLoginUsername.setOnFocusChangeListener(this); mEtLoginUsername.addTextChangedListener(this); mEtLoginPwd.setOnFocusChangeListener(this); mEtLoginPwd.addTextChangedListener(this); cbAgree = findViewById(R.id.cb_remember_login); cbAgree.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { Toast.makeText(this, "已同意协议", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "请阅读并同意协议", Toast.LENGTH_SHORT).show(); } }); } @SuppressLint("NonConstantResourceId") @Override public void onClick(View view) { switch (view.getId()) { case R.id.ib_navigation_back: //返回 finish(); break; case R.id.et_login_username: mEtLoginPwd.clearFocus(); mEtLoginUsername.setFocusableInTouchMode(true); mEtLoginUsername.requestFocus(); break; case R.id.et_login_pwd: mEtLoginUsername.clearFocus(); mEtLoginPwd.setFocusableInTouchMode(true); mEtLoginPwd.requestFocus(); break; case R.id.iv_login_username_del: //清空用户名 mEtLoginUsername.setText(null); break; case R.id.iv_login_pwd_del: //清空密码 mEtLoginPwd.setText(null); break; case R.id.bt_login_submit: //登录 loginRequest(); break; case R.id.tv_login_forget_pwd: //忘记密码 startActivity(new Intent(MainActivity.this, ForgetPwdActivity.class)); break; case R.id.ll_login_pull: mLlLoginPull.animate().cancel(); mLlLoginLayer.animate().cancel(); int height = mLlLoginOptions.getHeight(); float progress = (mLlLoginLayer.getTag() != null && mLlLoginLayer.getTag() instanceof Float) ? (float) mLlLoginLayer.getTag() : 1; int time = (int) (360 * progress); if (mLlLoginPull.getTag() != null) { mLlLoginPull.setTag(null); glide(height, progress, time); } else { mLlLoginPull.setTag(true); upGlide(height, progress, time); } break; case R.id.ib_login_weibo: weiboLogin(); break; case R.id.ib_login_qq: qqLogin(); break; case R.id.ib_login_wx: weixinLogin(); break; default: break; } } //用户名密码焦点改变 @Override public void onFocusChange(View v, boolean hasFocus) { int id = v.getId(); if (id == R.id.et_login_username) { if (hasFocus) { mLlLoginUsername.setActivated(true); mLlLoginPwd.setActivated(false); } } else { if (hasFocus) { mLlLoginPwd.setActivated(true); mLlLoginUsername.setActivated(false); } } } /** * menu glide * * @param height height * @param progress progress * @param time time */ private void glide(int height, float progress, int time) { mLlLoginPull.animate() .translationYBy(height - height * progress) .translationY(height) .setDuration(time) .start(); mLlLoginLayer.animate() .alphaBy(1 * progress) .alpha(0) .setDuration(time) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationCancel(Animator animation) { if (animation instanceof ValueAnimator) { mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); } } @Override public void onAnimationEnd(Animator animation) { if (animation instanceof ValueAnimator) { mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); } mLlLoginLayer.setVisibility(View.GONE); } }) .start(); } /** * menu up glide * * @param height height * @param progress progress * @param time time */ private void upGlide(int height, float progress, int time) { mLlLoginPull.animate() .translationYBy(height * progress) .translationY(0) .setDuration(time) .start(); mLlLoginLayer.animate() .alphaBy(1 - progress) .alpha(1) .setDuration(time) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mLlLoginLayer.setVisibility(View.VISIBLE); } @Override public void onAnimationCancel(Animator animation) { if (animation instanceof ValueAnimator) { mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); } } @Override public void onAnimationEnd(Animator animation) { if (animation instanceof ValueAnimator) { mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); } } }) .start(); } //显示或隐藏logo @Override public void onGlobalLayout() { final ImageView ivLogo = this.mIvLoginLogo; Rect KeypadRect = new Rect(); mLayBackBar.getWindowVisibleDisplayFrame(KeypadRect); int screenHeight = mLayBackBar.getRootView().getHeight(); int keypadHeight = screenHeight - KeypadRect.bottom; //隐藏logo if (keypadHeight > 300 && ivLogo.getTag() == null) { final int height = ivLogo.getHeight(); final int width = ivLogo.getWidth(); this.mLogoHeight = height; this.mLogoWidth = width; ivLogo.setTag(true); ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0); valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); valueAnimator.addUpdateListener(animation -> { float animatedValue = (float) animation.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = ivLogo.getLayoutParams(); layoutParams.height = (int) (height * animatedValue); layoutParams.width = (int) (width * animatedValue); ivLogo.requestLayout(); ivLogo.setAlpha(animatedValue); }); if (valueAnimator.isRunning()) { valueAnimator.cancel(); } valueAnimator.start(); } //显示logo else if (keypadHeight < 300 && ivLogo.getTag() != null) { final int height = mLogoHeight; final int width = mLogoWidth; ivLogo.setTag(null); ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); valueAnimator.addUpdateListener(animation -> { float animatedValue = (float) animation.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = ivLogo.getLayoutParams(); layoutParams.height = (int) (height * animatedValue); layoutParams.width = (int) (width * animatedValue); ivLogo.requestLayout(); ivLogo.setAlpha(animatedValue); }); if (valueAnimator.isRunning()) { valueAnimator.cancel(); } valueAnimator.start(); } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } //用户名密码输入事件 @Override public void afterTextChanged(Editable s) { String username = mEtLoginUsername.getText().toString().trim(); String pwd = mEtLoginPwd.getText().toString().trim(); //是否显示清除按钮 if (username.length() > 0) { mIvLoginUsernameDel.setVisibility(View.VISIBLE); } else { mIvLoginUsernameDel.setVisibility(View.INVISIBLE); } if (pwd.length() > 0) { mIvLoginPwdDel.setVisibility(View.VISIBLE); } else { mIvLoginPwdDel.setVisibility(View.INVISIBLE); } //登录按钮是否可用 if (!TextUtils.isEmpty(pwd) && !TextUtils.isEmpty(username)) { mBtLoginSubmit.setBackgroundResource(R.drawable.bg_login_submit); mBtLoginSubmit.setTextColor(ContextCompat.getColor(this,R.color.white)); } else { mBtLoginSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); mBtLoginSubmit.setTextColor(ContextCompat.getColor(this,R.color.account_lock_font_color)); } } //登录 private void loginRequest() { AppDatabase.deleteDatabase(this); // 验证是否删除成功 File dbFile = this.getDatabasePath("users.db"); if (!dbFile.exists()) { Log.d("Database", "数据库已彻底删除"); } String andy=mEtLoginUsername.getText().toString(); String pass=mEtLoginPwd.getText().toString(); Context context=this; try { HttpApi.HttpPost(getString(R.string.url_baidu), new User(0, null, andy, pass, 0), new ReturnMethod() { @Override public void Success(String data) { Log.d("success",data); // Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show(); User user =new User(0,"12323123","3211231","12312",0); AuthManager Auth=new AuthManager(context); Auth.register(user) ; Log.d("sql",""+ user.toString()); Log.d("sql",""+ Auth.login(user.getAndy(),user.getPass()) ); } @Override public void failed(String data) { } @Override public void error(Exception e) { // Toast.makeText(MainActivity.this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); Log.d("error",e.getLocalizedMessage()); } }); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } //微博登录 private void weiboLogin() { } //QQ登录 private void qqLogin() { } //微信登录 private void weixinLogin() { } /** * 显示Toast * * @param msg 提示信息内容 */ private void showToast(int msg) { if (null != mToast) { mToast.setText(msg); } else { mToast = Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT); } mToast.show(); } } package com.example.kucun2.entity; import androidx.room.Entity; import androidx.room.Ignore; import androidx.room.PrimaryKey; @Entity(tableName = "users") public class User { @PrimaryKey(autoGenerate = true) private Integer id; private String name; private String andy; private String pass; private Integer role; public int getId() { return id; } public String getName() { return name; } public String getAndy() { return andy; } public String getPass() { return pass; } public int getRole() { return role; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setAndy(String andy) { this.andy = andy; } public void setPass(String pass) { this.pass = pass; } public void setRole(int role) { this.role = role; } @Ignore public User(int id, String name, String andy, String pass, int role) { this.id = id; this.name = name; this.andy = andy; this.pass = pass; this.role = role; } public User() { } @Override public String toString() { StringBuilder sb = new StringBuilder("{"); // 处理属性名 sb.append("\"id\": "); // 处理不同数据类型 // 其他对象类型 sb.append((id != null) ? id : "null"); sb.append(","); // 处理属性名 sb.append("\"name\": "); // 处理不同数据类型 // 字符串类型处理(含转义) sb.append("\"") .append(name .replace("\\", "\\\\") .replace("\"", "\\\"") .replace("\b", "\\b") .replace("\f", "\\f") .replace("\n", "\\n") .replace("\r", "\\r") .replace("\t", "\\t")) .append("\""); sb.append(","); // 处理属性名 sb.append("\"andy\": "); // 处理不同数据类型 // 字符串类型处理(含转义) sb.append("\"") .append(andy .replace("\\", "\\\\") .replace("\"", "\\\"") .replace("\b", "\\b") .replace("\f", "\\f") .replace("\n", "\\n") .replace("\r", "\\r") .replace("\t", "\\t")) .append("\""); sb.append(","); // 处理属性名 sb.append("\"pass\": "); // 处理不同数据类型 // 字符串类型处理(含转义) sb.append("\"") .append(pass .replace("\\", "\\\\") .replace("\"", "\\\"") .replace("\b", "\\b") .replace("\f", "\\f") .replace("\n", "\\n") .replace("\r", "\\r") .replace("\t", "\\t")) .append("\""); sb.append(","); // 处理属性名 sb.append("\"role\": "); // 处理不同数据类型 // 其他对象类型 sb.append((role != null) ? role : "null"); sb.append("}"); return sb.toString(); } } package com.example.kucun2.manager; import android.content.Context; import androidx.room.Room; import com.example.kucun2.data.AppDatabase; import com.example.kucun2.data.UserDao; import com.example.kucun2.entity.User; import at.favre.lib.crypto.bcrypt.BCrypt; public class AuthManager { private final BCrypt.Hasher hasher = BCrypt.with(BCrypt.Version.VERSION_2Y); private final UserDao userDao; public AuthManager(Context context) { AppDatabase db = Room.databaseBuilder( context, AppDatabase.class, "app-db" ).build(); userDao = db.userDao(); } public boolean register(User user) { // 密码强度校验 if (!validatePassword(user.getPass())) return false; // 生成BCrypt哈希(自动处理盐值) String hash = hasher.hashToString(12, user.getPass().toCharArray()); // 异步插入数据库 new Thread(() -> { User us = new User(0,"000000",user.getAndy(),hash,0); userDao.insertUser(us); }).start(); return true; } private boolean validatePassword(String password) { return password.length() >= 8 && password.matches(".*[A-Z].*") && password.matches(".*\\d.*"); } public boolean login(String username, String password) { User user = userDao.findUserByUsername(username); if (user == null) return false; BCrypt.Result result = BCrypt.verifyer().verify( password.toCharArray(), user.getPass() ); return result.verified; } }
05-31
<think>我们正在处理一个Android开发问题:用户想设置TextView的文本内容,但遇到了问题。根据引用,常见问题包括: 1.调用setTextTextView不刷新(引用[1]和[3])->可能是UI线程问题2.空对象引用(引用[2])-> TextView对象为null用户当前问题描述:"我想设置文本视图的内容请问Android TextViewsetTextmsg"因此,我们需要指导用户正确使用TextViewsetText方法,并避免常见错误。 步骤: 1.确保TextView对象不为null(正确初始化)2.在主线程(UI线程)中更新TextView具体实现: -在Activity或Fragment中,通常通过findViewById获取TextView对象,并确保布局已正确加载(setContentView之后)。 -如果需要在非UI线程更新TextView,必须使用runOnUiThread(Activity中)或Handler或View.post等方式切换到UI线程。示例代码(在Activity中): ```javapublic classMainActivityextends AppCompatActivity {privateTextView mTextView;@Overrideprotectedvoid onCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化TextViewmTextView =findViewById(R.id.text_view);//示例:设置文本setText("HelloWorld");}//在主线程中设置文本privatevoid setText(Stringtext){mTextView.setText(text);}//如果在非UI线程中需要设置文本,可以这样:privatevoid setTextInBackground(finalString text) {newThread(newRunnable(){@Overridepublic voidrun(){//在后台线程中,不能直接调用setText,需要切换到UI线程runOnUiThread(newRunnable(){@Overridepublic voidrun(){mTextView.setText(text);}});}}).start();} }``` 注意事项: 1.空指针异常:确保mTextView不为null,即findViewById返回了有效的视图(检查布局文件中是否有id为text_view的TextView)。 2.线程问题:在非UI线程更新UI会导致异常或更新不生效,必须使用上述方法切换到UI线程。 根据引用[3]:非主线程不能调用textView.setText,必须通过回调(如使用Handler或Activity的runOnUiThread)来更新。如果用户遇到空指针异常(如引用[2]),请检查:-是否在setContentView之前调用了findViewById?-布局文件中是否包含该TextView且id正确? -是否在Fragment中,而findViewById是在Activity中调用的(应该使用Fragment的视图)?如果遇到不刷新,检查是否在正确的线程中更新。相关问题: 1.如何在Android中更新UI线程? 2.如何避免TextView的空指针异常?3.如何在Fragment中设置TextView的文本?</think>### Android TextView setText 方法详解 在Android中设置TextView文本内容的基本方法是使用`setText()`,但需要注意线程安全和空指针问题。以下是正确使用方式: #### 1. 基础用法(UI线程中) ```java // 在Activity/Fragment的UI线程中直接调用 TextView textView = findViewById(R.id.textView); textView.setText("Hello World"); // 设置普通文本 textView.setText(R.string.app_name); // 设置字符串资源 ``` #### 2. 非UI线程更新(关键!) 根据引用[3],**禁止在非UI线程直接调用setText**,必须通过以下方式切换线程: ```java // 方式1:使用runOnUiThread(Activity中) new Thread(() -> { String msg = "后台计算的结果"; runOnUiThread(() -> textView.setText(msg)); }).start(); // 方式2:使用Handler Handler mainHandler = new Handler(Looper.getMainLooper()); new Thread(() -> { String msg = "处理后的数据"; mainHandler.post(() -> textView.setText(msg)); }).start(); ``` #### 3. 常见问题解决 - **文本不刷新问题**(引用[1]): - 确保在UI线程更新 - 检查`textView.invalidate()`或`textView.requestLayout()`是否被错误移除 - **空指针异常**(引用[2]): ```java // 错误:未初始化TextView TextView textView; // 未赋值 textView.setText("msg"); // 触发NullPointerException // 正确:通过findViewById初始化 setContentView(R.layout.activity_main); // 先设置布局 TextView textView = findViewById(R.id.textView); // 再获取视图 ``` #### 4. 特殊文本处理 ```java // 设置HTML格式文本(需转义) textView.setText(Html.fromHtml("<b>加粗文本</b>", Html.FROM_HTML_MODE_COMPACT)); // 设置Spannable富文本 SpannableString spannable = new SpannableString("彩色文本"); spannable.setSpan(new ForegroundColorSpan(Color.RED), 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(spannable); ``` > **关键原则**:所有UI操作(包括setText)必须在主线程执行,后台线程需通过`runOnUiThread`/`Handler`切换线程[^1][^3]。若遇空指针,检查View初始化和布局文件ID匹配[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mrsongs的心情杂货铺

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值