Android Kotlin日历应用开发:笔记照片存储与动态视图创建问题
解决方案拆解
一、纯代码创建笔记展示View
直接继承LinearLayout(或其他ViewGroup),在代码中动态构建布局和控件,无需依赖XML:
class NoteDisplayView(context: Context) : LinearLayout(context) { private val noteContent: TextView private val noteImage: ImageView init { // 基础布局配置 orientation = VERTICAL setPadding(16.dpToPx(), 16.dpToPx(), 16.dpToPx(), 16.dpToPx()) background = ContextCompat.getDrawable(context, R.drawable.note_bg) // 创建笔记文本控件 noteContent = TextView(context).apply { layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT).apply { bottomMargin = 8.dpToPx() } textSize = 16f setTextColor(Color.BLACK) } // 创建图片展示控件(默认隐藏) noteImage = ImageView(context).apply { layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, 200.dpToPx()) scaleType = ImageView.ScaleType.CENTER_CROP visibility = View.GONE } // 将控件添加到当前View addView(noteContent) addView(noteImage) } // 对外暴露设置笔记内容的方法 fun setNoteContent(content: String) { noteContent.text = content } // 对外暴露设置图片的方法 fun setNoteImage(bitmap: Bitmap) { noteImage.setImageBitmap(bitmap) noteImage.visibility = View.VISIBLE } // 扩展函数:dp转px private fun Int.dpToPx(): Int { return (this * context.resources.displayMetrics.density).toInt() } }
使用示例:在Activity/Fragment中点击日历日期后,实例化该View并添加到布局(或弹窗):
// 点击日历日期后调用 val noteView = NoteDisplayView(this) noteView.setNoteContent("今天的笔记内容") // 如果有图片,设置图片 val bitmap = BitmapFactory.decodeFile("/storage/emulated/0/.../photo.jpg") noteView.setNoteImage(bitmap) // 将noteView添加到指定布局 rootLayout.addView(noteView)
二、笔记、照片、事件的存储方案
1. 结构化存储(推荐Room数据库)
适合多日期多内容的场景,结构化存储所有数据:
步骤1:添加Room依赖(Module级build.gradle)
dependencies { implementation "androidx.room:room-runtime:2.6.1" kapt "androidx.room:room-compiler:2.6.1" implementation "androidx.room:room-ktx:2.6.1" }
步骤2:创建实体类(对应数据库表)
@Entity(tableName = "calendar_notes") data class CalendarNote( @PrimaryKey(autoGenerate = true) val id: Int = 0, val date: Long, // 用时间戳存储选中的日历日期 val noteContent: String, // 笔记文本 val imagePath: String?, // 图片本地存储路径(不存Bitmap) val eventTitle: String?, // 事件标题 val eventTime: Long? // 事件时间戳 )
步骤3:创建Dao接口(数据库操作方法)
@Dao interface CalendarNoteDao { @Insert suspend fun insertNote(note: CalendarNote) @Update suspend fun updateNote(note: CalendarNote) @Query("SELECT * FROM calendar_notes WHERE date = :targetDate") suspend fun getNoteByDate(targetDate: Long): CalendarNote? @Delete suspend fun deleteNote(note: CalendarNote) }
步骤4:创建数据库单例类
@Database(entities = [CalendarNote::class], version = 1) abstract class CalendarDatabase : RoomDatabase() { abstract fun calendarNoteDao(): CalendarNoteDao companion object { @Volatile private var INSTANCE: CalendarDatabase? = null fun getDatabase(context: Context): CalendarDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( context.applicationContext, CalendarDatabase::class.java, "calendar_database" ).build() INSTANCE = instance instance } } } }
步骤5:数据库操作示例(协程中执行)
// 查询指定日期的笔记 lifecycleScope.launch { val selectedDate = calendarView.date // 获取CalendarView选中的日期时间戳 val existingNote = CalendarDatabase.getDatabase(this@MainActivity) .calendarNoteDao() .getNoteByDate(selectedDate) if (existingNote != null) { // 展示已有笔记 val noteView = NoteDisplayView(this@MainActivity) noteView.setNoteContent(existingNote.noteContent) existingNote.imagePath?.let { path -> val bitmap = BitmapFactory.decodeFile(path) noteView.setNoteImage(bitmap) } rootLayout.addView(noteView) } else { // 插入新笔记 val newNote = CalendarNote( date = selectedDate, noteContent = "用户输入的笔记内容", imagePath = "/data/data/com.yourapp/files/note_image.jpg", // 图片存储路径 eventTitle = "同学聚会", eventTime = System.currentTimeMillis() ) CalendarDatabase.getDatabase(this@MainActivity) .calendarNoteDao() .insertNote(newNote) } }
2. 照片存储处理
从相册选图后,不要直接存储Bitmap,而是将图片保存到应用私有目录,再把路径存入数据库:
// 处理相册返回的Uri,保存图片并返回路径 fun saveImageFromUri(uri: Uri, context: Context): String? { return try { val inputStream = context.contentResolver.openInputStream(uri) val bitmap = BitmapFactory.decodeStream(inputStream) // 保存到应用私有目录 val file = File(context.filesDir, "note_img_${System.currentTimeMillis()}.jpg") val outputStream = FileOutputStream(file) bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream) inputStream?.close() outputStream.close() file.absolutePath } catch (e: IOException) { e.printStackTrace() null } }
三、CalendarView交互逻辑
设置日期点击监听器,触发笔记的创建/展示流程:
calendarView.setOnDateChangeListener { _, year, month, dayOfMonth -> // 将年月日转为时间戳(与CalendarView的date格式一致) val calendar = Calendar.getInstance().apply { set(year, month, dayOfMonth) set(Calendar.HOUR_OF_DAY, 0) set(Calendar.MINUTE, 0) set(Calendar.SECOND, 0) set(Calendar.MILLISECOND, 0) } val selectedDate = calendar.timeInMillis // 这里可以弹出输入Dialog让用户填写笔记,再执行数据库操作 showNoteInputDialog(selectedDate) }
内容的提问来源于stack exchange,提问作者Nandan Praveen
相关产品推荐
相关产品推荐

