From 303e86b4755db5611fed65cc429d2435e0fdac14 Mon Sep 17 00:00:00 2001 From: zijunchiang Date: Sat, 5 Sep 2026 00:41:00 +0800 Subject: [PATCH] =?UTF-8?q?=E7=95=8C=E9=9D=A2:=20=E6=AD=8C=E6=9B=B2?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E8=A1=8C=E9=AB=98=E8=87=AA=E9=80=82=E5=BA=94?= =?UTF-8?q?=E9=93=BA=E6=BB=A1=E5=B1=8F=E5=B9=95(=E6=B6=88=E9=99=A4?= =?UTF-8?q?=E6=8A=95=E5=BD=B1/=E9=AB=98=E5=88=86=E5=B1=8F=E5=BA=95?= =?UTF-8?q?=E9=83=A8=E7=A9=BA=E7=99=BD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SongListAdapter: 新增 rowHeightPx/fitRowHeight/rowsPerPage, 分页列表(2列目录5行/排行6行) 按 ListView 实际可视高度均分行高(clamp 52-160dp), 内容垂直居中, 背景整行铺满 - 滚动型列表(已点/下载/已唱)保持自然行高 - MainActivity.renderSongList: 布局完成后 post fitRowHeight --- .../main/java/com/local/ktv/MainActivity.kt | 13 ++++ .../java/com/local/ktv/SongListAdapter.kt | 62 ++++++++++++++----- 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/local/ktv/MainActivity.kt b/app/src/main/java/com/local/ktv/MainActivity.kt index 01fc374..723a81e 100644 --- a/app/src/main/java/com/local/ktv/MainActivity.kt +++ b/app/src/main/java/com/local/ktv/MainActivity.kt @@ -9091,6 +9091,13 @@ class MainActivity : AppCompatActivity() { } val pageOffset = if (mode == "rank") browsePage * browsePageSize() else 0 val existing = modernSongAdapter?.takeIf { it.matches(mode, pageOffset) && list.adapter === it } + // 分页网格/排行列表: 行高自适应铺满屏幕(2列目录每页5行, 排行单列每页6行); + // 可滚动的队列/下载/已唱列表保持自然行高(rowsPerPage=0)。 + val rowsPerPage = when (mode) { + "catalog" -> 5 + "rank" -> 6 + else -> 0 + } val listAdapter = existing ?: SongListAdapter( this, visibleSongs, @@ -9109,11 +9116,17 @@ class MainActivity : AppCompatActivity() { }, onPauseResume = { song -> toggleDownloadPause(song) }, ), + initialRowHeightPx = 0, + rowsPerPage = rowsPerPage, ).also { modernSongAdapter = it list.adapter = it } if (existing != null) listAdapter.notifyDataSetChanged() + // 布局完成后按实际可视高度拉满各行, 消除投影/高分屏底部空白。 + if (rowsPerPage > 0) { + list.post { if (list.adapter === listAdapter) listAdapter.fitRowHeight(list.height) } + } val targetPosition = focusedMarker?.let(listAdapter::adapterPositionFor) ?: oldSelectedPosition.takeIf { it >= 0 } diff --git a/app/src/main/java/com/local/ktv/SongListAdapter.kt b/app/src/main/java/com/local/ktv/SongListAdapter.kt index 94700d5..9fc2ebd 100644 --- a/app/src/main/java/com/local/ktv/SongListAdapter.kt +++ b/app/src/main/java/com/local/ktv/SongListAdapter.kt @@ -42,11 +42,32 @@ class SongListAdapter( private val nextPageFocusId: Int, private val stateFor: (Song) -> SongRowState, private val callbacks: SongListCallbacks, + private val initialRowHeightPx: Int = 0, + private val rowsPerPage: Int = 0, ) : BaseAdapter() { private val density = context.resources.displayMetrics.density private val columns = if (mode in SINGLE_COLUMN_MODES) 1 else 2 private val cardIds = HashMap() + /** 当前行高(px)。0 = 保持内容自然高度(滚动列表用)。 */ + var rowHeightPx: Int = initialRowHeightPx + private set + + /** + * 让行高铺满可用高度: 把列表可视高度按每页行数均分(分页列表专用)。 + * 超出 min/max 范围时收敛, 避免过小/过大。滚动列表(rowsPerPage<=0)忽略。 + */ + fun fitRowHeight(availableHeightPx: Int) { + if (rowsPerPage <= 0 || availableHeightPx <= 0) return + val minPx = dp(52) + val maxPx = dp(160) + val fitted = (availableHeightPx / rowsPerPage).coerceIn(minPx, maxPx) + if (fitted != rowHeightPx) { + rowHeightPx = fitted + notifyDataSetChanged() + } + } + private fun cardId(index: Int): Int = cardIds.getOrPut(songKey(songs[index])) { View.generateViewId() } override fun getCount(): Int = ceil(songs.size / columns.toDouble()).toInt() @@ -64,27 +85,34 @@ class SongListAdapter( } override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { - if (columns == 1) { - return createSingleRow(songs[position], position).apply { + val view = if (columns == 1) { + createSingleRow(songs[position], position).apply { if (position == count - 1) nextFocusDownId = previousPageFocusId } - } - return LinearLayout(context).apply { - orientation = LinearLayout.HORIZONTAL - gravity = Gravity.CENTER_VERTICAL - val cells = mutableListOf() - repeat(2) { column -> - val index = position * 2 + column - val cell = songs.getOrNull(index)?.let { - createCatalogCell(it, index, column, position == count - 1) - } ?: View(context) - cells += cell - addView( - cell, - LinearLayout.LayoutParams(0, dp(60), 1f), - ) + } else { + LinearLayout(context).apply { + orientation = LinearLayout.HORIZONTAL + gravity = Gravity.CENTER_VERTICAL + repeat(2) { column -> + val index = position * 2 + column + val cell = songs.getOrNull(index)?.let { + createCatalogCell(it, index, column, position == count - 1) + } ?: View(context) + addView( + cell, + LinearLayout.LayoutParams(0, -1, 1f), + ) + } } } + // 分页列表: 让整行背景铺满均分行高; 滚动列表保持自然高度。 + if (rowHeightPx > 0) { + view.layoutParams = android.widget.AbsListView.LayoutParams( + android.widget.AbsListView.LayoutParams.MATCH_PARENT, + rowHeightPx, + ) + } + return view } private fun createSingleRow(song: Song, index: Int): View = when (mode) {