* 升级RecyclerView适配自适应刷新率

* 减小菜单点击区域

* ...

* 修复显示章节位置问题,修复顶部间距问题

* 显示漫画名称

* ...

* ...

* 漫画缩放移植到右上角
增加预加载数量设置
增加单页滚动
This commit is contained in:
lhjgege
2025-02-18 17:34:26 +08:00
committed by GitHub
parent 2f6b77d45c
commit 76d2f435ed
16 changed files with 170 additions and 30 deletions

View File

@@ -95,6 +95,8 @@ object PreferKey {
const val bitmapCacheSize = "bitmapCacheSize"
const val imageRetainNum = "imageRetainNum"
const val preDownloadNum = "preDownloadNum"
const val preMangaDownloadNum = "preMangaDownloadNum"
const val singlePageScrolling="singlePageScrolling"
const val autoRefresh = "auto_refresh"
const val defaultToRead = "defaultToRead"
const val exportCharset = "exportCharset"

View File

@@ -610,7 +610,24 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
get() = appCtx.getPrefBoolean(PreferKey.showMangaUi, true)
//禁用漫画缩放
val disableMangaScaling: Boolean
var disableMangaScaling: Boolean
get() = appCtx.getPrefBoolean(PreferKey.disableMangaScaling, true)
set(value) {
appCtx.putPrefBoolean(PreferKey.disableMangaScaling, value)
}
//漫画预加载数量
var preMangaDownloadNum
get() = appCtx.getPrefInt(PreferKey.preMangaDownloadNum, 10)
set(value) {
appCtx.putPrefInt(PreferKey.preMangaDownloadNum, value)
}
//单页滚动
var singlePageScrolling
get() = appCtx.getPrefBoolean(PreferKey.singlePageScrolling, false)
set(value) {
appCtx.putPrefBoolean(PreferKey.singlePageScrolling, value)
}
}

View File

@@ -1,5 +1,6 @@
package io.legado.app.ui.book.manga
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.os.Looper
@@ -14,6 +15,7 @@ import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.PagerSnapHelper
import com.bumptech.glide.Glide
import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader
import com.bumptech.glide.request.target.Target.SIZE_ORIGINAL
@@ -42,6 +44,7 @@ import io.legado.app.ui.book.manga.rv.MangaAdapter
import io.legado.app.ui.book.read.MangaMenu
import io.legado.app.ui.book.read.ReadBookActivity.Companion.RESULT_DELETED
import io.legado.app.ui.book.toc.TocActivityResult
import io.legado.app.ui.widget.number.NumberPickerDialog
import io.legado.app.ui.widget.recycler.LoadMoreView
import io.legado.app.utils.NetworkUtils
import io.legado.app.utils.StartActivityContract
@@ -64,17 +67,29 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
private val mAdapter: MangaAdapter by lazy {
MangaAdapter(this@ReadMangaActivity)
}
private val mPreDownloadNum by lazy {
AppConfig.preMangaDownloadNum
}
private val mSinglePageScroller by lazy {
AppConfig.singlePageScrolling
}
private val mDisableMangaScaling by lazy {
AppConfig.disableMangaScaling
}
private val mSizeProvider by lazy {
FixedPreloadSizeProvider<Any>(
this@ReadMangaActivity.resources.displayMetrics.widthPixels,
SIZE_ORIGINAL
this@ReadMangaActivity.resources.displayMetrics.widthPixels, SIZE_ORIGINAL
)
}
private val mRecyclerViewPreloader by lazy {
RecyclerViewPreloader(Glide.with(this), mAdapter, mSizeProvider, 10)
private val mPagerSnapHelper: PagerSnapHelper by lazy {
PagerSnapHelper()
}
private var mRecyclerViewPreloader: RecyclerViewPreloader<Any>? = null
private val networkChangedListener by lazy {
NetworkChangedListener(this)
}
@@ -95,13 +110,12 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
}
//打开目录返回选择章节返回结果
private val tocActivity =
registerForActivityResult(TocActivityResult()) {
it?.let {
binding.flLoading.isVisible = true
viewModel.openChapter(it.first, it.second)
}
private val tocActivity = registerForActivityResult(TocActivityResult()) {
it?.let {
binding.flLoading.isVisible = true
viewModel.openChapter(it.first, it.second)
}
}
private val bookInfoActivity =
registerForActivityResult(StartActivityContract(BookInfoActivity::class.java)) {
if (it.resultCode == RESULT_OK) {
@@ -122,6 +136,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
}
}
ReadManga.register(this)
disableMangaScaling(mDisableMangaScaling)
binding.mRecyclerMange.run {
adapter = mAdapter
itemAnimator = null
@@ -130,6 +145,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
mLayoutManager.initialPrefetchItemCount = 4
mLayoutManager.isItemPrefetchEnabled = true
setItemViewCacheSize(AppConfig.preDownloadNum)
singlePagerScroller(mSinglePageScroller)
setPreScrollListener { _, _, dy, position ->
if (dy > 0 && position + 2 > mAdapter.getCurrentList().size - 3) {
if (mAdapter.getCurrentList().last() is ReaderLoading) {
@@ -162,7 +178,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
}
}
addOnScrollListener(mRecyclerViewPreloader)
addRecyclerViewPreloader(mPreDownloadNum)
onToucheMiddle {
if (!binding.mangaMenu.isVisible) {
binding.mangaMenu.runMenuIn()
@@ -347,14 +363,17 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
}
@SuppressLint("StringFormatMatches")
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.book_manga, menu)
upMenu(menu)
return super.onCompatCreateOptionsMenu(menu)
}
/**
* 菜单
*/
@SuppressLint("StringFormatMatches")
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_change_source -> {
@@ -369,6 +388,27 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
tocActivity.launch(it.bookUrl)
}
}
R.id.menu_pre_manga_number -> {
NumberPickerDialog(this).setTitle(getString(R.string.pre_download))
.setMaxValue(9999).setMinValue(0).setValue(AppConfig.preMangaDownloadNum).show {
AppConfig.preMangaDownloadNum = it
item.setTitle(getString(R.string.pre_download_m, it))
addRecyclerViewPreloader(it)
}
}
R.id.menu_scroller_page -> {
item.isChecked = !item.isChecked
AppConfig.singlePageScrolling = item.isChecked
singlePagerScroller(item.isChecked)
}
R.id.menu_disable_manga_scaling -> {
item.isChecked = !item.isChecked
AppConfig.disableMangaScaling = item.isChecked
disableMangaScaling(item.isChecked)
}
}
return super.onCompatOptionsItemSelected(item)
}
@@ -405,4 +445,35 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
return super.dispatchKeyEvent(event)
}
private fun addRecyclerViewPreloader(maxPreload: Int) {
if (mRecyclerViewPreloader != null) {
binding.mRecyclerMange.removeOnScrollListener(mRecyclerViewPreloader!!)
}
mRecyclerViewPreloader = RecyclerViewPreloader(
Glide.with(this), mAdapter, mSizeProvider, maxPreload
)
binding.mRecyclerMange.addOnScrollListener(mRecyclerViewPreloader!!)
}
private fun singlePagerScroller(value: Boolean) {
if (value) {
mPagerSnapHelper.attachToRecyclerView(binding.mRecyclerMange)
} else {
mPagerSnapHelper.attachToRecyclerView(null)
}
}
@SuppressLint("StringFormatMatches")
private fun upMenu(menu: Menu) {
menu.findItem(R.id.menu_pre_manga_number)
.setTitle(getString(R.string.pre_download_m, mPreDownloadNum))
menu.findItem(R.id.menu_scroller_page).isChecked = mSinglePageScroller
menu.findItem(R.id.menu_disable_manga_scaling).isChecked = mDisableMangaScaling
}
private fun disableMangaScaling(disable: Boolean) {
binding.webtoonFrame.disableMangaScaling = disable
binding.mRecyclerMange.disableMangaScaling = disable
}
}

View File

@@ -7,7 +7,6 @@ import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.widget.FrameLayout
import io.legado.app.help.config.AppConfig
class WebtoonFrame : FrameLayout {
@@ -29,11 +28,13 @@ class WebtoonFrame : FrameLayout {
scaleDetector.isQuickScaleEnabled = value
}
var disableMangaScaling = false
private val recycler: WebtoonRecyclerView?
get() = getChildAt(0) as? WebtoonRecyclerView
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
if (!AppConfig.disableMangaScaling) {
if (!disableMangaScaling) {
scaleDetector.onTouchEvent(ev)
flingDetector.onTouchEvent(ev)
val recyclerRect = Rect()

View File

@@ -12,7 +12,6 @@ import android.view.animation.DecelerateInterpolator
import androidx.core.animation.doOnEnd
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.help.config.AppConfig
import io.legado.app.utils.findCenterViewPosition
import kotlin.math.abs
@@ -40,17 +39,23 @@ class WebtoonRecyclerView @JvmOverloads constructor(
private val listener = GestureListener()
private val detector = Detector()
private val mcRect = RectF()
private var mToucheMiddle: (() -> Unit)? = null
private val blRect = RectF()
private val brRect = RectF()
//起始点
private var startX: Float = 0f
private var startY: Float = 0f
var doubleTapZoom = true
var tapListener: ((MotionEvent) -> Unit)? = null
var longTapListener: ((MotionEvent) -> Boolean)? = null
var disableMangaScaling = false
private var mToucheMiddle: (() -> Unit)? = null
fun onToucheMiddle(init: () -> Unit) = apply { this.mToucheMiddle = init }
private var mNextPage: (() -> Unit)? = null
fun onNextPage(init: () -> Unit) = apply { this.mNextPage = init }
private var mPrevPage: (() -> Unit)? = null
fun onPrevPage(init: () -> Unit) = apply { this.mPrevPage = init }
override fun onMeasure(widthSpec: Int, heightSpec: Int) {
halfWidth = MeasureSpec.getSize(widthSpec) / 2
@@ -102,7 +107,9 @@ class WebtoonRecyclerView @JvmOverloads constructor(
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
mcRect.set(width * 0.33f, height * 0.33f, width * 0.66f, height * 0.66f)
mcRect.set(width * 0.33f, height * 0.33f, width * 0.66f, height * 0.46f)
blRect.set(0f, height * 0.66f, width * 0.33f, height.toFloat())
brRect.set(width * 0.66f, height * 0.66f, width.toFloat(), height.toFloat())
}
private fun getPositionX(positionX: Float): Float {
@@ -240,10 +247,23 @@ class WebtoonRecyclerView @JvmOverloads constructor(
inner class GestureListener : GestureDetectorWithLongTap.Listener() {
override fun onSingleTapConfirmed(ev: MotionEvent): Boolean {
if (mcRect.contains(startX, startY)) {
mToucheMiddle?.invoke()
} else {
tapListener?.invoke(ev)
when {
mcRect.contains(startX, startY) -> {
mToucheMiddle?.invoke()
}
blRect.contains(startX, startY) -> {
mPrevPage?.invoke()
}
brRect.contains(startX, startY) -> {
mNextPage?.invoke()
}
else -> {
tapListener?.invoke(ev)
}
}
return false
}
@@ -282,7 +302,6 @@ class WebtoonRecyclerView @JvmOverloads constructor(
private var isZoomDragging = false
var isDoubleTapping = false
var isQuickScaling = false
val disableMangaScaling = AppConfig.disableMangaScaling
override fun onTouchEvent(ev: MotionEvent): Boolean {
val action = ev.actionMasked
val actionIndex = ev.actionIndex

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<io.legado.app.ui.book.manga.rv.WebtoonFrame xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webtoonFrame"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"

View File

@@ -18,4 +18,23 @@
app:showAsAction="always" />
</group>
<item
android:id="@+id/menu_pre_manga_number"
android:title="@string/pre_download"
app:showAsAction="never" />
<item
android:id="@+id/menu_scroller_page"
android:checkable="true"
android:checked="false"
android:title="@string/single_page_scroller"
app:showAsAction="never" />
<item
android:id="@+id/menu_disable_manga_scaling"
android:checkable="true"
android:checked="false"
android:title="@string/disable_manga_scaling"
app:showAsAction="never" />
</menu>

View File

@@ -820,6 +820,8 @@
<string name="export_bookshelf">Exportar lista de libros</string>
<string name="import_bookshelf">Importar lista de libros</string>
<string name="pre_download">Descarga anterior</string>
<string name="pre_download_m">预下载%s页</string>
<string name="single_page_scroller">单页滚动</string>
<string name="pre_download_s">Descargue %s capítulos antes</string>
<string name="is_enabled">Está habilitado</string>
<string name="background_image">Imagen de fondo</string>

View File

@@ -823,6 +823,8 @@
<string name="export_bookshelf">Export the list of books</string>
<string name="import_bookshelf">Import the list of books</string>
<string name="pre_download">Download in advance</string>
<string name="pre_download_m">预下载%s页</string>
<string name="single_page_scroller">单页滚动</string>
<string name="pre_download_s">Download %s chapters in advance</string>
<string name="is_enabled">Is enabled</string>
<string name="background_image">Background image</string>

View File

@@ -821,6 +821,8 @@
<string name="export_bookshelf">Exportar a lista de livros</string>
<string name="import_bookshelf">Importar a lista de livros</string>
<string name="pre_download">Baixar antecipadamente</string>
<string name="pre_download_m">预下载%s页</string>
<string name="single_page_scroller">单页滚动</string>
<string name="pre_download_s">Baixar %s capítulos antecipadamente</string>
<string name="is_enabled">Está ativado</string>
<string name="background_image">Imagem de fundo</string>

View File

@@ -822,6 +822,8 @@ Còn </string>
<string name="export_bookshelf">Xuất bookshelf</string>
<string name="import_bookshelf">Nhập bookshelf</string>
<string name="pre_download">Tải xuống trước</string>
<string name="pre_download_m">预下载%s页</string>
<string name="single_page_scroller">单页滚动</string>
<string name="pre_download_s">Tải xuống trước %s chương</string>
<string name="is_enabled">Đã bật</string>
<string name="background_image">Ảnh nền</string>

View File

@@ -821,6 +821,8 @@
<string name="export_bookshelf">導出書單</string>
<string name="import_bookshelf">導入書單</string>
<string name="pre_download">預下載</string>
<string name="pre_download_m">預下載%s页</string>
<string name="single_page_scroller">单页滚动</string>
<string name="pre_download_s">預先下載%s章正文</string>
<string name="is_enabled">係咪啟用</string>
<string name="background_image">背景圖片</string>

View File

@@ -824,6 +824,8 @@
<string name="export_bookshelf">匯出書單</string>
<string name="import_bookshelf">匯入書單</string>
<string name="pre_download">預下載</string>
<string name="pre_download_m">预下载%s页</string>
<string name="single_page_scroller">单页滚动</string>
<string name="pre_download_s">預先下載%s章正文</string>
<string name="is_enabled">是否啟用</string>
<string name="background_image">背景圖片</string>

View File

@@ -827,6 +827,8 @@
<string name="export_bookshelf">导出书单</string>
<string name="import_bookshelf">导入书单</string>
<string name="pre_download">预下载</string>
<string name="single_page_scroller">单页滚动</string>
<string name="pre_download_m">预下载%s页</string>
<string name="pre_download_s">预先下载 %s 章正文</string>
<string name="is_enabled">是否启用</string>
<string name="background_image">背景图片</string>

View File

@@ -828,6 +828,8 @@
<string name="export_bookshelf">Export the list of books</string>
<string name="import_bookshelf">Import the list of books</string>
<string name="pre_download">Download in advance</string>
<string name="pre_download_m">Pre-download %s pages</string>
<string name="single_page_scroller">Single Page Scroller</string>
<string name="pre_download_s">Download %s chapters in advance</string>
<string name="is_enabled">Is enabled</string>
<string name="background_image">Background image</string>

View File

@@ -174,12 +174,6 @@
android:title="@string/show_mange_ui"
app:iconSpaceReserved="false" />
<io.legado.app.lib.prefs.SwitchPreference
android:defaultValue="true"
android:key="disableMangaScaling"
android:title="@string/disable_manga_scaling"
app:iconSpaceReserved="false" />
<io.legado.app.lib.prefs.Preference
android:key="webPort"
android:title="@string/web_port_title"