update pageview

pull/32/head
Administrator 5 years ago
parent e5f27fbe97
commit 17a90ab7eb
  1. 10
      app/src/main/java/io/legado/app/base/BaseViewModel.kt
  2. 3
      app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt
  3. 6
      app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt
  4. 21
      app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt
  5. 10
      app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt
  6. 8
      app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt
  7. 73
      app/src/main/java/io/legado/app/ui/widget/page/PageView.kt
  8. 3
      app/src/main/java/io/legado/app/ui/widget/page/ScrollContentView.kt
  9. 32
      app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt
  10. 14
      app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt
  11. 48
      app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt
  12. 22
      app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt
  13. 1
      app/src/main/res/layout/view_book_page.xml

@ -12,7 +12,7 @@ import org.jetbrains.anko.toast
open class BaseViewModel(application: Application) : AndroidViewModel(application), CoroutineScope by MainScope(), open class BaseViewModel(application: Application) : AndroidViewModel(application), CoroutineScope by MainScope(),
AnkoLogger { AnkoLogger {
val context: Context = this.getApplication<App>() val context: Context by lazy { this.getApplication<App>() }
fun <T> execute(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> T): Coroutine<T> { fun <T> execute(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> T): Coroutine<T> {
return Coroutine.async(scope) { block() } return Coroutine.async(scope) { block() }
@ -29,25 +29,25 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio
open fun toast(message: Int) { open fun toast(message: Int) {
launch { launch {
getApplication<App>().toast(message) context.toast(message)
} }
} }
open fun toast(message: CharSequence) { open fun toast(message: CharSequence) {
launch { launch {
getApplication<App>().toast(message) context.toast(message)
} }
} }
open fun longToast(message: Int) { open fun longToast(message: Int) {
launch { launch {
getApplication<App>().toast(message) context.toast(message)
} }
} }
open fun longToast(message: CharSequence) { open fun longToast(message: CharSequence) {
launch { launch {
getApplication<App>().toast(message) context.toast(message)
} }
} }
} }

@ -51,7 +51,6 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_rea
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
initAnimation() initAnimation()
initView() initView()
page_view.callBack = this
viewModel.callBack = this viewModel.callBack = this
viewModel.chapterMaxIndex.observe(this, Observer { bookLoadFinish() }) viewModel.chapterMaxIndex.observe(this, Observer { bookLoadFinish() })
viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) viewModel.bookData.observe(this, Observer { title_bar.title = it.name })
@ -242,7 +241,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_rea
} }
} }
override fun loadContentFinish(bookChapter: BookChapter, content: String) { override fun onLoadFinish(bookChapter: BookChapter, content: String) {
launch { launch {
when (bookChapter.index) { when (bookChapter.index) {
viewModel.durChapterIndex -> { viewModel.durChapterIndex -> {

@ -80,7 +80,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
execute { execute {
App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter ->
BookHelp.getContent(book, chapter)?.let { BookHelp.getContent(book, chapter)?.let {
callBack?.loadContentFinish(chapter, it) callBack?.onLoadFinish(chapter, it)
synchronized(loadingLock) { synchronized(loadingLock) {
loadingChapters.remove(index) loadingChapters.remove(index)
} }
@ -118,7 +118,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
?.onSuccess(IO) { content -> ?.onSuccess(IO) { content ->
content?.let { content?.let {
BookHelp.saveContent(book, chapter, it) BookHelp.saveContent(book, chapter, it)
callBack?.loadContentFinish(chapter, it) callBack?.onLoadFinish(chapter, it)
synchronized(loadingLock) { synchronized(loadingLock) {
loadingChapters.remove(chapter.index) loadingChapters.remove(chapter.index)
} }
@ -140,6 +140,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
} }
interface CallBack { interface CallBack {
fun loadContentFinish(bookChapter: BookChapter, content: String) fun onLoadFinish(bookChapter: BookChapter, content: String)
} }
} }

@ -1,18 +1,21 @@
package io.legado.app.ui.widget.page package io.legado.app.ui.widget.page
import android.content.Context import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.util.AttributeSet import android.util.AttributeSet
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.appcompat.widget.AppCompatImageView
import io.legado.app.R import io.legado.app.R
import io.legado.app.help.ImageLoader
import io.legado.app.utils.dp import io.legado.app.utils.dp
import kotlinx.android.synthetic.main.view_book_page.view.* import kotlinx.android.synthetic.main.view_book_page.view.*
import org.jetbrains.anko.horizontalPadding import org.jetbrains.anko.horizontalPadding
import org.jetbrains.anko.matchParent
class ContentView : FrameLayout { class ContentView : FrameLayout {
private val bgImage: AppCompatImageView = AppCompatImageView(context)
constructor(context: Context) : super(context) constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
@ -20,22 +23,16 @@ class ContentView : FrameLayout {
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
init { init {
addView(bgImage, LayoutParams(matchParent, matchParent))
inflate(context, R.layout.view_book_page, this) inflate(context, R.layout.view_book_page, this)
setBackgroundColor(Color.WHITE)
upStyle() upStyle()
} }
fun upStyle() { fun upStyle() {
page_panel.horizontalPadding = 16.dp page_panel.horizontalPadding = 16.dp
ImageLoader.load(context, R.drawable.bg1)
} .centerCrop()
.setAsDrawable(bgImage)
fun setBg(bg: Drawable?) {
page_panel.background = bg
}
fun setBgColor(color: Int) {
page_panel.setBackgroundColor(color)
} }
fun upTime() { fun upTime() {

@ -1,11 +1,17 @@
package io.legado.app.ui.widget.page package io.legado.app.ui.widget.page
import io.legado.app.data.entities.BookChapter
interface DataSource { interface DataSource {
fun isPrepared(): Boolean
fun getChapterPosition() fun getChapterPosition()
fun getChapter(position: Int): TextChapter? fun getChapter(position: Int): TextChapter?
fun getCurrentChapter(): TextChapter?
fun getNextChapter(): TextChapter? fun getNextChapter(): TextChapter?
fun getPreviousChapter(): TextChapter? fun getPreviousChapter(): TextChapter?
@ -13,4 +19,8 @@ interface DataSource {
fun hasNextChapter(): Boolean fun hasNextChapter(): Boolean
fun hasPrevChapter(): Boolean fun hasPrevChapter(): Boolean
interface CallBack {
fun onLoadFinish(bookChapter: BookChapter, content: String)
}
} }

@ -4,10 +4,18 @@ abstract class PageFactory<DATA>(protected val dataSource: DataSource) {
abstract fun pageAt(index: Int): DATA? abstract fun pageAt(index: Int): DATA?
abstract fun moveToFirst()
abstract fun moveToNext():Boolean
abstract fun moveToPrevious(): Boolean
abstract fun nextPage(): DATA? abstract fun nextPage(): DATA?
abstract fun previousPage(): DATA? abstract fun previousPage(): DATA?
abstract fun currentPage(): DATA?
abstract fun hasNext(): Boolean abstract fun hasNext(): Boolean
abstract fun hasPrev(): Boolean abstract fun hasPrev(): Boolean

@ -12,8 +12,9 @@ import io.legado.app.ui.widget.page.delegate.PageDelegate
class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface { class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface {
var callBack: CallBack? = null var callback: CallBack? = null
private var pageDelegate: PageDelegate? = null private var pageDelegate: PageDelegate? = null
private var pageFactory: TextPageFactory? = null
var prevPage: ContentView? = null var prevPage: ContentView? = null
var curPage: ContentView? = null var curPage: ContentView? = null
@ -30,6 +31,40 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att
setWillNotDraw(false) setWillNotDraw(false)
pageDelegate = CoverPageDelegate(this) pageDelegate = CoverPageDelegate(this)
setPageFactory(TextPageFactory.create(object : DataSource {
override fun isPrepared(): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getChapterPosition() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getChapter(position: Int): TextChapter? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getCurrentChapter(): TextChapter? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getNextChapter(): TextChapter? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getPreviousChapter(): TextChapter? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun hasNextChapter(): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun hasPrevChapter(): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}))
} }
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
@ -41,9 +76,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att
override fun dispatchDraw(canvas: Canvas) { override fun dispatchDraw(canvas: Canvas) {
super.dispatchDraw(canvas) super.dispatchDraw(canvas)
// bringChildToFront(prevPage) pageDelegate?.onDraw(canvas)
pageDelegate?.onPerform(canvas)
} }
override fun computeScroll() { override fun computeScroll() {
@ -56,7 +89,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att
} }
fun chapterLoadFinish(chapterOnDur: Int = 0) { fun chapterLoadFinish(chapterOnDur: Int = 0) {
callBack?.let { cb -> callback?.let { cb ->
when (chapterOnDur) { when (chapterOnDur) {
0 -> { 0 -> {
cb.textChapter()?.let { cb.textChapter()?.let {
@ -89,8 +122,36 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att
} }
} }
fun setPageFactory(factory: PageFactory<*>) { fun fillPage(direction: PageDelegate.Direction) {
pageFactory?.let {
when (direction) {
PageDelegate.Direction.PREV -> {
it.moveToPrevious()
}
PageDelegate.Direction.NEXT -> {
it.moveToNext()
}
else -> {
}
}
prevPage?.setContent(it.previousPage()?.text)
curPage?.setContent(it.currentPage()?.text)
nextPage?.setContent(it.nextPage()?.text)
}
}
fun setPageFactory(factory: TextPageFactory) {
this.pageFactory = factory
//可做成异步回调
pageFactory?.let {
prevPage?.setContent(it.previousPage()?.text)
curPage?.setContent(it.currentPage()?.text)
nextPage?.setContent(it.nextPage()?.text)
}
} }
override fun hasNext(): Boolean { override fun hasNext(): Boolean {

@ -0,0 +1,3 @@
package io.legado.app.ui.widget.page
class ScrollContentView

@ -22,12 +22,36 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory<
TODO("todo...") TODO("todo...")
} }
override fun nextPage(): TextPage { override fun moveToFirst() {
return TextPage(index.plus(1), "index:$index") index = 0
} }
override fun previousPage(): TextPage { override fun moveToNext(): Boolean {
return TextPage(index.minus(1), "index:$index") return if(hasNext()){
index = index.plus(1)
true
}else
false
}
override fun moveToPrevious(): Boolean {
return if(hasPrev()){
index = index.minus(1)
true
}else
false
}
override fun currentPage(): TextPage? {
return TextPage(index, "index:$index")
}
override fun nextPage(): TextPage? {
return TextPage(index + 1, "index:${index + 1}")
}
override fun previousPage(): TextPage? {
return TextPage(index - 1, "index:${index - 1}")
} }

@ -24,7 +24,7 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) {
shadowDrawableL.gradientType = GradientDrawable.LINEAR_GRADIENT shadowDrawableL.gradientType = GradientDrawable.LINEAR_GRADIENT
} }
override fun onStart() { override fun onScrollStart() {
val distanceX: Float val distanceX: Float
when (direction) { when (direction) {
Direction.NEXT -> if (isCancel) { Direction.NEXT -> if (isCancel) {
@ -47,10 +47,18 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) {
start() start()
} }
override fun onPerform(canvas: Canvas) { override fun onScrollStop() {
if (!isCancel) {
pageView.fillPage(direction)
}
}
override fun onDraw(canvas: Canvas) {
val offsetX = touchX - startX val offsetX = touchX - startX
if(offsetX == 0.toFloat()) return if ((direction == Direction.NEXT && offsetX > 0)
|| (direction == Direction.PREV && offsetX < 0)
) return
val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth
bitmap?.let { bitmap?.let {

@ -4,15 +4,14 @@ import android.graphics.Bitmap
import android.graphics.Canvas import android.graphics.Canvas
import android.view.GestureDetector import android.view.GestureDetector
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View
import android.widget.Scroller import android.widget.Scroller
import androidx.interpolator.view.animation.FastOutLinearInInterpolator import androidx.interpolator.view.animation.FastOutLinearInInterpolator
import io.legado.app.ui.widget.page.ContentView
import io.legado.app.ui.widget.page.PageView import io.legado.app.ui.widget.page.PageView
import io.legado.app.utils.screenshot import io.legado.app.utils.screenshot
import kotlinx.android.synthetic.main.view_book_page.view.*
import kotlin.math.abs import kotlin.math.abs
abstract class PageDelegate(private val pageView: PageView) { abstract class PageDelegate(protected val pageView: PageView) {
//起始点 //起始点
protected var startX: Float = 0.toFloat() protected var startX: Float = 0.toFloat()
@ -21,8 +20,14 @@ abstract class PageDelegate(private val pageView: PageView) {
protected var touchX: Float = 0.toFloat() protected var touchX: Float = 0.toFloat()
protected var touchY: Float = 0.toFloat() protected var touchY: Float = 0.toFloat()
protected val view: View protected val nextPage: ContentView?
get() = pageView.page_panel get() = pageView.nextPage
protected val curPage: ContentView?
get() = pageView.curPage
protected val prevPage: ContentView?
get() = pageView.prevPage
protected var bitmap: Bitmap? = null protected var bitmap: Bitmap? = null
@ -58,6 +63,8 @@ abstract class PageDelegate(private val pageView: PageView) {
if (invalidate) { if (invalidate) {
invalidate() invalidate()
} }
onScroll()
} }
fun setViewSize(width: Int, height: Int) { fun setViewSize(width: Int, height: Int) {
@ -89,6 +96,7 @@ abstract class PageDelegate(private val pageView: PageView) {
} else if (isStarted) { } else if (isStarted) {
setTouchPoint(scroller.finalX.toFloat(), scroller.finalY.toFloat(), false) setTouchPoint(scroller.finalX.toFloat(), scroller.finalY.toFloat(), false)
stop() stop()
onScrollStop()
} }
} }
@ -126,14 +134,16 @@ abstract class PageDelegate(private val pageView: PageView) {
return return
} }
} }
onStart() onScrollStart()
} }
fun onTouch(event: MotionEvent): Boolean { fun onTouch(event: MotionEvent): Boolean {
if (isStarted) return false
if (isMoved && event.action == MotionEvent.ACTION_UP) { if (isMoved && event.action == MotionEvent.ACTION_UP) {
// 开启翻页效果 // 开启翻页效果
if (!noNext) { if (!noNext) {
onStart() onScrollStart()
} }
return true return true
} }
@ -145,9 +155,15 @@ abstract class PageDelegate(private val pageView: PageView) {
return duration.toInt() return duration.toInt()
} }
abstract fun onStart() abstract fun onScrollStart()//scroller start
abstract fun onPerform(canvas: Canvas) abstract fun onDraw(canvas: Canvas)//绘制
abstract fun onScrollStop()//scroller finish
open fun onScroll() {//移动contentView, slidePage
}
enum class Direction { enum class Direction {
NONE, PREV, NEXT NONE, PREV, NEXT
@ -156,7 +172,7 @@ abstract class PageDelegate(private val pageView: PageView) {
private inner class GestureListener : GestureDetector.OnGestureListener { private inner class GestureListener : GestureDetector.OnGestureListener {
override fun onDown(e: MotionEvent): Boolean { override fun onDown(e: MotionEvent): Boolean {
abort() // abort()
//是否移动 //是否移动
isMoved = false isMoved = false
//是否存在下一章 //是否存在下一章
@ -185,21 +201,24 @@ abstract class PageDelegate(private val pageView: PageView) {
if (!hasNext) { if (!hasNext) {
return true return true
} }
//下一页截图
bitmap = nextPage?.screenshot()
} else { } else {
val hasPrev = pageView.hasPrev() val hasPrev = pageView.hasPrev()
if (!hasPrev) { if (!hasPrev) {
return true return true
} }
//上一页截图
bitmap = prevPage?.screenshot()
} }
setTouchPoint(x, y) setTouchPoint(x, y)
onScrollStart()
return true return true
} }
override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
if (!isMoved && abs(distanceX) > abs(distanceY)) { if (!isMoved && abs(distanceX) > abs(distanceY)) {
//上一页或下一页截图,还未处理
if (distanceX < 0) { if (distanceX < 0) {
bitmap = pageView.prevPage?.screenshot()
//上一页的参数配置 //上一页的参数配置
direction = Direction.PREV direction = Direction.PREV
//判断是否上一页存在 //判断是否上一页存在
@ -209,8 +228,9 @@ abstract class PageDelegate(private val pageView: PageView) {
noNext = true noNext = true
return true return true
} }
//上一页截图
bitmap = prevPage?.screenshot()
} else { } else {
bitmap = pageView.nextPage?.screenshot()
//进行下一页的配置 //进行下一页的配置
direction = Direction.NEXT direction = Direction.NEXT
//判断是否下一页存在 //判断是否下一页存在
@ -220,6 +240,8 @@ abstract class PageDelegate(private val pageView: PageView) {
noNext = true noNext = true
return true return true
} }
//下一页截图
bitmap = nextPage?.screenshot()
} }
isMoved = true isMoved = true
} }

@ -0,0 +1,22 @@
package io.legado.app.ui.widget.page.delegate
import android.graphics.Canvas
import io.legado.app.ui.widget.page.PageView
class SlidePageDelegate(pageView: PageView) : PageDelegate(pageView) {
override fun onScrollStart() {
}
override fun onDraw(canvas: Canvas) {
}
override fun onScroll() {
}
override fun onScrollStop() {
}
}

@ -4,7 +4,6 @@
android:id="@+id/page_panel" android:id="@+id/page_panel"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/background"
android:orientation="vertical" android:orientation="vertical"
app:divider="@drawable/ic_divider" app:divider="@drawable/ic_divider"
app:showDividers="middle"> app:showDividers="middle">

Loading…
Cancel
Save