/** * Copyright 2016 JustWayward Team * <p/> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.justwayward.reader.view.readview; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.PointF; import android.view.MotionEvent; import android.view.View; import android.widget.Scroller; import com.justwayward.reader.base.Constant; import com.justwayward.reader.bean.BookMixAToc; import com.justwayward.reader.manager.SettingManager; import com.justwayward.reader.manager.ThemeManager; import com.justwayward.reader.utils.LogUtils; import com.justwayward.reader.utils.ScreenUtils; import com.justwayward.reader.utils.SharedPreferencesUtil; import com.justwayward.reader.utils.ToastUtils; import java.util.List; /** * @author yuyh. * @date 2016/10/18. */ public abstract class BaseReadView extends View { protected int mScreenWidth; protected int mScreenHeight; protected PointF mTouch = new PointF(); protected float actiondownX, actiondownY; protected float touch_down = 0; // 当前触摸点与按下时的点的差值 protected Bitmap mCurPageBitmap, mNextPageBitmap; protected Canvas mCurrentPageCanvas, mNextPageCanvas; protected PageFactory pagefactory = null; protected OnReadStateChangeListener listener; protected String bookId; public boolean isPrepared = false; Scroller mScroller; public BaseReadView(Context context, String bookId, List<BookMixAToc.mixToc.Chapters> chaptersList, OnReadStateChangeListener listener) { super(context); this.listener = listener; this.bookId = bookId; mScreenWidth = ScreenUtils.getScreenWidth(); mScreenHeight = ScreenUtils.getScreenHeight(); mCurPageBitmap = Bitmap.createBitmap(mScreenWidth, mScreenHeight, Bitmap.Config.ARGB_8888); mNextPageBitmap = Bitmap.createBitmap(mScreenWidth, mScreenHeight, Bitmap.Config.ARGB_8888); mCurrentPageCanvas = new Canvas(mCurPageBitmap); mNextPageCanvas = new Canvas(mNextPageBitmap); mScroller = new Scroller(getContext()); pagefactory = new PageFactory(getContext(), bookId, chaptersList); pagefactory.setOnReadStateChangeListener(listener); } public synchronized void init(int theme) { if (!isPrepared) { try { pagefactory.setBgBitmap(ThemeManager.getThemeDrawable(theme)); // 自动跳转到上次阅读位置 int pos[] = SettingManager.getInstance().getReadProgress(bookId); int ret = pagefactory.openBook(pos[0], new int[]{pos[1], pos[2]}); LogUtils.i("上次阅读位置:chapter=" + pos[0] + " startPos=" + pos[1] + " endPos=" + pos[2]); if (ret == 0) { listener.onLoadChapterFailure(pos[0]); return; } pagefactory.onDraw(mCurrentPageCanvas); postInvalidate(); } catch (Exception e) { } isPrepared = true; } } private int dx, dy; private long et = 0; private boolean cancel = false; private boolean center = false; @Override public boolean onTouchEvent(MotionEvent e) { switch (e.getAction()) { case MotionEvent.ACTION_DOWN: et = System.currentTimeMillis(); dx = (int) e.getX(); dy = (int) e.getY(); mTouch.x = dx; mTouch.y = dy; actiondownX = dx; actiondownY = dy; touch_down = 0; pagefactory.onDraw(mCurrentPageCanvas); if (actiondownX >= mScreenWidth / 3 && actiondownX <= mScreenWidth * 2 / 3 && actiondownY >= mScreenHeight / 3 && actiondownY <= mScreenHeight * 2 / 3) { center = true; } else { center = false; calcCornerXY(actiondownX, actiondownY); if (actiondownX < mScreenWidth / 2) {// 从左翻 BookStatus status = pagefactory.prePage(); if (status == BookStatus.NO_PRE_PAGE) { ToastUtils.showSingleToast("没有上一页啦"); return false; } else if (status == BookStatus.LOAD_SUCCESS) { abortAnimation(); pagefactory.onDraw(mNextPageCanvas); } else { return false; } } else if (actiondownX >= mScreenWidth / 2) {// 从右翻 BookStatus status = pagefactory.nextPage(); if (status == BookStatus.NO_NEXT_PAGE) { ToastUtils.showSingleToast("没有下一页啦"); return false; } else if (status == BookStatus.LOAD_SUCCESS) { abortAnimation(); pagefactory.onDraw(mNextPageCanvas); } else { return false; } } listener.onFlip(); setBitmaps(mCurPageBitmap, mNextPageBitmap); } break; case MotionEvent.ACTION_MOVE: if (center) break; int mx = (int) e.getX(); int my = (int) e.getY(); cancel = (actiondownX < mScreenWidth / 2 && mx < mTouch.x) || (actiondownX > mScreenWidth / 2 && mx > mTouch.x); mTouch.x = mx; mTouch.y = my; touch_down = mTouch.x - actiondownX; this.postInvalidate(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: long t = System.currentTimeMillis(); int ux = (int) e.getX(); int uy = (int) e.getY(); if (center) { // ACTION_DOWN的位置在中间,则不响应滑动事件 resetTouchPoint(); if (Math.abs(ux - actiondownX) < 5 && Math.abs(uy - actiondownY) < 5) { listener.onCenterClick(); return false; } break; } if ((Math.abs(ux - dx) < 10) && (Math.abs(uy - dy) < 10)) { if ((t - et < 1000)) { // 单击 if(this instanceof NoAimWidget) { ((NoAimWidget)this).startAnimation(0); }else{ startAnimation(); } } else { // 长按 pagefactory.cancelPage(); restoreAnimation(); } postInvalidate(); return true; } if (cancel) { pagefactory.cancelPage(); restoreAnimation(); postInvalidate(); } else { startAnimation(); postInvalidate(); } cancel = false; center = false; break; default: break; } return true; } @Override protected void onDraw(Canvas canvas) { calcPoints(); drawCurrentPageArea(canvas); drawNextPageAreaAndShadow(canvas); drawCurrentPageShadow(canvas); drawCurrentBackArea(canvas); } protected abstract void drawNextPageAreaAndShadow(Canvas canvas); protected abstract void drawCurrentPageShadow(Canvas canvas); protected abstract void drawCurrentBackArea(Canvas canvas); protected abstract void drawCurrentPageArea(Canvas canvas); protected abstract void calcPoints(); protected abstract void calcCornerXY(float x, float y); /** * 开启翻页 */ protected abstract void startAnimation(); /** * 停止翻页动画(滑到一半调用停止的话 翻页效果会卡住 可调用#{restoreAnimation} 还原效果) */ protected abstract void abortAnimation(); /** * 还原翻页 */ protected abstract void restoreAnimation(); protected abstract void setBitmaps(Bitmap mCurPageBitmap, Bitmap mNextPageBitmap); public abstract void setTheme(int theme); /** * 复位触摸点位 */ protected void resetTouchPoint() { mTouch.x = 0.1f; mTouch.y = 0.1f; touch_down = 0; calcCornerXY(mTouch.x, mTouch.y); } public void jumpToChapter(int chapter) { resetTouchPoint(); pagefactory.openBook(chapter, new int[]{0, 0}); pagefactory.onDraw(mCurrentPageCanvas); pagefactory.onDraw(mNextPageCanvas); postInvalidate(); } public void nextPage() { BookStatus status = pagefactory.nextPage(); if (status == BookStatus.NO_NEXT_PAGE) { ToastUtils.showSingleToast("没有下一页啦"); return; } else if (status == BookStatus.LOAD_SUCCESS) { if (isPrepared) { pagefactory.onDraw(mCurrentPageCanvas); pagefactory.onDraw(mNextPageCanvas); postInvalidate(); } } else { return; } } public void prePage() { BookStatus status = pagefactory.prePage(); if (status == BookStatus.NO_PRE_PAGE) { ToastUtils.showSingleToast("没有上一页啦"); return; } else if (status == BookStatus.LOAD_SUCCESS) { if (isPrepared) { pagefactory.onDraw(mCurrentPageCanvas); pagefactory.onDraw(mNextPageCanvas); postInvalidate(); } } else { return; } } public synchronized void setFontSize(final int fontSizePx) { resetTouchPoint(); pagefactory.setTextFont(fontSizePx); if (isPrepared) { pagefactory.onDraw(mCurrentPageCanvas); pagefactory.onDraw(mNextPageCanvas); //SettingManager.getInstance().saveFontSize(bookId, fontSizePx); SettingManager.getInstance().saveFontSize(fontSizePx); postInvalidate(); } } public synchronized void setTextColor(int textColor, int titleColor) { resetTouchPoint(); pagefactory.setTextColor(textColor, titleColor); if (isPrepared) { pagefactory.onDraw(mCurrentPageCanvas); pagefactory.onDraw(mNextPageCanvas); postInvalidate(); } } public void setBattery(int battery) { pagefactory.setBattery(battery); if (isPrepared) { pagefactory.onDraw(mCurrentPageCanvas); postInvalidate(); } } public void setTime(String time) { pagefactory.setTime(time); } public void setPosition(int[] pos) { int ret = pagefactory.openBook(pos[0], new int[]{pos[1], pos[2]}); if (ret == 0) { listener.onLoadChapterFailure(pos[0]); return; } pagefactory.onDraw(mCurrentPageCanvas); postInvalidate(); } public int[] getReadPos() { return pagefactory.getPosition(); } public String getHeadLine() { return pagefactory.getHeadLineStr().replaceAll("@", ""); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (pagefactory != null) { pagefactory.recycle(); } if (mCurPageBitmap != null && !mCurPageBitmap.isRecycled()) { mCurPageBitmap.recycle(); mCurPageBitmap = null; LogUtils.d("mCurPageBitmap recycle"); } if (mNextPageBitmap != null && !mNextPageBitmap.isRecycled()) { mNextPageBitmap.recycle(); mNextPageBitmap = null; LogUtils.d("mNextPageBitmap recycle"); } } }