feat: Use material search view & recyclerview adapter handler is activity

This commit is contained in:
AnranYus
2023-11-04 17:19:07 +08:00
parent b386e87bc8
commit e3336b0458
6 changed files with 80 additions and 216 deletions
+3 -3
View File
@@ -4,12 +4,12 @@ plugins {
} }
android { android {
compileSdkVersion = 33 compileSdkVersion = 34
defaultConfig { defaultConfig {
applicationId "com.lsp.view" applicationId "com.lsp.view"
minSdkVersion 29 minSdkVersion 29
targetSdkVersion 33 targetSdkVersion 34
versionCode 221022 versionCode 221022
versionName "1.2.7" versionName "1.2.7"
@@ -33,7 +33,7 @@ android {
} }
dependencies { dependencies {
implementation("com.google.android.material:material:1.5.0") implementation("com.google.android.material:material:1.10.0")
implementation 'jp.wasabeef:recyclerview-animators:4.0.2' implementation 'jp.wasabeef:recyclerview-animators:4.0.2'
implementation "androidx.drawerlayout:drawerlayout:1.1.1" implementation "androidx.drawerlayout:drawerlayout:1.1.1"
implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0'
@@ -1,34 +1,20 @@
package com.lsp.view.activity.main package com.lsp.view.activity.main
import android.animation.Animator import android.os.Bundle
import android.animation.AnimatorListenerAdapter
import android.content.Intent
import android.os.*
import android.util.Log import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.GravityCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat.Type.ime
import androidx.drawerlayout.widget.DrawerLayout
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.google.android.material.navigation.NavigationView import com.google.android.material.search.SearchBar
import com.google.android.material.search.SearchView
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.lsp.view.YandViewApplication
import com.lsp.view.R import com.lsp.view.R
import com.lsp.view.activity.favtag.FavTagActivity import com.lsp.view.YandViewApplication
import com.lsp.view.activity.setting.SettingsActivity
import com.lsp.view.model.MainViewModel import com.lsp.view.model.MainViewModel
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private lateinit var search: EditText
private var shortAnnotationDuration: Int = 0 private var shortAnnotationDuration: Int = 0
private var username: String? = "" private var username: String? = ""
val TAG = javaClass.simpleName val TAG = javaClass.simpleName
@@ -38,11 +24,13 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
viewModel = MainViewModel.provideFactory((application as YandViewApplication).repository, this,this).create(MainViewModel::class.java) viewModel = MainViewModel.provideFactory((application as YandViewApplication).repository, this,this).create(MainViewModel::class.java)
val adapter by lazy {
viewModel.fetchPostByRefresh()
PostAdapter(this)
}
//刷新 //刷新
val refresh = val refresh =
findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipeRefreshLayout) findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipeRefreshLayout)
@@ -53,14 +41,26 @@ class MainActivity : AppCompatActivity() {
viewModel.errorMessage.observe(this){ viewModel.errorMessage.observe(this){
Snackbar.make(refresh,it,Snackbar.LENGTH_SHORT).show() Snackbar.make(refresh,it,Snackbar.LENGTH_SHORT).show()
} }
viewModel.postList.observe(this){
search = findViewById(R.id.search) if (adapter.isAppendData){
shortAnnotationDuration = resources.getInteger(android.R.integer.config_shortAnimTime) adapter.appendDate(it)
}else{
search.setOnEditorActionListener { content, actionId, _ -> adapter.pushNewData(it)
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
viewModel.fetchPostBySearch(content.text.toString())
} }
}
shortAnnotationDuration = resources.getInteger(android.R.integer.config_shortAnimTime)
val searchBar = findViewById<SearchBar>(R.id.search_bar)
val searchView = findViewById<SearchView>(R.id.search_view)
searchView.editText.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
viewModel.fetchPostBySearch(searchView.text.toString())
searchBar.setText(searchView.text)
searchView.hide()
}
return@setOnEditorActionListener false return@setOnEditorActionListener false
} }
@@ -70,31 +70,28 @@ class MainActivity : AppCompatActivity() {
viewModel.uiState.value.nowSearchText.value = stringExtra viewModel.uiState.value.nowSearchText.value = stringExtra
} }
viewModel.uiState.value.nowSearchText.observe(this){ viewModel.uiState.value.nowSearchText.observe(this){
search.setText(it) searchView.setText(it)
searchBar.setText(it)
} }
// val appbar = findViewById<AppBarLayout>(R.id.appbar)
// val nowHeight = appbar.layoutParams.height
// appbar.layoutParams.height = (application as YandViewApplication).statusBarHeight()+nowHeight
refresh.setOnRefreshListener { refresh.setOnRefreshListener {
viewModel.fetchPostByRefresh() viewModel.fetchPostByRefresh()
} }
viewModel.adapter.apply { adapter.apply {
setLoadMoreListener(object :PostAdapter.OnScrollToBottom{ setLoadMoreListener(object :PostAdapter.OnScrollToBottom{
override fun event(position: Int) { override fun event(position: Int) {
adapter.isAppendData = true//设置数据状态为追加数据
viewModel.fetchMore() viewModel.fetchMore()
} }
}) })
} }
findViewById<RecyclerView>(R.id.recyclerview).apply { findViewById<RecyclerView>(R.id.recyclerview).apply {
val layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) val layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
this.layoutManager = layoutManager this.layoutManager = layoutManager
this.adapter = viewModel.adapter this.adapter = adapter
} }
@@ -108,39 +105,6 @@ class MainActivity : AppCompatActivity() {
val sp = getSharedPreferences("username", 0) val sp = getSharedPreferences("username", 0)
username = sp.getString("username", null) username = sp.getString("username", null)
val nav = findViewById<NavigationView>(R.id.nav)
//加载导航栏列表
nav.setCheckedItem(R.id.photo)
//设置侧边栏点击逻辑
nav.setNavigationItemSelectedListener {
val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
when (it.itemId) {
//画廊
R.id.photo -> {
viewModel.fetchPostByRefresh()
drawerLayout.closeDrawers()
true
}
//设置
R.id.setting -> {
val intent = Intent(this, SettingsActivity::class.java)
startActivity(intent)
drawerLayout.closeDrawers()
false
}
R.id.taglist -> {
val intent = Intent(this, FavTagActivity::class.java)
startActivity(intent)
drawerLayout.closeDrawers()
false
}
else -> false
}
}
} }
override fun onResume() { override fun onResume() {
@@ -163,74 +127,4 @@ class MainActivity : AppCompatActivity() {
} }
//隐藏搜索栏
private fun hiddenSearchBar() {
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_baseline_menu_24)
search.animate()
.alpha(0f)
.setDuration(shortAnnotationDuration.toLong())
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
search.visibility = View.GONE
}
})
hideIm()
viewModel.uiState.value.switchShowSearchBar()
}
//现实搜索栏
private fun showSearchBar() {
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_baseline_arrow_back_24)
search.apply {
alpha = 0f
visibility = View.VISIBLE
animate()
.alpha(1f)
.setDuration(shortAnnotationDuration.toLong())
.setListener(null)
}
viewModel.uiState.value.switchShowSearchBar()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
if (viewModel.uiState.value.showSearchBar){
hiddenSearchBar()
}else {
val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
drawerLayout.openDrawer(GravityCompat.START)
}
}
R.id.search_nav -> {
if (viewModel.uiState.value.showSearchBar) {
viewModel.fetchPostByRefresh()
hideIm()
}
if (search.visibility == View.GONE) {
showSearchBar()
}
}
}
return true
}
private fun hideIm() {
WindowCompat.getInsetsController(this.window,window.decorView).hide(ime())
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.toolbar_menu, menu)
return true
}
} }
@@ -14,13 +14,11 @@ import com.lsp.view.activity.pic.PicActivity
import com.lsp.view.repository.bean.YandPost import com.lsp.view.repository.bean.YandPost
class PostAdapter(val context: Context): class PostAdapter(val context: Context,private val postList: ArrayList<YandPost> = ArrayList()):
RecyclerView.Adapter<PostAdapter.ViewHolder>() { RecyclerView.Adapter<PostAdapter.ViewHolder>() {
val TAG = this::class.java.simpleName val TAG = this::class.java.simpleName
private val UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" private val UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
var isAppendData = false//数据追加标志
private var postList = ArrayList<YandPost>()
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val picImage: ImageView = view.findViewById(R.id.picImgae) val picImage: ImageView = view.findViewById(R.id.picImgae)
@@ -39,6 +37,7 @@ class PostAdapter(val context: Context):
val pos = postList.size val pos = postList.size
postList.addAll(list) postList.addAll(list)
notifyItemRangeInserted(pos-1, list.size) notifyItemRangeInserted(pos-1, list.size)
isAppendData = false
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@@ -11,6 +11,8 @@ import androidx.lifecycle.viewModelScope
import com.lsp.view.activity.main.PostAdapter import com.lsp.view.activity.main.PostAdapter
import com.lsp.view.repository.PostRepository import com.lsp.view.repository.PostRepository
import androidx.savedstate.SavedStateRegistryOwner import androidx.savedstate.SavedStateRegistryOwner
import com.lsp.view.repository.bean.Post
import com.lsp.view.repository.bean.YandPost
import com.lsp.view.repository.exception.NetworkErrorException import com.lsp.view.repository.exception.NetworkErrorException
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@@ -25,12 +27,14 @@ class MainViewModel(private val repository: PostRepository,context: Context):Vie
val uiState:StateFlow<UiState> val uiState:StateFlow<UiState>
get() = _uiState.asStateFlow() get() = _uiState.asStateFlow()
private var fetchJob: Job? = null private var fetchJob: Job? = null
val adapter = PostAdapter(context)
private val TAG = this::class.java.simpleName private val TAG = this::class.java.simpleName
private val _errorMessage = MutableLiveData<String>() private val _errorMessage = MutableLiveData<String>()
val errorMessage val errorMessage
get() = _errorMessage as LiveData<String> get() = _errorMessage as LiveData<String>
private val _postList = MutableLiveData<ArrayList<YandPost>>()
val postList get() = _postList as LiveData<ArrayList<YandPost>>
companion object { companion object {
fun provideFactory( fun provideFactory(
@@ -77,19 +81,11 @@ class MainViewModel(private val repository: PostRepository,context: Context):Vie
fetchJob = viewModelScope.launch(Dispatchers.IO) { fetchJob = viewModelScope.launch(Dispatchers.IO) {
_uiState.value.isRefreshing.postValue(true) _uiState.value.isRefreshing.postValue(true)
try { try {
val postList = repository.fetchPostData( _postList.postValue(repository.fetchPostData(
_uiState.value.nowSearchText.value, _uiState.value.nowSearchText.value,
_uiState.value.isSafe, _uiState.value.isSafe,
_uiState.value.nowPage _uiState.value.nowPage
) ))
launch(Dispatchers.Main) {
if (append){
adapter.appendDate(postList)
}else{
adapter.pushNewData(postList)
}
}
}catch (e:NetworkErrorException){ }catch (e:NetworkErrorException){
_errorMessage.postValue(e.message.toString()) _errorMessage.postValue(e.message.toString())
@@ -7,7 +7,7 @@ class PostRepository {
private val dataSource = PostDataSource() private val dataSource = PostDataSource()
//获取post //获取post
suspend fun fetchPostData(searchTarget :String?,safe:Boolean,page:Int): List<YandPost> { suspend fun fetchPostData(searchTarget :String?,safe:Boolean,page:Int): ArrayList<YandPost> {
var target = searchTarget var target = searchTarget
var isNum = true var isNum = true
@@ -26,7 +26,7 @@ class PostRepository {
val dataList = dataSource.fetchNewPost(load) val dataList = dataSource.fetchNewPost(load)
return if (safe){ return if (safe){
dataList.filter { it.rating == "s" } ArrayList(dataList.filter { it.rating == "s" })
}else{ }else{
dataList dataList
} }
+32 -57
View File
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout <androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/drawerLayout"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
@@ -8,63 +7,39 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".activity.main.MainActivity"> tools:context=".activity.main.MainActivity">
<RelativeLayout <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:id="@+id/rl" android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content">
tools:context=".activity.main.MainActivity"> <androidx.recyclerview.widget.RecyclerView
app:layout_behavior="@string/appbar_scrolling_view_behavior"
<androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/recyclerview"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="wrap_content">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.search.SearchBar
android:layout_width="match_parent" android:id="@+id/search_bar"
android:layout_height="wrap_content"> android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.appcompat.widget.Toolbar <com.google.android.material.search.SearchView
android:layout_width="match_parent" android:id="@+id/search_view"
android:layout_height="?attr/actionBarSize" android:layout_width="match_parent"
app:menu="@menu/toolbar_menu" android:layout_height="wrap_content"
android:id="@+id/toolbar" app:layout_anchor="@id/search_bar">
app:layout_scrollFlags="scroll|enterAlways|snap" <androidx.recyclerview.widget.RecyclerView
> android:layout_width="match_parent"
<EditText android:layout_height="wrap_content"
android:layout_width="match_parent" android:id="@+id/search_tip"
android:layout_height="match_parent" android:visibility="gone"/>
android:textSize="20sp" </com.google.android.material.search.SearchView>
android:id="@+id/search"
android:imeOptions="actionSearch"
android:singleLine="true"
android:visibility="gone" />
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:id="@+id/swipeRefreshLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/recyclerview"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>
<com.google.android.material.navigation.NavigationView
android:layout_width="240dp"
android:layout_height="match_parent"
android:id="@+id/nav"
android:layout_gravity="start"
app:menu="@menu/nav_menu"
app:headerLayout="@layout/nav_header"
/>
</androidx.drawerlayout.widget.DrawerLayout>