界面: 歌曲列表行高自适应铺满屏幕(消除投影/高分屏底部空白)
- SongListAdapter: 新增 rowHeightPx/fitRowHeight/rowsPerPage, 分页列表(2列目录5行/排行6行) 按 ListView 实际可视高度均分行高(clamp 52-160dp), 内容垂直居中, 背景整行铺满 - 滚动型列表(已点/下载/已唱)保持自然行高 - MainActivity.renderSongList: 布局完成后 post fitRowHeight
This commit is contained in:
@@ -9091,6 +9091,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
val pageOffset = if (mode == "rank") browsePage * browsePageSize() else 0
|
val pageOffset = if (mode == "rank") browsePage * browsePageSize() else 0
|
||||||
val existing = modernSongAdapter?.takeIf { it.matches(mode, pageOffset) && list.adapter === it }
|
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(
|
val listAdapter = existing ?: SongListAdapter(
|
||||||
this,
|
this,
|
||||||
visibleSongs,
|
visibleSongs,
|
||||||
@@ -9109,11 +9116,17 @@ class MainActivity : AppCompatActivity() {
|
|||||||
},
|
},
|
||||||
onPauseResume = { song -> toggleDownloadPause(song) },
|
onPauseResume = { song -> toggleDownloadPause(song) },
|
||||||
),
|
),
|
||||||
|
initialRowHeightPx = 0,
|
||||||
|
rowsPerPage = rowsPerPage,
|
||||||
).also {
|
).also {
|
||||||
modernSongAdapter = it
|
modernSongAdapter = it
|
||||||
list.adapter = it
|
list.adapter = it
|
||||||
}
|
}
|
||||||
if (existing != null) listAdapter.notifyDataSetChanged()
|
if (existing != null) listAdapter.notifyDataSetChanged()
|
||||||
|
// 布局完成后按实际可视高度拉满各行, 消除投影/高分屏底部空白。
|
||||||
|
if (rowsPerPage > 0) {
|
||||||
|
list.post { if (list.adapter === listAdapter) listAdapter.fitRowHeight(list.height) }
|
||||||
|
}
|
||||||
|
|
||||||
val targetPosition = focusedMarker?.let(listAdapter::adapterPositionFor)
|
val targetPosition = focusedMarker?.let(listAdapter::adapterPositionFor)
|
||||||
?: oldSelectedPosition.takeIf { it >= 0 }
|
?: oldSelectedPosition.takeIf { it >= 0 }
|
||||||
|
|||||||
@@ -42,11 +42,32 @@ class SongListAdapter(
|
|||||||
private val nextPageFocusId: Int,
|
private val nextPageFocusId: Int,
|
||||||
private val stateFor: (Song) -> SongRowState,
|
private val stateFor: (Song) -> SongRowState,
|
||||||
private val callbacks: SongListCallbacks,
|
private val callbacks: SongListCallbacks,
|
||||||
|
private val initialRowHeightPx: Int = 0,
|
||||||
|
private val rowsPerPage: Int = 0,
|
||||||
) : BaseAdapter() {
|
) : BaseAdapter() {
|
||||||
private val density = context.resources.displayMetrics.density
|
private val density = context.resources.displayMetrics.density
|
||||||
private val columns = if (mode in SINGLE_COLUMN_MODES) 1 else 2
|
private val columns = if (mode in SINGLE_COLUMN_MODES) 1 else 2
|
||||||
private val cardIds = HashMap<String, Int>()
|
private val cardIds = HashMap<String, Int>()
|
||||||
|
|
||||||
|
/** 当前行高(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() }
|
private fun cardId(index: Int): Int = cardIds.getOrPut(songKey(songs[index])) { View.generateViewId() }
|
||||||
|
|
||||||
override fun getCount(): Int = ceil(songs.size / columns.toDouble()).toInt()
|
override fun getCount(): Int = ceil(songs.size / columns.toDouble()).toInt()
|
||||||
@@ -64,28 +85,35 @@ class SongListAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
if (columns == 1) {
|
val view = if (columns == 1) {
|
||||||
return createSingleRow(songs[position], position).apply {
|
createSingleRow(songs[position], position).apply {
|
||||||
if (position == count - 1) nextFocusDownId = previousPageFocusId
|
if (position == count - 1) nextFocusDownId = previousPageFocusId
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
return LinearLayout(context).apply {
|
LinearLayout(context).apply {
|
||||||
orientation = LinearLayout.HORIZONTAL
|
orientation = LinearLayout.HORIZONTAL
|
||||||
gravity = Gravity.CENTER_VERTICAL
|
gravity = Gravity.CENTER_VERTICAL
|
||||||
val cells = mutableListOf<View>()
|
|
||||||
repeat(2) { column ->
|
repeat(2) { column ->
|
||||||
val index = position * 2 + column
|
val index = position * 2 + column
|
||||||
val cell = songs.getOrNull(index)?.let {
|
val cell = songs.getOrNull(index)?.let {
|
||||||
createCatalogCell(it, index, column, position == count - 1)
|
createCatalogCell(it, index, column, position == count - 1)
|
||||||
} ?: View(context)
|
} ?: View(context)
|
||||||
cells += cell
|
|
||||||
addView(
|
addView(
|
||||||
cell,
|
cell,
|
||||||
LinearLayout.LayoutParams(0, dp(60), 1f),
|
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) {
|
private fun createSingleRow(song: Song, index: Int): View = when (mode) {
|
||||||
"rank" -> createRankRow(song, index)
|
"rank" -> createRankRow(song, index)
|
||||||
|
|||||||
Reference in New Issue
Block a user