添加笔记创建和编辑功能
我们将逐步实现笔记的创建和编辑功能。以下是详细的实现步骤:
1. 数据模型
首先,定义一个 Note 数据类来表示笔记。
Note.kt
package com.nemo.notes.model
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.util.Date
@Entity(tableName = "notes")
data class Note(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val title: String,
val content: String,
val createdAt: Date = Date(),
val updatedAt: Date = Date()
)
2. 数据库访问对象 (DAO)
定义一个 NoteDao 接口来操作数据库。
NoteDao.kt
package com.nemo.notes.database
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.nemo.notes.model.Note
import kotlinx.coroutines.flow.Flow
@Dao
interface NoteDao {
@Query("SELECT * FROM notes ORDER BY updatedAt DESC")
fun getAllNotes(): Flow<List<Note>>
@Insert
suspend fun insert(note: Note): Long
@Update
suspend fun update(note: Note): Int
@Query("DELETE FROM notes WHERE id = :noteId")
suspend fun delete(noteId: Long): Int
@Delete
suspend fun delete(note: Note): Int
}
3. 数据库
创建一个 NoteDatabase 类来管理数据库。
NoteDatabase.kt
package com.nemo.notes.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.example.notes.model.Note
@Database(entities = [Note::class], version = 1, exportSchema = false)
abstract class NoteDatabase : RoomDatabase() {
abstract fun noteDao(): NoteDao
companion object {
@Volatile
private var INSTANCE: NoteDatabase? = null
fun getDatabase(context: Context): NoteDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
NoteDatabase::class.java,
"note_database"
).build()
INSTANCE = instance
instance
}
}
}
}
4. 仓库
创建一个 NoteRepository 类来管理数据操作。
NoteRepository.kt
package com.nemo.notes.repository
import com.example.notes.database.NoteDao
import com.example.notes.model.Note
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class NoteRepository @Inject constructor(
private val noteDao: NoteDao
) {
fun getAllNotes(): Flow<List<Note>> = noteDao.getAllNotes()
suspend fun insert(note: Note) = noteDao.insert(note)
suspend fun update(note: Note) = noteDao.update(note)
suspend fun delete(noteId: Long) = noteDao.delete(noteId)
}
5. ViewModel
创建一个 NoteViewModel 类来管理 UI 数据。
NoteViewModel.kt
package com.nemo.notes.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.nemo.notes.model.Note
import com.nemo.notes.repository.NoteRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class NoteViewModel @Inject constructor(
private val repository: NoteRepository
) : ViewModel() {
val allNotes: Flow<List<Note>> = repository.getAllNotes()
fun insert(note: Note) = viewModelScope.launch {
repository.insert(note)
}
fun update(note: Note) = viewModelScope.launch {
repository.update(note)
}
fun addNote(note: Note) {
viewModelScope.launch {
repository.insert(note)
}
}
fun delete(noteId: Long) = viewModelScope.launch {
repository.delete(noteId)
}
}
6. UI 界面
6.1 笔记列表界面
NoteListScreen.kt
package com.nemo.notes.ui
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.example.notes.model.Note
import com.example.notes.viewmodel.NoteViewModel
@Composable
fun NoteListScreen(navController: NavController, viewModel: NoteViewModel) {
val notes by viewModel.getAllNotes().collectAsState(initial = emptyList())
Column(modifier = Modifier.padding(16.dp)) {
Text(text = "My Notes", style = MaterialTheme.typography.headlineMedium)
LazyColumn {
items(notes) { note ->
Card(
onClick = { navController.navigate("noteEdit/${note.id}") },
modifier = Modifier.padding(8.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(text = note.title, style = MaterialTheme.typography.titleMedium)
Text(text = note.content, style = MaterialTheme.typography.bodyMedium)
}
}
}
}
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = { navController.navigate("noteEdit/${note.id}") },
modifier = Modifier.fillMaxWidth()
) {
Text("Add New Note")
}
}
}
6.2 笔记编辑界面
NoteEditScreen.kt
package com.nemo.notes.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.nemo.notes.model.Note
import com.nemo.notes.viewmodel.NoteViewModel
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NoteEditScreen(
navController: NavController,
viewModel: NoteViewModel,
noteId: Long?
) {
val note = remember { mutableStateOf(Note(title = "", content = "")) }
if (noteId != null) {
LaunchedEffect(noteId) {
viewModel.allNotes.collect { notes ->
notes.find { it.id == noteId }?.let { note.value = it }
} } }
Column(modifier = Modifier.padding(16.dp)) {
TextField(
value = note.value.title,
onValueChange = { note.value = note.value.copy(title = it) },
label = { Text("Title") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = note.value.content,
onValueChange = { note.value = note.value.copy(content = it) },
label = { Text("Content") },
modifier = Modifier.fillMaxWidth().height(200.dp)
)
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = {
if (noteId == null) {
viewModel.insert(note.value)
} else {
viewModel.update(note.value.copy(id = noteId))
}
navController.popBackStack()
},
modifier = Modifier.fillMaxWidth()
) {
Text(if (noteId == null) "Create Note" else "Update Note")
}
}}
7. 导航
更新导航以支持笔记列表和编辑界面之间的切换。
MainActivity.kt
package com.nemo.notes.ui
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.nemo.notes.ui.theme.NotesAppTheme
import com.nemo.notes.viewmodel.NoteViewModel
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
NotesAppTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
val navController = rememberNavController()
val viewModel: NoteViewModel = hiltViewModel()
NavHost(navController = navController, startDestination = "noteList") {
composable("noteList") {
NoteListScreen(navController, viewModel)
}
composable("noteEdit/{noteId}") { backStackEntry ->
val noteId = backStackEntry.arguments?.getString("noteId")?.toLongOrNull()
NoteEditScreen(navController, viewModel, noteId)
}
}
}
}
}
}
}
8. 运行项目
- 确保 Android 项目配置正确。
- 运行项目并测试笔记的创建和编辑功能。
项目代码参考地址:github.com/wxxzy/Notes…
通过以上步骤,您已经成功实现了笔记的创建和编辑功能。接下来,您可以继续实现搜索、标签管 理、云同步等功能。如果有任何问题或需要进一步的帮助,请随时告诉我!