apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
SunFlower学习之UI组件
implementation "com.google.android.material:material:1.1.0"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation "androidx.recyclerview:recyclerview:1.1.0"
常用组件
DrawerLayout
NavigationView
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
CoordinatorLayout
AppBarLayout
CollapsingToolbarLayout
Toolbar
FloatingActionButton
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="280dp"
android:fitsSystemWindows="true"
android:animateLayoutChanges="true"
android:stateListAnimator="@animator/show_toolbar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/toolbarLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:collapsedTitleTextAppearance="@style/TextAppearance.Sunflower.Toolbar.Text"
app:expandedTitleTextAppearance="@style/TextAppearance.Sunflower.Toolbar.Text2"
app:statusBarScrim="@color/colorPrimary"
android:fitsSystemWindows="true"
android:animateLayoutChanges="true"
app:contentScrim="@color/colorPrimary"
app:expandedTitleGravity="left|bottom"
app:collapsedTitleGravity="left"
app:titleEnabled="true"
app:toolbarId="@id/toolbar">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="280dp"
android:scaleType="fitXY"
app:layout_collapseMode="parallax"
android:fitsSystemWindows="true"
android:src="@drawable/ic_launcher_background" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/transparent"
app:contentInsetStartWithNavigation="0dp"
android:theme="@style/ToolbarTheme"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<include layout="@layout/content_main" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|end"
app:srcCompat="@android:drawable/ic_dialog_email" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
viewpager2
recyclerview
BottomNavigationView
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
android:fitsSystemWindows="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/homeContent"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/nav_view"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
val root = inflater.inflate(R.layout.fragment_home, container, false)
val fragmentStateAdapter = object : FragmentStateAdapter(this) {
private val tabFragmentsCreators: Map<Int, () -> Fragment> = mapOf(
0 to { BottomHomeFragment() },
1 to { DashboardFragment() },
2 to { NotificationsFragment() }
)
override fun getItemCount() = tabFragmentsCreators.size
override fun createFragment(position: Int): Fragment {
return tabFragmentsCreators[position]?.invoke() ?: throw IndexOutOfBoundsException()
}
}
root.homeContent.adapter = fragmentStateAdapter
root.homeContent.registerOnPageChangeCallback(object : OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
when (position) {
0 -> {
root.nav_view.selectedItemId = R.id.navigation_home
}
1 -> {
root.nav_view.selectedItemId = R.id.navigation_dashboard
}
2 -> {
root.nav_view.selectedItemId = R.id.navigation_notifications
}
}
}
})
root.nav_view.setOnNavigationItemSelectedListener {
Log.e("nav_view", "${it.itemId}")
when (it.itemId) {
R.id.navigation_home -> {
root.homeContent.setCurrentItem(0, true)
}
R.id.navigation_dashboard -> {
root.homeContent.setCurrentItem(1, true)
}
R.id.navigation_notifications -> {
root.homeContent.setCurrentItem(2, true)
}
else -> {
}
}
true
}
数据库Room
implementation "androidx.room:room-ktx:2.2.5"
kapt "androidx.room:room-compiler:2.2.5"
//异步任务处理
implementation "androidx.work:work-runtime-ktx:2.3.4"
@Database(entities = [Plant::class, GardenPlanting::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun plantDao(): PlantDao
abstract fun gardenPlantingDao(): GardenPlantingDao
companion object {
// For Singleton instantiation
@Volatile
private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
instance ?: buildDatabase(context).also { instance = it }
}
}
// Create and pre-populate the database. See this article for more details:
// https://medium.com/google-developers/7-pro-tips-for-room-fbadea4bfbd1#4785
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
.addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
val request = OneTimeWorkRequestBuilder<SeedDatabaseWorker>().build()
WorkManager.getInstance(context).enqueue(request)
}
})
.build()
}
}
}
@Dao
interface GardenPlantingDao {
@Query("SELECT * FROM garden_plantings")
fun getGardenPlantings(): LiveData<List<GardenPlanting>>
@Query("SELECT EXISTS(SELECT 1 FROM garden_plantings WHERE plant_id = :plantId LIMIT 1)")
fun isPlanted(plantId: String): LiveData<Boolean>
/**
* This query will tell Room to query both the [Plant] and [GardenPlanting] tables and handle
* the object mapping.
*/
@Transaction
@Query("SELECT * FROM garden_plantings")
fun getPlantGardens(): LiveData<List<PlantAndGardenPlanting>>
@Query("SELECT * FROM garden_plantings WHERE plant_id = :plantId")
fun getGardenPlanting(plantId: String): LiveData<GardenPlanting>
@Insert
suspend fun insertGardenPlanting(gardenPlanting: GardenPlanting): Long
@Delete
suspend fun deleteGardenPlanting(gardenPlanting: GardenPlanting)
@Update
suspend fun updateGardenPlanting(gardenPlanting: GardenPlanting)
}
设计模式MVVM
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.fragment:fragment-ktx:1.2.3'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.61"
//协程
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0"
DataBinding
dataBinding {
enabled = true
}
navigation
implementation "androidx.navigation:navigation-fragment-ktx:2.2.1"
implementation "androidx.navigation:navigation-ui-ktx:2.2.1"