From 85d11d6cd12abdd1e1f5f7516a7fb53a4826633f Mon Sep 17 00:00:00 2001
From: cloudroam <cloudroam>
Date: 星期二, 15 四月 2025 09:17:18 +0800
Subject: [PATCH] add: 消息提醒
---
app/src/main/java/com/example/firstapp/ui/invitation/InvitationActivity.kt | 384 +++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 334 insertions(+), 50 deletions(-)
diff --git a/app/src/main/java/com/example/firstapp/ui/invitation/InvitationActivity.kt b/app/src/main/java/com/example/firstapp/ui/invitation/InvitationActivity.kt
index 51fc5fc..353707d 100644
--- a/app/src/main/java/com/example/firstapp/ui/invitation/InvitationActivity.kt
+++ b/app/src/main/java/com/example/firstapp/ui/invitation/InvitationActivity.kt
@@ -1,98 +1,382 @@
package com.example.firstapp.ui.invitation
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
-import android.util.DisplayMetrics
+import android.text.Html
+import android.util.TypedValue
+import android.view.View
+import android.widget.Button
+import android.widget.TextView
+import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import com.example.firstapp.R
import com.example.firstapp.adapter.InvitationAdapter
+import com.example.firstapp.adapter.InvitationRecordAdapter
import com.example.firstapp.entity.InvitationRecord
-import java.text.SimpleDateFormat
-import java.util.Locale
-import java.util.concurrent.Executors
+import com.example.firstapp.utils.PreferencesManager
+import kotlin.math.abs
class InvitationActivity : AppCompatActivity() {
- private lateinit var recyclerView: RecyclerView
+ private lateinit var recyclerSuccessView: RecyclerView
+ private lateinit var recyclerRecordView: RecyclerView
private lateinit var adapter: InvitationAdapter
- private var currentPosition = 0
+ private lateinit var recordadapter: InvitationRecordAdapter
+ private val data = mutableListOf<InvitationRecord>()
+ private val recorddata = mutableListOf<InvitationRecord>()
private val handler = Handler(Looper.getMainLooper())
- private lateinit var scrollRunnable: Runnable
+ private val scrollInterval = 3000L
+ private var currentScrollPosition = 0
+ private var currentRecordScrollPosition = 0
+ private var itemHeight = 0 // 动态存储item高度
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_invitation_main)
- setupRecyclerView()
+ // 初始化视图
+ initViews()
+
+ //初始化Adapter
+ initSuccessAdapter()
+
+ initRecorddapter()
+
+ //加载数据
loadData()
- setupAutoScroll()
+
+ loadRecordData()
+
+ //启动轮播
+ startAutoScroll()
+
+ //分享
+ val btnInvite = findViewById<Button>(R.id.btnInvite)
+ btnInvite.setOnClickListener {
+ shareImageToWechat()
+ }
+
+ //邀请码
+ val invitationCodeText = findViewById<TextView>(R.id.invitationCodeText)
+ invitationCodeText.text = "A1B2"
+ //invitationCodeText.text = formatInvitationCode(PreferencesManager.getInviteCode());
+ findViewById<Button>(R.id.copyButton).setOnClickListener {
+ val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
+ val clip = ClipData.newPlainText(
+ "邀请码",
+ invitationCodeText.text.toString().replace(" ", "") // 复制时去掉空格
+ )
+ clipboard.setPrimaryClip(clip)
+ Toast.makeText(this, "已复制邀请码", Toast.LENGTH_SHORT).show()
+ }
}
- private fun setupRecyclerView() {
- recyclerView = findViewById(R.id.invitationsuccessRecyclerView)
- recyclerView.layoutManager = LinearLayoutManager(this).apply {
- stackFromEnd = false // 从顶部开始布局
+ private fun initViews() {
+ findViewById<TextView>(R.id.tv_notic).apply {
+ text = Html.fromHtml(getString(R.string.invite_reward_text), Html.FROM_HTML_MODE_LEGACY)
}
- adapter = InvitationAdapter()
- recyclerView.adapter = adapter
+ recyclerSuccessView = findViewById(R.id.invitationsuccessRecyclerView)
+ addSuccessListener()
+
+ recyclerRecordView = findViewById(R.id.invitationrecordRecyclerView)
+ addRecordListener()
+ }
+
+ private fun addSuccessListener() {
+ recyclerSuccessView.viewTreeObserver.addOnGlobalLayoutListener {
+ if (recyclerSuccessView.childCount > 0) {
+ // 计算预期高度(60dp转px)
+ val expectedHeight = dpToPx(60f)
+ if (itemHeight != expectedHeight) {
+ // 修正所有item的高度
+ for (i in 0 until recyclerSuccessView.childCount) {
+ recyclerSuccessView.getChildAt(i).layoutParams.height = expectedHeight
+ }
+ // 请求重新布局
+ recyclerSuccessView.requestLayout()
+ itemHeight = expectedHeight
+ }
+ }
+ }
+ recyclerSuccessView.layoutManager = object : LinearLayoutManager(this@InvitationActivity) {
+ override fun onMeasure(
+ recycler: RecyclerView.Recycler, state: RecyclerView.State,
+ widthSpec: Int, heightSpec: Int
+ ) {
+ if (itemHeight > 0) {
+ // 使用实际测量的高度
+ setMeasuredDimension(
+ View.resolveSize(widthSpec, width),
+ itemHeight
+ )
+ } else {
+ // 默认高度60dp
+ val defaultHeight = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, 60f,
+ resources.displayMetrics
+ ).toInt()
+ setMeasuredDimension(
+ View.resolveSize(widthSpec, width),
+ defaultHeight
+ )
+ }
+ }
+ }
+ }
+
+ private fun addRecordListener() {
+ recyclerRecordView.viewTreeObserver.addOnGlobalLayoutListener {
+ if (recyclerSuccessView.childCount > 0) {
+ // 计算预期高度(60dp转px)
+ val expectedHeight = dpToPx(60f)
+ if (itemHeight != expectedHeight) {
+ // 修正所有item的高度
+ for (i in 0 until recyclerSuccessView.childCount) {
+ recyclerSuccessView.getChildAt(i).layoutParams.height = expectedHeight
+ }
+ // 请求重新布局
+ recyclerSuccessView.requestLayout()
+ itemHeight = expectedHeight
+ }
+ }
+ }
+ recyclerRecordView.layoutManager = object : LinearLayoutManager(this@InvitationActivity) {
+ override fun onMeasure(
+ recycler: RecyclerView.Recycler, state: RecyclerView.State,
+ widthSpec: Int, heightSpec: Int
+ ) {
+ if (itemHeight > 0) {
+ // 使用实际测量的高度
+ setMeasuredDimension(
+ View.resolveSize(widthSpec, width),
+ itemHeight
+ )
+ } else {
+ // 默认高度60dp
+ val defaultHeight = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, 60f,
+ resources.displayMetrics
+ ).toInt()
+ setMeasuredDimension(
+ View.resolveSize(widthSpec, width),
+ defaultHeight
+ )
+ }
+ }
+ }
+ }
+
+ private fun initSuccessAdapter() {
+ adapter = InvitationAdapter(this, data).apply {
+ registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
+ override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
+ // 数据插入时检查高度
+ recyclerSuccessView.post {
+ if (recyclerSuccessView.childCount > 0) {
+ itemHeight = recyclerSuccessView.getChildAt(0).height
+ }
+ }
+ }
+ })
+ }
+ recyclerSuccessView.adapter = adapter
+ }
+
+ private fun initRecorddapter() {
+ recordadapter = InvitationRecordAdapter(this, recorddata).apply {
+ registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
+ override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
+ // 数据插入时检查高度
+ recyclerRecordView.post {
+ if (recyclerRecordView.childCount > 0) {
+ itemHeight = recyclerRecordView.getChildAt(0).height
+ }
+ }
+ }
+ })
+ }
+ recyclerRecordView.adapter = recordadapter
}
private fun loadData() {
- val mockData = listOf(
- InvitationRecord("H****e", "获得了3天会员"),
- InvitationRecord("U****r", "获得了7天会员"),
- InvitationRecord("A****e", "获得了免广告特权"),
- InvitationRecord("B****d", "获得了3天会员"),
- InvitationRecord("C****o", "获得了7天会员")
+ data.clear()
+ data.addAll(
+ listOf(
+ InvitationRecord("H****e", "获得了1天会员", "已注册"),
+ InvitationRecord("U****r", "获得了2天会员", "已注册"),
+ InvitationRecord("A****e", "获得了免广告特权", "已注册"),
+ InvitationRecord("B****e", "获得了3天会员", "已注册"),
+ InvitationRecord("C****o", "获得了4天会员", "已注册")
+ )
)
- adapter.submitList(mockData)
+ adapter.notifyDataSetChanged()
}
- private fun setupAutoScroll() {
- scrollRunnable = object : Runnable {
- override fun run() {
- if (currentPosition < adapter.itemCount - 1) {
- currentPosition++
- smoothScrollToPosition(currentPosition)
- } else {
- // 滚动到底部后回到顶部
- currentPosition = 0
- recyclerView.scrollToPosition(0)
+ private fun loadRecordData() {
+ recorddata.clear()
+ recorddata.addAll(
+ listOf(
+ InvitationRecord("M****e", "", "未注册"),
+ InvitationRecord("Q****r", "", "已注册"),
+ InvitationRecord("W****e", "", "未注册"),
+ InvitationRecord("E****e", "", "未注册"),
+ InvitationRecord("R****o", "", "已注册")
+ )
+ )
+ recordadapter.notifyDataSetChanged()
+ }
+
+ // 分享资源图片到微信
+ private fun shareImageToWechat() {
+ try {
+ // 获取资源图片的URI
+ val imageUri = Uri.parse("android.resource://${packageName}/${R.drawable.location}")
+
+ val intent = Intent().apply {
+ action = Intent.ACTION_SEND
+ type = "image/*"
+ putExtra(Intent.EXTRA_STREAM, imageUri)
+ flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ setPackage("com.tencent.mm") // 指定微信包名
+ }
+
+ // 创建选择器,即使微信不可用也能选择其他应用
+ val chooserIntent = Intent.createChooser(intent, "分享邀请图片")
+
+ // 检查是否有应用能处理这个Intent
+ if (intent.resolveActivity(packageManager) != null) {
+ startActivity(chooserIntent)
+ } else {
+ Toast.makeText(this, "未找到可分享的应用", Toast.LENGTH_SHORT).show()
+ }
+ } catch (e: Exception) {
+ Toast.makeText(this, "分享失败: ${e.message}", Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ private fun formatInvitationCode(code: String): String {
+ return if (code.length > 2) {
+ code.chunked(2).joinToString(" ")
+ } else {
+ code
+ }
+ }
+
+ private val scrollRunnable = object : Runnable {
+ override fun run() {
+ if (data.isEmpty() || itemHeight <= 0) {
+ handler.postDelayed(this, scrollInterval)
+ return
+ }
+
+ // 使用取模运算确保位置在有效范围内
+ currentScrollPosition++
+ currentRecordScrollPosition++
+
+ // 创建自定义平滑滚动器
+ val smoothScroller = object : LinearSmoothScroller(this@InvitationActivity) {
+ override fun getVerticalSnapPreference(): Int = SNAP_TO_START
+
+ override fun calculateDyToMakeVisible(view: View, snapPreference: Int): Int {
+ // 计算需要滚动的距离,确保完整显示下一个item
+ val top = view.top
+ val height = view.height
+ return when {
+ snapPreference == SNAP_TO_START -> -top
+ snapPreference == SNAP_TO_END -> -(top - (recyclerSuccessView.height - height))
+ else -> -(top - (recyclerSuccessView.height / 2 - height / 2))
+ }
}
- handler.postDelayed(this, 2000)
+
+ override fun calculateTimeForScrolling(dx: Int): Int {
+ // 根据滚动距离动态计算时间,保持匀速
+ return maxOf((500f * abs(dx) / itemHeight).toInt(), 200)
+ }
+ }.apply {
+ targetPosition = currentScrollPosition
}
+
+ val smoothRecordScroller = object : LinearSmoothScroller(this@InvitationActivity) {
+ override fun getVerticalSnapPreference(): Int = SNAP_TO_START
+
+ override fun calculateDyToMakeVisible(view: View, snapPreference: Int): Int {
+ // 计算需要滚动的距离,确保完整显示下一个item
+ val top = view.top
+ val height = view.height
+ return when {
+ snapPreference == SNAP_TO_START -> -top
+ snapPreference == SNAP_TO_END -> -(top - (recyclerRecordView.height - height))
+ else -> -(top - (recyclerRecordView.height / 2 - height / 2))
+ }
+ }
+
+ override fun calculateTimeForScrolling(dx: Int): Int {
+ // 根据滚动距离动态计算时间,保持匀速
+ return maxOf((500f * abs(dx) / itemHeight).toInt(), 200)
+ }
+ }.apply {
+ targetPosition = currentRecordScrollPosition
+ }
+
+ // 启动平滑滚动
+ recyclerSuccessView.layoutManager?.startSmoothScroll(smoothScroller)
+
+ recyclerRecordView.layoutManager?.startSmoothScroll(smoothRecordScroller)
+
+ // 更智能的边界检测
+ (recyclerSuccessView.layoutManager as? LinearLayoutManager)?.let { lm ->
+ val lastVisible = lm.findLastVisibleItemPosition()
+ val totalItems = adapter.itemCount
+
+ // 当接近"虚拟列表"末尾时,跳转到中间位置
+ if (lastVisible >= totalItems - 3) {
+ val jumpPosition = (totalItems / 2) * (Int.MAX_VALUE / totalItems)
+ currentScrollPosition = jumpPosition
+ recyclerSuccessView.scrollToPosition(jumpPosition)
+ }
+ }
+
+ (recyclerRecordView.layoutManager as? LinearLayoutManager)?.let { lm ->
+ val lastVisible = lm.findLastVisibleItemPosition()
+ val totalItems = recordadapter.itemCount
+
+ // 当接近"虚拟列表"末尾时,跳转到中间位置
+ if (lastVisible >= totalItems - 3) {
+ val jumpPosition = (totalItems / 2) * (Int.MAX_VALUE / totalItems)
+ currentRecordScrollPosition = jumpPosition
+ recyclerRecordView.scrollToPosition(jumpPosition)
+ }
+ }
+
+ handler.postDelayed(this, scrollInterval)
}
- startAutoScroll()
}
- private fun smoothScrollToPosition(position: Int) {
- val layoutManager = recyclerView.layoutManager as LinearLayoutManager
- val smoothScroller = object : LinearSmoothScroller(this) {
- override fun getVerticalSnapPreference(): Int = SNAP_TO_START
+ private fun pxToDp(px: Int, context: Context): Int {
+ return (px / (context.resources.displayMetrics.density)).toInt()
+ }
- override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {
- return 100f / displayMetrics.densityDpi // 控制滚动速度
- }
- }
- smoothScroller.targetPosition = position
- layoutManager.startSmoothScroll(smoothScroller)
+ private fun dpToPx(dp: Float): Int {
+ return (dp * resources.displayMetrics.density).toInt()
}
private fun startAutoScroll() {
- handler.postDelayed(scrollRunnable, 2000)
- }
-
- private fun stopAutoScroll() {
- handler.removeCallbacks(scrollRunnable)
+ handler.removeCallbacks(scrollRunnable) // 先移除之前的回调
+ handler.postDelayed(scrollRunnable, scrollInterval)
}
override fun onPause() {
+ handler.removeCallbacks(scrollRunnable)
super.onPause()
- stopAutoScroll()
}
override fun onResume() {
--
Gitblit v1.9.3