关联用户列表优化

This commit is contained in:
2026-05-25 14:04:53 +08:00
parent fe025c8a69
commit fd84f18e4d
7 changed files with 206 additions and 366 deletions

View File

@@ -102,5 +102,6 @@ dependencies {
implementation("androidx.camera:camera-view:1.0.0-alpha25") implementation("androidx.camera:camera-view:1.0.0-alpha25")
//上拉刷新下拉加载 //上拉刷新下拉加载
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("com.yanzhenjie.recyclerview:x:1.3.2")
} }

View File

@@ -5,7 +5,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.databinding.ItemLinkedUserBinding import com.example.defenseapplication.databinding.ItemLinkedUserBinding
import com.example.defenseapplication.view.SlideLayout
data class LinkedUser( data class LinkedUser(
val userId: String, val userId: String,
@@ -16,18 +15,11 @@ data class LinkedUser(
) )
class LinkedUserAdapter( class LinkedUserAdapter(
private val deleteText: String,
private val isUnlinkMode: Boolean, private val isUnlinkMode: Boolean,
private val onItemClick: (LinkedUser, Int) -> Unit, private val onItemClick: (LinkedUser, Int) -> Unit
private val onDeleteClick: (LinkedUser, Int) -> Unit
) : RecyclerView.Adapter<LinkedUserAdapter.LinkedUserViewHolder>() { ) : RecyclerView.Adapter<LinkedUserAdapter.LinkedUserViewHolder>() {
private val items = mutableListOf<LinkedUser>() private val items = mutableListOf<LinkedUser>()
private var _openSlideLayout: SlideLayout? = null
/** 供外部(如 Activity访问当前展开的 SlideLayout */
val openSlideLayout: SlideLayout?
get() = _openSlideLayout
fun submitList(userList: List<LinkedUser>) { fun submitList(userList: List<LinkedUser>) {
items.clear() items.clear()
@@ -52,54 +44,7 @@ class LinkedUserAdapter(
} }
override fun onBindViewHolder(holder: LinkedUserViewHolder, position: Int) { override fun onBindViewHolder(holder: LinkedUserViewHolder, position: Int) {
val item = items[position] holder.bind(items[position], position)
holder.bind(item)
// 每次 bind 都设置监听器RecyclerView 复用视图时也会调用
val slideLayout = holder.itemView as SlideLayout
slideLayout.setOnSlideChangeListener(object : SlideLayout.OnSlideChangeListener {
override fun onMenuOpen(slideLayout: SlideLayout) {
val prev = _openSlideLayout
if (prev != null && prev != slideLayout) {
prev.closeMenu()
}
_openSlideLayout = slideLayout
}
override fun onMenuClose(slideLayout: SlideLayout) {
if (_openSlideLayout == slideLayout) {
_openSlideLayout = null
}
}
override fun onClick(slideLayout: SlideLayout) {
val prev = _openSlideLayout
if (prev != null && prev != slideLayout) {
prev.closeMenu()
}
}
})
holder.binding.llContent.setOnClickListener {
val pos = holder.bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) {
onItemClick(items[pos], pos)
}
}
holder.binding.tvDeleteAction.setOnClickListener {
val pos = holder.bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) {
onDeleteClick(items[pos], pos)
}
}
holder.binding.tvUnlinkAction.setOnClickListener {
val pos = holder.bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) {
onDeleteClick(items[pos], pos)
}
}
} }
override fun getItemCount(): Int = items.size override fun getItemCount(): Int = items.size
@@ -108,19 +53,14 @@ class LinkedUserAdapter(
val binding: ItemLinkedUserBinding val binding: ItemLinkedUserBinding
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: LinkedUser) { fun bind(item: LinkedUser, position: Int) {
binding.tvUserName.text = item.name binding.tvUserName.text = item.name
binding.tvTime.text = item.time binding.tvTime.text = item.time
binding.tvPhone.text = "手机号码:${item.phone}" binding.tvPhone.text = "手机号码:${item.phone}"
binding.tvIdCard.text = "身份证号:${item.idCard}" binding.tvIdCard.text = "身份证号:${item.idCard}"
if (isUnlinkMode) { binding.root.setOnClickListener {
binding.tvUnlinkAction.visibility = View.VISIBLE onItemClick(item, position)
binding.tvDeleteAction.visibility = View.GONE
} else {
binding.tvUnlinkAction.visibility = View.GONE
binding.tvDeleteAction.visibility = View.VISIBLE
binding.tvDeleteAction.text = deleteText
} }
} }
} }

View File

@@ -5,6 +5,7 @@ import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@@ -22,10 +23,12 @@ import com.example.defenseapplication.utils.DeviceUserUpdateEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.view.CustomDialogFragmentText import com.example.defenseapplication.view.CustomDialogFragmentText
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import com.yanzhenjie.recyclerview.SwipeMenuItem
import com.yanzhenjie.recyclerview.SwipeRecyclerView
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
//关联用户页面
class LinkedUserActivity : AppCompatActivity() { class LinkedUserActivity : AppCompatActivity() {
private lateinit var binding: LinkedUserActivityBinding private lateinit var binding: LinkedUserActivityBinding
@@ -35,8 +38,6 @@ class LinkedUserActivity : AppCompatActivity() {
private var mode: Int = MODE_SETTINGS private var mode: Int = MODE_SETTINGS
companion object { companion object {
const val REQUEST_CODE_SEARCH = 1001
const val EXTRA_SEARCH_RESULT = "search_result"
const val EXTRA_MODE = "extra_mode" const val EXTRA_MODE = "extra_mode"
const val MODE_SETTINGS = 0 const val MODE_SETTINGS = 0
const val MODE_PERSONAL = 1 const val MODE_PERSONAL = 1
@@ -73,45 +74,57 @@ class LinkedUserActivity : AppCompatActivity() {
} }
private fun initView() { private fun initView() {
val deleteText = if (mode == MODE_SETTINGS) getString(R.string.unlink) else getString(R.string.delete)
val isUnlinkMode = mode == MODE_SETTINGS
adapter = LinkedUserAdapter( adapter = LinkedUserAdapter(
deleteText = deleteText, isUnlinkMode = mode == MODE_SETTINGS,
isUnlinkMode = isUnlinkMode,
onItemClick = { user, position -> onItemClick = { user, position ->
val intent = Intent(this, UserDetailsActivity::class.java).apply { val intent = Intent(this, UserDetailsActivity::class.java).apply {
putExtra("userId", user.userId) putExtra("userId", user.userId)
putExtra("deleteText", if (mode == MODE_SETTINGS) getString(R.string.unlink) else getString(R.string.delete))
putExtra("isUnlinkMode", mode == MODE_SETTINGS)
} }
startActivity(intent) startActivity(intent)
},
onDeleteClick = { user, position ->
showUnlinkDialog(user, position)
} }
) )
binding.rvLinkedUser.layoutManager = LinearLayoutManager(this)
binding.rvLinkedUser.adapter = adapter (binding.rvLinkedUser as RecyclerView).layoutManager = LinearLayoutManager(this)
binding.swipeRefresh.setOnRefreshListener { binding.swipeRefresh.setOnRefreshListener {
fetchUserList() fetchUserList()
} }
binding.rvLinkedUser.addOnScrollListener(object : RecyclerView.OnScrollListener() { binding.rvLinkedUser.setSwipeMenuCreator { leftMenu, rightMenu, position ->
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { if (mode == MODE_SETTINGS) {
super.onScrolled(recyclerView, dx, dy) val unlinkItem = SwipeMenuItem(this@LinkedUserActivity).apply {
val layoutManager = recyclerView.layoutManager as LinearLayoutManager setText(getString(R.string.unlink))
val totalItemCount = layoutManager.itemCount setBackgroundColor(getColor(R.color.red))
val lastVisibleItem = layoutManager.findLastVisibleItemPosition() setTextColor(getColor(R.color.white))
if (totalItemCount > 0 && lastVisibleItem >= totalItemCount - 3) { width = 200
if (!binding.swipeRefresh.isRefreshing) { height = ViewGroup.LayoutParams.MATCH_PARENT
fetchUserList()
}
} }
rightMenu.addMenuItem(unlinkItem)
} else {
val deleteItem = SwipeMenuItem(this@LinkedUserActivity).apply {
setText(getString(R.string.delete))
setBackgroundColor(getColor(R.color.red))
setTextColor(getColor(R.color.white))
width = 200
height = ViewGroup.LayoutParams.MATCH_PARENT
}
rightMenu.addMenuItem(deleteItem)
} }
}) }
binding.rvLinkedUser.setOnItemMenuClickListener { _, position ->
// 直接关闭菜单(使用 RecyclerView 的方法)
binding.rvLinkedUser.smoothCloseMenu() // 或 closeMenu()
val user = userList[position]
showDeleteDialog(user, position)
}
(binding.rvLinkedUser as RecyclerView).adapter = adapter
} }
private fun showUnlinkDialog(user: LinkedUser, position: Int) { private fun showDeleteDialog(user: LinkedUser, position: Int) {
val dialog = CustomDialogFragmentText() val dialog = CustomDialogFragmentText()
if (mode == MODE_SETTINGS) { if (mode == MODE_SETTINGS) {
dialog.setTitle(getString(R.string.tip)) dialog.setTitle(getString(R.string.tip))
@@ -121,18 +134,10 @@ class LinkedUserActivity : AppCompatActivity() {
dialog.setMessage(getString(R.string.confirm_delete_user)) dialog.setMessage(getString(R.string.confirm_delete_user))
} }
dialog.setShowInput(false) dialog.setShowInput(false)
dialog.setPositiveText(getString(R.string.confirm))
dialog.setNegativeText(getString(R.string.cancel))
dialog.setOnConfirmListener { dialog.setOnConfirmListener {
deleteDeviceUser(user, position) deleteDeviceUser(user, position)
} }
dialog.setOnDismissListener { dialog.show(supportFragmentManager, "DeleteDialog")
// Dialog 关闭后,如果之前打开了菜单则关闭它
if (adapter.openSlideLayout != null) {
adapter.openSlideLayout?.closeMenu()
}
}
dialog.show(supportFragmentManager, "UnlinkDialog")
} }
private fun deleteDeviceUser(user: LinkedUser, position: Int) { private fun deleteDeviceUser(user: LinkedUser, position: Int) {
@@ -152,7 +157,8 @@ class LinkedUserActivity : AppCompatActivity() {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (response.code == 200) { if (response.code == 200) {
userList.removeAt(position) userList.removeAt(position)
adapter.removeItem(position) adapter.notifyItemRemoved(position) // 通知删除动画
adapter.notifyItemRangeChanged(position, userList.size - position) // 更新后续位置索引
Toast.makeText(this@LinkedUserActivity, "删除成功", Toast.LENGTH_SHORT).show() Toast.makeText(this@LinkedUserActivity, "删除成功", Toast.LENGTH_SHORT).show()
} else { } else {
Toast.makeText(this@LinkedUserActivity, response.msg, Toast.LENGTH_SHORT).show() Toast.makeText(this@LinkedUserActivity, response.msg, Toast.LENGTH_SHORT).show()
@@ -175,12 +181,15 @@ class LinkedUserActivity : AppCompatActivity() {
binding.swipeRefresh.isRefreshing = true binding.swipeRefresh.isRefreshing = true
lifecycleScope.launch { lifecycleScope.launch {
try { try {
val response = if (mode == MODE_SETTINGS) { val deviceId = DeviceIdEvent.getDeviceId()
val deviceId = DeviceIdEvent.getDeviceId() if (deviceId.isNullOrEmpty()) {
if (deviceId.isNullOrEmpty()) { Toast.makeText(this@LinkedUserActivity, "设备 ID 为空", Toast.LENGTH_SHORT).show()
Toast.makeText(this@LinkedUserActivity, "设备 ID 为空", Toast.LENGTH_SHORT).show() withContext(Dispatchers.Main) {
return@launch binding.swipeRefresh.isRefreshing = false
} }
return@launch
}
val response = if (mode == MODE_SETTINGS) {
RetrofitNetwork.getNetworkService().getDeviceUserList(deviceId) RetrofitNetwork.getNetworkService().getDeviceUserList(deviceId)
} else { } else {
RetrofitNetwork.getNetworkService().getFamilyMembers() RetrofitNetwork.getNetworkService().getFamilyMembers()
@@ -289,18 +298,5 @@ class LinkedUserActivity : AppCompatActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_SEARCH && resultCode == RESULT_OK) {
data?.getStringExtra(EXTRA_SEARCH_RESULT)?.let { result ->
val newUser = LinkedUser(
userId = "",
name = result,
phone = "13800000000",
idCard = "110101199001011234",
time = "2026-05-10 ${android.text.format.DateFormat.format("HH:mm:ss", System.currentTimeMillis())}"
)
userList.add(0, newUser)
adapter.submitList(userList)
}
}
} }
} }

View File

@@ -1,176 +0,0 @@
package com.example.defenseapplication.view
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewParent
import android.widget.FrameLayout
import android.widget.OverScroller
class SlideLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
private val scroller = OverScroller(context)
private var downX: Float = 0f
private var downY: Float = 0f
private var lastX: Float = 0f
private var isHorizontalDragging: Boolean = false
private var listener: OnSlideChangeListener? = null
private var shouldMenuBeOpen: Boolean = false
/** 缓存菜单宽度,避免 RecyclerView 复用时 measuredWidth 读取不到 */
private var cachedMenuWidth: Int = 0
interface OnSlideChangeListener {
fun onMenuOpen(slideLayout: SlideLayout)
fun onMenuClose(slideLayout: SlideLayout)
fun onClick(slideLayout: SlideLayout)
}
fun setOnSlideChangeListener(listener: OnSlideChangeListener) {
this.listener = listener
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
// 缓存菜单宽度,在 onLayout 和 onTouchEvent 中使用
cachedMenuWidth = if (childCount >= 2) getChildAt(0).measuredWidth else 0
}
private fun getMenuWidth(): Int {
// 优先使用缓存值RecyclerView 复用时 measuredWidth 可能尚未更新
val w = cachedMenuWidth
return if (w > 0) w else {
if (childCount >= 2) {
val measured = getChildAt(0).measuredWidth
if (measured > 0) measured else getChildAt(0).width
} else 0
}
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
if (childCount < 2) return
val contentWidth = right - left
val menu = getChildAt(0)
val menuW = getMenuWidth()
// 内容左移 scrollX → 菜单右边缘逐渐露出
// 菜单左边界 = 内容右边缘 - scrollX
menu.layout(contentWidth - scrollX, top, contentWidth - scrollX + menuW, bottom)
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
downX = ev.x
downY = ev.y
lastX = ev.x
isHorizontalDragging = false
}
MotionEvent.ACTION_MOVE -> {
val dx = Math.abs(ev.x - downX)
val dy = Math.abs(ev.y - downY)
if (dx > dy && dx > 10f) {
isHorizontalDragging = true
disallowInterceptChain(true)
return true
}
}
}
return super.onInterceptTouchEvent(ev)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
downX = event.x
downY = event.y
lastX = event.x
disallowInterceptChain(true)
return true
}
MotionEvent.ACTION_MOVE -> {
val dx = lastX - event.x
lastX = event.x
if (Math.abs(event.x - downX) > 10f) {
isHorizontalDragging = true
}
if (isHorizontalDragging) {
val menuW = getMenuWidth()
var newScrollX = scrollX + dx.toInt()
if (newScrollX < 0) newScrollX = 0
if (newScrollX > menuW) newScrollX = menuW
scrollTo(newScrollX, 0)
}
}
MotionEvent.ACTION_UP -> {
val wasDragging = isHorizontalDragging
isHorizontalDragging = false
disallowInterceptChain(false)
if (!wasDragging) {
listener?.onClick(this)
} else {
val menuW = getMenuWidth()
if (scrollX > menuW / 2) {
openMenu()
} else {
closeMenu()
}
}
}
MotionEvent.ACTION_CANCEL -> {
isHorizontalDragging = false
disallowInterceptChain(false)
// 弹窗等外部中断:按当前菜单是否露出状态决定动画关闭或保持关闭
if (scrollX > 0) {
closeMenu()
}
}
}
return true
}
private fun disallowInterceptChain(disallow: Boolean) {
var parent: ViewParent? = parent
while (parent != null) {
parent.requestDisallowInterceptTouchEvent(disallow)
parent = parent.parent
}
}
override fun computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.currX, scroller.currY)
postInvalidateOnAnimation()
}
}
fun openMenu() {
val menuW = getMenuWidth()
if (shouldMenuBeOpen && scrollX == menuW) return
shouldMenuBeOpen = true
scroller.startScroll(scrollX, 0, menuW - scrollX, 0, 300)
postInvalidateOnAnimation()
listener?.onMenuOpen(this)
}
fun closeMenu() {
if (!shouldMenuBeOpen && scrollX == 0) return
shouldMenuBeOpen = false
scroller.startScroll(scrollX, 0, -scrollX, 0, 300)
postInvalidateOnAnimation()
listener?.onMenuClose(this)
}
fun isMenuOpened(): Boolean = shouldMenuBeOpen
}

View File

@@ -0,0 +1,118 @@
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/bg_gray"
tools:context=".liveVideo.LinkedUserActivity">
<!-- 标题栏 -->
<LinearLayout
android:id="@+id/topBar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:paddingHorizontal="16dp"
android:background="@color/white">
<ImageView
android:id="@+id/ivBack"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/back" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/linked_user"
android:textColor="@color/black"
android:textSize="16dp"
android:textStyle="bold" />
</LinearLayout>
<!-- 搜索区域 -->
<LinearLayout
android:id="@+id/searchLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:paddingHorizontal="16dp"
android:paddingVertical="12dp"
android:layout_marginTop="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/bg_user_manage"
android:gravity="center_vertical"
android:paddingHorizontal="16dp">
<ImageView
android:layout_width="18dp"
android:layout_height="18dp"
android:src="@drawable/search"
android:layout_marginRight="8dp"/>
<EditText
android:id="@+id/etSearch"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@null"
android:hint="@string/search_preset_text"
android:textColorHint="@color/gray"
android:textColor="@color/black"
android:textSize="14sp"
android:inputType="text"
android:imeOptions="actionSearch"
android:singleLine="true"/>
</LinearLayout>
</LinearLayout>
<!-- 列表区域 -->
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefresh"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<com.yanzhenjie.recyclerview.SwipeRecyclerView
android:id="@+id/rvLinkedUser"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="16dp"
android:paddingTop="8dp"
android:paddingBottom="16dp"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<!-- 底部按钮 -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
android:paddingBottom="60dp">
<android.widget.Button
android:id="@+id/btnAddLinkedUser"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="@string/add_linked_user"
android:textColor="@color/white"
android:textSize="14dp"
android:background="@drawable/rounded_blue_bg" />
<!-- 悬浮加号按钮 -->
<ImageView
android:visibility="gone"
android:layout_gravity="end"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/add_img"
android:id="@+id/fabAdd"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,86 +1,47 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<com.example.defenseapplication.view.SlideLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout 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_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="120dp"
android:background="@color/white"
android:orientation="vertical"
android:padding="16dp">
<!-- 背景按钮层:删除 + 解除关联 两个按钮 -->
<LinearLayout <LinearLayout
android:id="@+id/llActions" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_height="120dp"
android:gravity="start|center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/tvDeleteAction" android:id="@+id/tvUserName"
android:layout_width="100dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:background="@color/red" android:layout_weight="1"
android:gravity="center" android:textColor="@color/black"
android:text="@string/delete"
android:textColor="@color/white"
android:textSize="16sp" android:textSize="16sp"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:id="@+id/tvUnlinkAction" android:id="@+id/tvTime"
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="@color/red"
android:gravity="center"
android:text="@string/unlink"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<!-- 前景内容层:随 swipe 移动 -->
<LinearLayout
android:id="@+id/llContent"
android:layout_width="match_parent"
android:layout_height="120dp"
android:background="@color/white"
android:orientation="vertical"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tvUserName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/black"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/gray"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:id="@+id/tvPhone"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textColor="@color/gray" android:textColor="@color/gray"
android:textSize="14sp" /> android:textSize="12sp" />
<TextView
android:id="@+id/tvIdCard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/gray"
android:textSize="14sp" />
</LinearLayout> </LinearLayout>
</com.example.defenseapplication.view.SlideLayout> <TextView
android:id="@+id/tvPhone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textColor="@color/gray"
android:textSize="14sp" />
<TextView
android:id="@+id/tvIdCard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/gray"
android:textSize="14sp" />
</LinearLayout>

View File

@@ -78,7 +78,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1"> android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView <com.yanzhenjie.recyclerview.SwipeRecyclerView
android:id="@+id/rvLinkedUser" android:id="@+id/rvLinkedUser"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"