效果图
以下是源代码
build.gradle文件
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.example.word3"
minSdk 27
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'androidx.room:room-runtime:2.1.0'
kapt "androidx.room:room-compiler:2.1.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.navigation:navigation-fragment-ktx:2.5.2"
implementation "androidx.navigation:navigation-ui-ktx:2.5.2"
implementation 'androidx.recyclerview:recyclerview:1.2.1'
}
layout
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
cell_card.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="60dp"
android:clickable="true"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
android:background="?selectableItemBackground">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintGuide_percent="0.8"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintGuide_percent="0.15"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textViewNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintHorizontal_bias="0.38"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.412" />
<TextView
android:id="@+id/textViewEnglish"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="200dp"
android:paddingTop="20dp"
android:text="TextView"
android:textSize="24dp"
app:layout_constraintBottom_toTopOf="@+id/textViewChinese"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/guideline4"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.333"
app:layout_goneMarginStart="16dp" />
<TextView
android:id="@+id/textViewChinese"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:layout_marginEnd="204dp"
android:paddingLeft="0dp"
android:paddingTop="40dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.072"
app:layout_constraintStart_toStartOf="@id/textViewEnglish"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.878" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout2"
android:layout_width="83dp"
android:layout_height="80dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0">
<Switch
android:id="@+id/aSwitchChineseInvisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="30dp"
android:paddingEnd="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.444"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.484"
tools:ignore="TouchTargetSizeCheck,UseSwitchCompatOrMaterialXml" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
cell_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#F9F9F9"
android:clickable="true">
<View
android:id="@+id/divider"
android:layout_width="2dp"
android:layout_height="match_parent"
android:background="?android:attr/listDivider"
android:paddingTop="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/constraintLayout"
app:layout_constraintStart_toEndOf="@+id/constraintLayout"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@android:drawable/list_selector_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.15" />
<TextView
android:id="@+id/textViewNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintHorizontal_bias="0.38"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.412" />
<TextView
android:id="@+id/textViewEnglish"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="200dp"
android:text="TextView"
android:textSize="24dp"
app:layout_constraintBottom_toTopOf="@+id/textViewChinese"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/guideline4"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.333"
app:layout_goneMarginStart="16dp" />
<TextView
android:id="@+id/textViewChinese"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="204dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.072"
app:layout_constraintStart_toStartOf="@id/textViewEnglish"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.878" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout2"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="parent">
<Switch
android:id="@+id/aSwitchChineseInvisible"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:paddingStart="20dp"
android:paddingEnd="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.444"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.484"
tools:ignore="TouchTargetSizeCheck,UseSwitchCompatOrMaterialXml" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.8" />
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_add.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/addLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".AddFragment">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="添加单词"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.485"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.135" />
<EditText
android:id="@+id/editTextEnglish"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ems="10"
android:hint="English_Word"
android:inputType="textPersonName"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.276" />
<EditText
android:id="@+id/editTextChinese"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ems="10"
android:hint="中文"
android:inputType="textPersonName"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.406" />
<Button
android:id="@+id/buttonSubmit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_words.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/wordsFragmentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WordsFragment">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="16dp"
android:clickable="true"
android:elevation="8dp"
android:src="@drawable/ic_baseline_add_24"
tools:ignore="SpeakableTextPresentCheck" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
menu:
main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/clearData"
android:title="清空数据" />
<item
android:id="@+id/switchViewType"
android:title="切换视图" />
<item
android:id="@+id/app_bar_search"
android:icon="@android:drawable/ic_menu_search"
android:title="Search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always" />
</menu>
navigation:
navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation"
app:startDestination="@id/wordsFragment">
<fragment
android:id="@+id/addFragment"
android:name="com.example.word3.AddFragment"
android:label="Add"
tools:layout="@layout/fragment_add" />
<fragment
android:id="@+id/wordsFragment"
android:name="com.example.word3.WordsFragment"
android:label="Words"
tools:layout="@layout/fragment_words">
<action
android:id="@+id/action_wordsFragment_to_addFragment"
app:destination="@id/addFragment"
app:enterAnim="@anim/nav_default_enter_anim" />
</fragment>
</navigation>
values
ids.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="word_for_view_holder" type="id"/>
</resources>
AddFragment
import android.content.Context
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.EditText
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.Navigation
class AddFragment : Fragment() {
private lateinit var buttonSubmit: Button
private lateinit var editTextEnglish: EditText
private lateinit var editTextChinese: EditText
private lateinit var wordViewModel: WordViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
var view: View = inflater.inflate(R.layout.fragment_add, container, false)
buttonSubmit = view.findViewById(R.id.buttonSubmit)
editTextChinese = view.findViewById(R.id.editTextChinese)
editTextEnglish = view.findViewById(R.id.editTextEnglish)
return view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
buttonSubmit.isEnabled = false
editTextEnglish.requestFocus()
wordViewModel= ViewModelProvider(requireActivity()).get(WordViewModel::class.java)
val imm: InputMethodManager =
requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(editTextEnglish, 0)
editTextChinese.addTextChangedListener(mydetextWatcher())
editTextEnglish.addTextChangedListener(mydetextWatcher())
buttonSubmit.setOnClickListener {
val english:String=editTextEnglish.text.toString().trim()
val chinese:String=editTextChinese.text.toString().trim()
val word:Word= Word(english,chinese,false)
wordViewModel.insertWords(word)
val navController: NavController = Navigation.findNavController(it)
navController.navigateUp()
val imm:InputMethodManager= requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(it.windowToken,0)
}
}
inner class mydetextWatcher : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
val english: String = editTextEnglish.text.toString().trim()
val chinese: String = editTextChinese.text.toString().trim()
buttonSubmit.isEnabled = english.isNotEmpty() && chinese.isNotEmpty()
}
override fun afterTextChanged(p0: Editable?) {
}
}
}
MainActivity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.NavigationUI
class MainActivity : AppCompatActivity() {
private lateinit var navController:NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
navController=supportFragmentManager.findFragmentById(R.id.fragment)?.findNavController() as NavController
NavigationUI.setupActionBarWithNavController(this,navController)
}
override fun onSupportNavigateUp(): Boolean {
navController.navigateUp()
return super.onSupportNavigateUp()||findNavController(R.id.fragment).navigateUp()
}
}
MyAdapter
import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Switch
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
class MyAdapter(var useCardView:Boolean,var wordViewModel: WordViewModel) :androidx.recyclerview.widget.ListAdapter<Word,MyAdapter.ViewHolder>(diffCallback) {
companion object{
val diffCallback=object :DiffUtil.ItemCallback<Word>(){
override fun areItemsTheSame(oldItem: Word, newItem: Word): Boolean {
return oldItem.id==newItem.id
}
override fun areContentsTheSame(oldItem: Word, newItem: Word): Boolean {
return (oldItem.word == newItem.word &&
oldItem.chineseMeaning == newItem.chineseMeaning &&
oldItem.isChineseInvisible == newItem.isChineseInvisible)
}
}
}
override fun onViewAttachedToWindow(holder: ViewHolder) {
super.onViewAttachedToWindow(holder)
holder.textViewNumber.text=(holder.absoluteAdapterPosition +1).toString()
}
inner class ViewHolder(view:View):RecyclerView.ViewHolder(view){
val aSwitchChineseInvisible:Switch=view.findViewById(R.id.aSwitchChineseInvisible)
var textViewNumber:TextView=view.findViewById(R.id.textViewNumber)
var textViewEnglish:TextView=view.findViewById(R.id.textViewEnglish)
var textViewChinese:TextView=view.findViewById(R.id.textViewChinese)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
var layoutInflater:LayoutInflater=LayoutInflater.from(parent.context)
var itemView:View = if(useCardView){
layoutInflater.inflate(R.layout.cell_card,parent,false)
}else{
layoutInflater.inflate(R.layout.cell_normal,parent,false)
}
val holder: ViewHolder =ViewHolder(itemView)
holder.itemView.setOnClickListener {
var uri:Uri= Uri.parse("https://m.youdao.com/dict?le=eng&q="+holder.textViewEnglish.text)
var intent:Intent= Intent(Intent.ACTION_VIEW)
intent.setData(uri)
holder.itemView.context.startActivities(arrayOf(intent))
}
holder.aSwitchChineseInvisible.setOnCheckedChangeListener { compoundButton, b ->
var word:Word=holder.itemView.getTag(R.id.word_for_view_holder) as Word
if (b){
word.isChineseInvisible=true
holder.textViewChinese.visibility=View.GONE
wordViewModel.updateWords(word)
}else{
word.isChineseInvisible=false
holder.textViewChinese.visibility=View.VISIBLE
wordViewModel.updateWords(word)
}
}
return holder
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
var word:Word=getItem(position)
holder.itemView.setTag(R.id.word_for_view_holder,word)
holder.textViewNumber.text= (position+1).toString()
holder.textViewEnglish.text=word.word
holder.textViewChinese.text=word.chineseMeaning
if (word.isChineseInvisible){
holder.textViewChinese.visibility=View.GONE
holder.aSwitchChineseInvisible.isChecked=true
}else{
holder.textViewChinese.visibility=View.VISIBLE
holder.aSwitchChineseInvisible.isChecked=false
}
}
}
MyApplication
import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
class MyApplication:Application() {
companion object{
@SuppressLint("StaticFieldLeak")
lateinit var context: Context
}
override fun onCreate() {
super.onCreate()
context=applicationContext
}
}
Word
@Entity
data class Word (var word: String,var chineseMeaning:String,var isChineseInvisible:Boolean){
@PrimaryKey(autoGenerate = true)
var id:Int=0
}
WordDao
import androidx.lifecycle.LiveData
import androidx.room.*
@Dao
interface WordDao {
@Insert
fun insertWords( vararg word: Word)
@Update
fun updateWords(vararg word: Word)
@Delete
fun deleteWords(vararg word: Word)
@Query("DELETE FROM WORD")
fun deleteAllWords()
@Query("SELECT * FROM WORD ORDER BY ID DESC")
fun getAllWordsLive():LiveData<List<Word>>
@Query("SELECT * FROM WORD WHERE word LIKE:patten ORDER BY ID DESC")
fun findWordsWithPatten(patten:String):LiveData<List<Word>>
}
WordDatabase
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database( version = 3, entities = [Word::class],exportSchema = false)
abstract class WordDatabase: RoomDatabase() {
companion object {
private var instance: WordDatabase? = null
@Synchronized
fun getWordDatabase(context: Context): WordDatabase {
instance?.let {
return it
}
return Room.databaseBuilder(
context.applicationContext,
WordDatabase::class.java, "word_database"
).allowMainThreadQueries().fallbackToDestructiveMigration()
.build()
.apply {
instance = this
}
}
}
abstract fun getWordDao():WordDao
}
WordRepository
import android.os.AsyncTask
import androidx.lifecycle.LiveData
class WordRepository {
lateinit var wordDao: WordDao
lateinit var allWordsLive: LiveData<List<Word>>
init {
val wordDatabase:WordDatabase=WordDatabase.getWordDatabase(MyApplication.context)
wordDao=wordDatabase.getWordDao()
allWordsLive=wordDao.getAllWordsLive()
}
fun findWordsWithPatten(patten:String): LiveData<List<Word>>{
return wordDao.findWordsWithPatten("%"+patten+"%")
}
fun insertWords(vararg p0: Word?){
InsertAsyncTask(wordDao).execute(*p0)
}
fun updateWords(vararg p0: Word?){
UpdateAsyncTask(wordDao).execute(*p0)
}
fun deleteWords(vararg p0: Word?){
DeleteAsyncTask(wordDao).execute(*p0)
}
fun deleteAllWords(vararg p0: Word?){
DeleteAllAsyncTask(wordDao).execute()
}
companion object {
class InsertAsyncTask internal constructor(var wordDao: WordDao) :
AsyncTask<Word, Void, Void?>() {
override fun doInBackground(vararg p0: Word?): Void? {
wordDao.insertWords(*p0 as Array<out Word>)
return null
}
}
class UpdateAsyncTask internal constructor(var wordDao: WordDao) :
AsyncTask<Word, Void, Void?>() {
override fun doInBackground(vararg p0: Word?): Void? {
wordDao.updateWords(*p0 as Array<out Word>)
return null
}
}
class DeleteAsyncTask internal constructor(var wordDao: WordDao) :
AsyncTask<Word, Void, Void?>() {
override fun doInBackground(vararg p0: Word?): Void? {
wordDao.deleteWords(*p0 as Array<out Word>)
return null
}
}
class DeleteAllAsyncTask internal constructor(var wordDao: WordDao) :
AsyncTask<Void, Void, Void?>() {
override fun doInBackground(vararg p0: Void?): Void? {
wordDao.deleteAllWords()
return null
}
}
}
}
WordsFragment
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.view.*
import androidx.fragment.app.Fragment
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.SearchView
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.Navigation
import androidx.recyclerview.widget.*
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
class WordsFragment : Fragment() {
private lateinit var wordViewModel: WordViewModel
private lateinit var recyclerView: RecyclerView
private lateinit var myAdapter1: MyAdapter
private lateinit var myAdapter2: MyAdapter
private lateinit var floatingActionButton: FloatingActionButton
private lateinit var filteredWords: LiveData<List<Word>>
val VIEW_TYPE_SHP:String="view_type_shp"
val IS_USING_CARD_VIEW:String="is_using_card_view"
private lateinit var allWords:List<Word>
lateinit var dividerItemDecoration: DividerItemDecoration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
wordViewModel = ViewModelProvider(this).get(WordViewModel::class.java)
myAdapter1 = MyAdapter(false, wordViewModel)
myAdapter2 = MyAdapter(true, wordViewModel)
}
inner class defaultItemAnimator:DefaultItemAnimator(){
override fun onAnimationFinished(viewHolder: RecyclerView.ViewHolder) {
super.onAnimationFinished(viewHolder)
var linearLayoutManager:LinearLayoutManager=recyclerView.layoutManager as LinearLayoutManager
if (linearLayoutManager!=null){
var firstPosition:Int=linearLayoutManager.findFirstVisibleItemPosition()
var lastPosition:Int=linearLayoutManager.findLastVisibleItemPosition()
for (i in firstPosition until lastPosition+1){
var holder: MyAdapter.ViewHolder=recyclerView.findViewHolderForAdapterPosition(i) as MyAdapter.ViewHolder
if (holder!=null){
holder.textViewNumber.text= (i+1).toString()
}
}
}
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
recyclerView.itemAnimator=defaultItemAnimator()
var shp=requireActivity().getSharedPreferences(VIEW_TYPE_SHP,Context.MODE_PRIVATE)
var viewType:Boolean=shp.getBoolean(IS_USING_CARD_VIEW,false)
dividerItemDecoration= DividerItemDecoration(requireActivity(),DividerItemDecoration.VERTICAL)
if (viewType){
recyclerView.adapter=myAdapter2
}else{
recyclerView.adapter=myAdapter1
recyclerView.addItemDecoration(dividerItemDecoration)
}
filteredWords=wordViewModel.allWordsLive
filteredWords.observe(requireActivity(), Observer { count ->
var temp:Int=myAdapter1.itemCount
allWords=count
if (temp!=count.size){
if (temp<count.size)
recyclerView.smoothScrollBy(0,-200)
myAdapter1.submitList(count)
myAdapter2.submitList(count)
}
})
ItemTouchHelper(object :ItemTouchHelper.Callback(){
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
return makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN,ItemTouchHelper.START or ItemTouchHelper.END)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
Toast.makeText(requireActivity(),"慢一点",Toast.LENGTH_SHORT).show()
var wordFrom:Word=allWords.get(viewHolder.adapterPosition)
var wordTo:Word=allWords.get(target.adapterPosition)
var idTemp:Int=wordFrom.id
wordFrom.id=wordTo.id
wordTo.id=idTemp
wordViewModel.updateWords(wordFrom,wordTo)
myAdapter1.notifyItemMoved(viewHolder.adapterPosition,target.adapterPosition)
myAdapter2.notifyItemMoved(viewHolder.adapterPosition,target.adapterPosition)
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
var wordToDelete:Word=allWords.get(viewHolder.adapterPosition)
wordViewModel.deleteWords(wordToDelete)
Snackbar.make(requireActivity().findViewById(R.id.wordsFragmentView),"删除了一个词汇",Snackbar.LENGTH_SHORT)
.setAction("撤销",View.OnClickListener {
wordViewModel.insertWords(wordToDelete)
})
.show()
}
}).attachToRecyclerView(recyclerView)
floatingActionButton.setOnClickListener {
var navController: NavController = Navigation.findNavController(it)
navController.navigate(R.id.action_wordsFragment_to_addFragment)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
var view:View=inflater.inflate(R.layout.fragment_words, container, false)
recyclerView = view.findViewById(R.id.recyclerView)
floatingActionButton=view.findViewById(R.id.floatingActionButton)
recyclerView.layoutManager = LinearLayoutManager(activity)
recyclerView.adapter = myAdapter1
setHasOptionsMenu(true)
return view
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu,inflater)
inflater?.inflate(R.menu.main_menu,menu)
var searchView:SearchView= menu.findItem(R.id.app_bar_search).actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
var patten: String = newText.trim()
filteredWords.removeObservers(requireActivity())
filteredWords = wordViewModel.findWordsWithPatten(patten)
filteredWords.observe(requireActivity(), Observer { count ->
var temp = myAdapter1.itemCount
allWords=count
if (temp != count.size) {
myAdapter1.submitList(count)
myAdapter2.submitList(count)
}
})
return false
}
})
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when(item.itemId){
R.id.clearData->AlertDialog.Builder(requireActivity()).apply {
setTitle("清空数据")
setPositiveButton("确定"){dialog,which->wordViewModel.deleteAllWords()}
setNegativeButton("取消"){dialog,which->}
show()
}
R.id.switchViewType->{ var shp=requireActivity().getSharedPreferences(VIEW_TYPE_SHP,Context.MODE_PRIVATE)
var viewType:Boolean=shp.getBoolean(IS_USING_CARD_VIEW,false)
var editor:SharedPreferences.Editor=shp.edit()
if (viewType){
recyclerView.adapter=myAdapter1
recyclerView.addItemDecoration(dividerItemDecoration)
editor.putBoolean(IS_USING_CARD_VIEW,false)
}else{
recyclerView.adapter=myAdapter2
recyclerView.removeItemDecoration(dividerItemDecoration)
editor.putBoolean(IS_USING_CARD_VIEW,true)
}
editor.apply()
}
}
return super.onOptionsItemSelected(item)
}
}
WordViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
class WordViewModel: ViewModel() {
lateinit var wordRepository: WordRepository
lateinit var allWordsLive: LiveData<List<Word>>
init {
wordRepository= WordRepository()
allWordsLive=wordRepository.allWordsLive
}
fun findWordsWithPatten(patten:String): LiveData<List<Word>>{
return wordRepository.findWordsWithPatten("%"+patten+"%")
}
fun insertWords(vararg p0: Word?){
wordRepository.insertWords(*p0)
}
fun updateWords(vararg p0: Word?){
wordRepository.updateWords(*p0)
}
fun deleteWords(vararg p0: Word?){
wordRepository.deleteWords(*p0)
}
fun deleteAllWords(vararg p0: Word?){
wordRepository.deleteAllWords()
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/95972.html