完善功能,修改注释

mengcheng_branch
mc19 2 months ago
parent a6feecbe39
commit 22720f6f47

@ -32,15 +32,10 @@ import android.util.Log;
import java.util.HashMap;
/**
*Contact
*
*<P></P>
*
*
* @author
* @version 1.0
* @since []
*/
* Contact
*
*
*/
public class Contact {
//HashMap表示联系人和电话号码之间的映射关系。只声明不new是延迟初始化的表现
private static HashMap<String, String> sContactCache;
@ -56,15 +51,13 @@ public class Contact {
/**
*
* <P></P>
*
* @param context 访ContentResolver
* @param phoneNumber 0
* @return code null
* @throws
* @see android.provider.ContactsContract.CommonDataKinds
* @return (code null)
*/
public static String getContact(Context context, String phoneNumber) {
//不到真正要用的时候,不给对象分配内存。第一次被调用时才new。
//不到真正要用的时候,不给对象分配内存第一次被调用时才new
if(sContactCache == null) {
sContactCache = new HashMap<String, String>();
}
@ -74,11 +67,11 @@ public class Contact {
return sContactCache.get(phoneNumber);
}
//构造匹配串,提取数字核心部分
//构造匹配串,提取电话号码数字核心部分
String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
//cursor是数据库游标初始位置是-1query把SQL拼装好后交给系统联系人Provider
//getcontentresolver.query()方法查询数据库,根据URI和电话号码匹配
Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME },
@ -86,16 +79,17 @@ public class Contact {
new String[] { phoneNumber },
null);
//指针移到第一行成功返回true
//利用cursor获取联系人姓名
if (cursor != null && cursor.moveToFirst()) {
try {
String name = cursor.getString(0);
sContactCache.put(phoneNumber, name); //将号码-姓名键值对放进内存缓存
return name;
} catch (IndexOutOfBoundsException e) { //捕获异常,索引超出列范围的情况,返回错误日志
} catch (IndexOutOfBoundsException e) {
//捕获索引越界异常
Log.e(TAG, " Cursor get string error " + e.toString());
return null;
} finally { //无论是否发生异常都必须释放cursor。
} finally {
cursor.close();
}
} else { //查询失败,输出日志信息

@ -25,14 +25,14 @@ package net.micode.notes.data;
import android.net.Uri;
/**
*Notes便
* <P>URI便/Intent</P>
* <b>static final</b>
* Notes便
* <p>URI便/Intent</p>
* static final,
*/
public class Notes {
public static final String AUTHORITY = "micode_notes"; //拼接URI的前缀
public static final String TAG = "Notes"; //日志显示Notes
public static final String TAG = "Notes"; //日志显示的标记
/**
* 便//
@ -55,7 +55,6 @@ public class Notes {
/**
* Intent
*
*/
public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; //提醒时间戳
public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; //便签背景颜色
@ -65,7 +64,7 @@ public class Notes {
public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; //通话记录时间戳
/**
*
*
*/
public static final int TYPE_WIDGET_INVALIDE = -1;
public static final int TYPE_WIDGET_2X = 0;
@ -94,7 +93,7 @@ public class Notes {
/**
* NoteColumns便
* 便便IDID,
* 便便IDID,
*/
public interface NoteColumns {
/**
@ -247,7 +246,7 @@ public class Notes {
/**
* 便
* 便
*/
public interface DataColumns {
/**
@ -345,27 +344,27 @@ public class Notes {
* Mode to indicate the text in check list mode or not
* <P> Type: Integer 1:check list mode 0: normal mode </P>
*/
public static final String MODE = DATA1; //清单模式or普通文本模式
public static final String MODE = DATA1; //存储文本的清单模式或普通文本模式
public static final int MODE_CHECK_LIST = 1;
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; //MIME类型为集合(多条)
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; //MIME类型为批量笔记
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; //MIME类型为单条
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; //MIME类型为单条笔记
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note");
}
/**
* CallNote便
* DataColumnsTextNote
* TextNoteCalloteDataColumns
*/
public static final class CallNote implements DataColumns {
/**
* Call date for this record
* <P> Type: INTEGER (long) </P>
*/
public static final String CALL_DATE = DATA1; //DATA1是数据库中的真实列名将通话的时间戳存入DATA1列中
public static final String CALL_DATE = DATA1; //DATA1存储通话的时间戳
/**
* Phone number for this record
@ -382,6 +381,7 @@ public class Notes {
/**
*
* 便
*/
public static final class ImageData implements DataColumns {
/**

@ -32,32 +32,29 @@ import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
/**
*便
<P>
*
*便
*<ul>
* <li>/ note data </li>
* <li>便便</li>
* <li></li>
* <li></li>
* <li>7</li>
* <li>note.db</li>
* <li>/notedata</li>
* <li>便</li>
* <li></li>
* <li></li>
*</ul>
</P>
*
* @author
* @version {@link #DB_VERSION} 4
* @since 2010-2011
* @version 1.0
* @since 2025-12-13
*/
public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
*
*
*/
private static final String DB_NAME = "note.db";
private static final int DB_VERSION = 7;
/**表明常量接口*/
public interface TABLE {
public static final String NOTE = "note";
@ -66,16 +63,17 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "NotesDatabaseHelper";
//类加载时不创建NotesDatabaseHelper实例(mInstance),真正需要使用数据库时才调用getInstance初始化节省应用启动时的内存和资源开销。
//类加载时不创建实例单例,真正需要使用时才调用getInstance初始化节省应用启动时的内存和资源开销。
private static NotesDatabaseHelper mInstance;
//二、建表SQL初始化note和data表同时添加note_id_index索引列
/**
* NotesNoteColumns
* NotesNoteColumns便IDPARENT_IDNotes
* NOT NULLNULLDEFAULT 0 0NOT NULLDEFAULT
* strftimeSQLite%sUnixnow'
* NoteData
* NoteColumns Notes便IDPARENT_ID
* <p>
* NOT NULLNULLDEFAULT 0 0,
* NOT NULLDEFAULT
* </p>
* strftime SQLite%sUnixnow'
*/
private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" + //开始建表表名是TABLE.NOTE(note)
@ -105,8 +103,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Data SQLNotesDataColumns
* <p>
* {@link DataColumns#NOTE_ID} note.id <br>
* data1~data5 {@link DataColumns#MIME_TYPE}
* {@link DataColumns#NOTE_ID} note.id <br>
* data1~data5 {@link DataColumns#MIME_TYPE}
* </p>
*/
private static final String CREATE_DATA_TABLE_SQL =
@ -127,20 +125,19 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
")";
/**
*data(NOTE_ID)note_id_index
* 便SELECT * FROM data WHERE note_id=?
* <p>data note_id</p>
* <p>便"SELECT * FROM data WHERE note_id=?"</p>
*/
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
"CREATE INDEX IF NOT EXISTS note_id_index ON " +
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
//三、创建Note表触发器在文件夹下便签数量变化时自动增减便签数量(notes_count)的值
/**
* Note便便
* Increase folder's note count when move note to the folder
* increase_folder_count_on_update
* noteparent_id
* Notenotes_count=notes_count+1,id=new.parent_id
* increase_folder_count_on_update
* note parent_id
* Note notes_count=notes_count+1, id=new.parent_id
* 便
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
@ -190,11 +187,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" AND " + NoteColumns.NOTES_COUNT + ">0;" +
" END";
//四、Data 表触发器自动同步便签摘要snippet)
/**
* Data 便snippet
* Update note's content when insert data with type {@link DataConstants#NOTE}
* DATAmime_typenote()
* notesnippetcontentnoteid=note_id
* mime_typenote
* note_id Notesnippet DataColumncontent
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
"CREATE TRIGGER update_note_content_on_insert " +
@ -234,8 +231,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Delete data belong to note which has been deleted
* notedatanote_idnoteid
* data-
* note noteid data note_id
* data
*/
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
"CREATE TRIGGER delete_data_on_delete " +
@ -247,7 +244,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Delete notes belong to folder which has been deleted
* notenoteparent_idid
* notenoteparent_idid
*
*/
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =
"CREATE TRIGGER folder_delete_notes_on_delete " +
@ -271,7 +269,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" END";
/**
* Android/
* Android/
* @param context 访
*/
public NotesDatabaseHelper(Context context) {
@ -279,13 +277,15 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** super(SQLiteOpenHelper)
* @param context context
* @param DB_NAME
* @param null (cursor),null
* @param DB_VERSION
* @param null (cursor),null( 1)
* @param DB_VERSION
*/
super(context, DB_NAME, null, DB_VERSION);
}
//完成note表的全量初始化
/**
* Note
*/
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL); //执行SQL语句创建note表
reCreateNoteTableTriggers(db); //重建该表关联的触发器
@ -293,7 +293,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
Log.d(TAG, "note table has been created"); //打印日志确认note表成功创建
}
//批量重建触发器,先删除旧的,再建立新的
/**
*
*/
private void reCreateNoteTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update");
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update");
@ -312,7 +314,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}
//向note表插入四个系统默认文件夹通话记录、根、临时、回收站。保证应用首次启动时有基础的文件夹结构。
/**
*
* note.
* @param db
*/
private void createSystemFolder(SQLiteDatabase db) {
//ContentValues类用于存储键值对
ContentValues values = new ContentValues();
@ -349,6 +355,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.insert(TABLE.NOTE, null, values);
}
/**
* Data
*/
public void createDataTable(SQLiteDatabase db) {
db.execSQL(CREATE_DATA_TABLE_SQL);
reCreateDataTableTriggers(db);
@ -367,10 +376,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
}
/**
* synchronized线线if
* getInstance
* synchronized线线
* getInstance
*/
static synchronized NotesDatabaseHelper getInstance(Context context) {
//首次调用该方法时,才创建实例;若已创建,则直接复用
if (mInstance == null) {
@ -379,13 +387,24 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
return mInstance;
}
//@override是Java中的一种注解用于明确表示子类的方法是对父类方法的重写实现多态性
/**
* onCreate
* "@override"
*/
@Override
public void onCreate(SQLiteDatabase db) {
createNoteTable(db); //初始化笔记表
createDataTable(db); //初始化数据表
createNoteTable(db); //初始化笔记表Note
createDataTable(db); //初始化数据表Data
}
/**
* onUpgrade
* <p>
*
* <li> rich_text_format</li>
* <li>, </li>
* </p>
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
boolean reCreateTriggers = false;
@ -408,25 +427,25 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
oldVersion++;
}
if (oldVersion == 4) {
upgradeToV5(db);
oldVersion++;
}
if (oldVersion == 4) {
upgradeToV5(db);
oldVersion++;
}
if (oldVersion == 5) {
upgradeToV6(db);
oldVersion++;
}
if (oldVersion == 5) {
upgradeToV6(db);
oldVersion++;
}
if (oldVersion == 6) {
upgradeToV7(db);
oldVersion++;
}
if (oldVersion == 6) {
upgradeToV7(db);
oldVersion++;
}
if (oldVersion == 7) {
upgradeToV8(db);
oldVersion++;
}
if (oldVersion == 7) {
upgradeToV8(db);
oldVersion++;
}
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
@ -439,7 +458,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
}
}
//v1到v2的升级删除旧的note data表清空所有用户数据重建新的
/**
* v1v2note data
*/
private void upgradeToV2(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); //执行具体的SQL语句删除旧的note表
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); //删除旧的data表
@ -447,7 +468,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
createDataTable(db);
}
//v2到v3的升级清除无用触发器新增gtask_id列新增回收站文件夹
/**
* v2v3Note gtask_id
*/
private void upgradeToV3(SQLiteDatabase db) {
// drop unused triggers
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
@ -463,37 +486,49 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.insert(TABLE.NOTE, null, values);
}
//v3到v4的升级为note表新增version列且约束非空默认为0
/**
*v3 v4 note version0
*/
private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
//v4到v5的升级为data表新增rich_text_format列用于存储富文本格式信息
/**
* v4v5 data rich_text_format
*/
private void upgradeToV5(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.DATA + " ADD COLUMN rich_text_format TEXT NOT NULL DEFAULT ''");
}
//v5到v6的升级为data表新增用于存储图片路径的列
/**
* v5v6 data
*/
private void upgradeToV6(SQLiteDatabase db) {
// 为data表添加一个专门存储图片路径的列
db.execSQL("ALTER TABLE " + TABLE.DATA + " ADD COLUMN image_path TEXT NOT NULL DEFAULT ''");
}
//v6到v7的升级为note表新增位置提醒相关的列
/**
* v6v7 note
*/
private void upgradeToV7(SQLiteDatabase db) {
// 为note表添加位置提醒相关的列
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LATITUDE + " REAL NOT NULL DEFAULT 0");
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LONGITUDE + " REAL NOT NULL DEFAULT 0");
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_RADIUS + " REAL NOT NULL DEFAULT 0");
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LOCATION_NAME + " TEXT NOT NULL DEFAULT ''");
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LATITUDE + " REAL NOT NULL DEFAULT 0"); //纬度
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LONGITUDE + " REAL NOT NULL DEFAULT 0"); //经度
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_RADIUS + " REAL NOT NULL DEFAULT 0"); //半径
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LOCATION_NAME + " TEXT NOT NULL DEFAULT ''"); //地点名称
}
//v7到v8的升级为note表新增隐私锁相关的列
/**
* v7v8 note
*/
private void upgradeToV8(SQLiteDatabase db) {
// 为note表添加隐私锁相关列
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.LOCKED + " INTEGER NOT NULL DEFAULT 0"); // 锁定状态0-未锁定1-已锁定
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.LOCK_TYPE + " INTEGER NOT NULL DEFAULT 0"); // 锁类型0-无锁1-密码锁2-手势锁
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ENCRYPTED_PASSWORD + " TEXT NOT NULL DEFAULT ''"); // 加密后的密码
// 锁定状态0-未锁定1-已锁定
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.LOCKED + " INTEGER NOT NULL DEFAULT 0");
// 锁类型0-无锁1-密码锁2-手势锁
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.LOCK_TYPE + " INTEGER NOT NULL DEFAULT 0");
// 加密后的密码
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ENCRYPTED_PASSWORD + " TEXT NOT NULL DEFAULT ''");
}
}
}

@ -3,7 +3,6 @@ package net.micode.notes.ui;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
@ -47,6 +46,8 @@ public class LoginRegisterActivity extends AppCompatActivity {
// 密码可见性状态
private boolean isPasswordVisible = false;
private static final int ROOT_AUTH_REQUEST_CODE = 1001;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -130,7 +131,8 @@ public class LoginRegisterActivity extends AppCompatActivity {
if (isLoginMode) {
performLogin();
} else {
performRegister();
// 注册前需要验证根用户权限
showRootAuthDialog();
}
}
});
@ -144,6 +146,15 @@ public class LoginRegisterActivity extends AppCompatActivity {
});
}
/**
*
*/
private void showRootAuthDialog() {
Intent intent = new Intent(this, SplashActivity.class);
intent.putExtra("SHOW_ROOT_AUTH_DIALOG", true);
startActivityForResult(intent, ROOT_AUTH_REQUEST_CODE);
}
/**
* UI
*/
@ -323,6 +334,24 @@ public class LoginRegisterActivity extends AppCompatActivity {
})
.show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ROOT_AUTH_REQUEST_CODE) {
if (resultCode == RESULT_OK && data != null) {
boolean authResult = data.getBooleanExtra("ROOT_AUTH_RESULT", false);
if (authResult) {
// 根用户验证成功,执行注册
performRegister();
} else {
Toast.makeText(this, "根用户验证失败,无法注册新用户", Toast.LENGTH_SHORT).show();
}
} else if (resultCode == RESULT_CANCELED) {
// 用户取消了验证
Toast.makeText(this, "已取消根用户验证", Toast.LENGTH_SHORT).show();
}
}
}
}

@ -3,24 +3,16 @@ package net.micode.notes.ui;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import net.micode.notes.R;
import net.micode.notes.tool.UserManager;
public class SplashActivity extends AppCompatActivity {
private static final int SPLASH_DURATION = 3000; // 3秒
private static final int TEXT_FADE_IN_DELAY = 2000; // 2秒后文字淡入
// 动画完成回调接口
public interface OnSplashCompleteListener {
void onSplashComplete();
}
// 启动页创建,初始化动画界面和跳转逻辑
@Override
@ -28,37 +20,29 @@ public class SplashActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
ImageView logo = findViewById(R.id.splash_logo);
TextView text = findViewById(R.id.splash_text);
// 加载文字滑动动画
Animation slideUpAnimation = AnimationUtils.loadAnimation(this, R.anim.text_slide_up);
// 2秒后显示文字动画
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
text.setVisibility(android.view.View.VISIBLE);
text.startAnimation(slideUpAnimation);
}
}, TEXT_FADE_IN_DELAY);
// 3秒后跳转到登录界面
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
onSplashComplete();
// 开始淡入动画
WaveAnimation.applyFadeInAnimation(text);
// 3秒后根据登录状态跳转
new Handler().postDelayed(() -> {
UserManager userManager = UserManager.getInstance(this);
boolean isLoggedIn = userManager.isLoggedIn();
if (isLoggedIn) {
// 已登录,直接进入主界面
Intent intent = new Intent(SplashActivity.this, NotesListActivity.class);
startActivity(intent);
} else {
// 未登录,跳转到注册登录界面
Intent intent = new Intent(SplashActivity.this, LoginRegisterActivity.class);
startActivity(intent);
}
finish();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}, SPLASH_DURATION);
}
// 动画完成回调方法
private void onSplashComplete() {
Intent intent = new Intent(SplashActivity.this, LoginRegisterActivity.class);
startActivity(intent);
finish(); // 结束启动页,防止用户返回到此页面
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
// 处理屏幕旋转等配置变更
@Override

@ -0,0 +1,76 @@
package net.micode.notes.ui;
import android.animation.ValueAnimator;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.TextView;
public class WaveAnimation {
// 整行文字从左到右淡入显示动画
public static void applyFadeInAnimation(TextView textView) {
// 设置初始状态为完全透明
textView.setAlpha(0f);
textView.setVisibility(android.view.View.VISIBLE);
// 创建透明度渐变动画
ValueAnimator fadeInAnimator = ValueAnimator.ofFloat(0f, 1f);
fadeInAnimator.setDuration(2000); // 2秒淡入效果
fadeInAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
fadeInAnimator.addUpdateListener(animation -> {
float alpha = (float) animation.getAnimatedValue();
textView.setAlpha(alpha);
});
// 创建从左到右的滑入效果
ValueAnimator slideInAnimator = ValueAnimator.ofFloat(-100f, 0f);
slideInAnimator.setDuration(1500); // 1.5秒滑入
slideInAnimator.setInterpolator(new android.view.animation.OvershootInterpolator());
slideInAnimator.addUpdateListener(animation -> {
float translationX = (float) animation.getAnimatedValue();
textView.setTranslationX(translationX);
});
// 同时启动两个动画
fadeInAnimator.start();
slideInAnimator.start();
}
// 从左到右逐字淡入效果(如果需要的话)
public static void applyCharByCharFadeIn(TextView textView) {
String text = textView.getText().toString();
int length = text.length();
// 设置初始状态
textView.setAlpha(0f);
textView.setVisibility(android.view.View.VISIBLE);
// 为整行文字创建统一的淡入动画
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(2500); // 总时长2.5秒
animator.setInterpolator(new android.view.animation.DecelerateInterpolator());
animator.addUpdateListener(animation -> {
float progress = (float) animation.getAnimatedValue();
textView.setAlpha(progress);
// 添加轻微的缩放效果
float scale = 0.8f + (progress * 0.2f); // 从0.8倍放大到1倍
textView.setScaleX(scale);
textView.setScaleY(scale);
});
animator.start();
}
// 兼容旧版本的方法名 - 使用新的淡入效果
public static void applyComplexWaveAnimation(TextView textView) {
applyFadeInAnimation(textView);
}
// 兼容旧版本的另一个方法名
public static void applyCharWaveAnimation(TextView textView) {
applyCharByCharFadeIn(textView);
}
}
Loading…
Cancel
Save