Android实战演练(kotlin版),词汇记录APP

效果图

Android实战演练(kotlin版),词汇记录APP_第1张图片Android实战演练(kotlin版),词汇记录APP_第2张图片

Android实战演练(kotlin版),词汇记录APP_第3张图片 

以下是源代码

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




    

cell_card.xml 



    

        
            

            

            

            

            

            
                
            
        

    

cell_normal.xml  




    

    


        

        

        

        
    

    

        
    

    

fragment_add.xml





    

    

    

    

fragment_words.xml 





    

    

menu:

main_menu.xml 




    
    
    

navigation:

navigation.xml



    
    
        
    

values

ids.xml



    


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(diffCallback) {
    companion object{
        val diffCallback=object :DiffUtil.ItemCallback(){
            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>
    @Query("SELECT * FROM WORD WHERE word LIKE:patten ORDER BY ID DESC")
    fun findWordsWithPatten(patten:String):LiveData>
}

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>
    init {
        val wordDatabase:WordDatabase=WordDatabase.getWordDatabase(MyApplication.context)
        wordDao=wordDatabase.getWordDao()
        allWordsLive=wordDao.getAllWordsLive()
    }
    fun findWordsWithPatten(patten:String): LiveData>{
        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() {
            override fun doInBackground(vararg p0: Word?): Void? {
                wordDao.insertWords(*p0 as Array)
                return null
            }
        }

        class UpdateAsyncTask internal constructor(var wordDao: WordDao) :
            AsyncTask() {
            override fun doInBackground(vararg p0: Word?): Void? {
                wordDao.updateWords(*p0 as Array)
                return null
            }
        }
        class DeleteAsyncTask internal constructor(var wordDao: WordDao) :
            AsyncTask() {
            override fun doInBackground(vararg p0: Word?): Void? {
                wordDao.deleteWords(*p0 as Array)
                return null
            }
        }
        class DeleteAllAsyncTask internal constructor(var wordDao: WordDao) :
            AsyncTask() {

            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>
    val VIEW_TYPE_SHP:String="view_type_shp"
    val IS_USING_CARD_VIEW:String="is_using_card_view"
    private lateinit var allWords:List
    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
                        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>
    init {
        wordRepository= WordRepository()
        allWordsLive=wordRepository.allWordsLive
    }
    fun findWordsWithPatten(patten:String): LiveData>{
        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()
    }
}

你可能感兴趣的:(Android,android,kotlin,java)