android酷炫翻页效果+图形分析
16lz
2022-03-31
android酷炫翻页效果+图形分析
package sf.hmg.turntest;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Region;
import android.graphics.drawable.GradientDrawable;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
public class PageWidget extends View{
private static final StringTAG = " hmg " ;
private int mWidth = 480 ;
private int mHeight = 800 ;
private int mCornerX = 0 ; // 拖拽点对应的页脚
private int mCornerY = 0 ;
private PathmPath0;
private PathmPath1;
BitmapmCurPageBitmap = null ; // 当前页
BitmapmNextPageBitmap = null ;
PointFmTouch = new PointF(); // 拖拽点
PointFmBezierStart1 = new PointF(); // 贝塞尔曲线起始点
PointFmBezierControl1 = new PointF(); // 贝塞尔曲线控制点
PointFmBeziervertex1 = new PointF(); // 贝塞尔曲线顶点
PointFmBezierEnd1 = new PointF(); // 贝塞尔曲线结束点
PointFmBezierStart2 = new PointF(); // 另一条贝塞尔曲线
PointFmBezierControl2 = new PointF();
PointFmBeziervertex2 = new PointF();
PointFmBezierEnd2 = new PointF();
float mMiddleX;
float mMiddleY;
float mDegrees;
float mTouchToCornerDis;
ColorMatrixColorFiltermColorMatrixFilter;
MatrixmMatrix;
float []mMatrixArray = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1.0f };
boolean mIsRTandLB; // 是否属于右上左下
float mMaxLength = ( float )Math.hypot(mWidth,mHeight);
int []mBackShadowColors;
int []mFrontShadowColors;
GradientDrawablemBackShadowDrawableLR;
GradientDrawablemBackShadowDrawableRL;
GradientDrawablemFolderShadowDrawableLR;
GradientDrawablemFolderShadowDrawableRL;
GradientDrawablemFrontShadowDrawableHBT;
GradientDrawablemFrontShadowDrawableHTB;
GradientDrawablemFrontShadowDrawableVLR;
GradientDrawablemFrontShadowDrawableVRL;
PaintmPaint;
ScrollermScroller;
public PageWidget(Contextcontext){
super (context);
// TODOAuto-generatedconstructorstub
mPath0 = new Path();
mPath1 = new Path();
createDrawable();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
ColorMatrixcm = new ColorMatrix();
float array[] = { 0.55f , 0 , 0 , 0 , 80.0f , 0 , 0.55f , 0 , 0 , 80.0f , 0 , 0 ,
0.55f , 0 , 80.0f , 0 , 0 , 0 , 0.2f , 0 };
cm.set(array);
mColorMatrixFilter = new ColorMatrixColorFilter(cm);
mMatrix = new Matrix();
mScroller = new Scroller(getContext());
mTouch.x = 0.01f ; // 不让x,y为0,否则在点计算时会有问题
mTouch.y = 0.01f ;
}
/**
*Author:hmg25Version:1.0Description:计算拖拽点对应的拖拽脚
*/
public void calcCornerXY( float x, float y){
if (x <= mWidth / 2 )
mCornerX = 0 ;
else
mCornerX = mWidth;
if (y <= mHeight / 2 )
mCornerY = 0 ;
else
mCornerY = mHeight;
if ((mCornerX == 0 && mCornerY == mHeight)
|| (mCornerX == mWidth && mCornerY == 0 ))
mIsRTandLB = true ;
else
mIsRTandLB = false ;
}
public boolean doTouchEvent(MotionEventevent){
// TODOAuto-generatedmethodstub
if (event.getAction() == MotionEvent.ACTION_MOVE){
mTouch.x = event.getX();
mTouch.y = event.getY();
this .postInvalidate();
}
if (event.getAction() == MotionEvent.ACTION_DOWN){
mTouch.x = event.getX();
mTouch.y = event.getY();
// calcCornerXY(mTouch.x,mTouch.y);
// this.postInvalidate();
}
if (event.getAction() == MotionEvent.ACTION_UP){
if (canDragOver()){
startAnimation( 1200 );
} else {
mTouch.x = mCornerX - 0.09f ;
mTouch.y = mCornerY - 0.09f ;
}
this .postInvalidate();
}
// returnsuper.onTouchEvent(event);
return true ;
}
/**
*Author:hmg25Version:1.0Description:求解直线P1P2和直线P3P4的交点坐标
*/
public PointFgetCross(PointFP1,PointFP2,PointFP3,PointFP4){
PointFCrossP = new PointF();
// 二元函数通式:y=ax+b
float a1 = (P2.y - P1.y) / (P2.x - P1.x);
float b1 = ((P1.x * P2.y) - (P2.x * P1.y)) / (P1.x - P2.x);
float a2 = (P4.y - P3.y) / (P4.x - P3.x);
float b2 = ((P3.x * P4.y) - (P4.x * P3.y)) / (P3.x - P4.x);
CrossP.x = (b2 - b1) / (a1 - a2);
CrossP.y = a1 * CrossP.x + b1;
return CrossP;
}
private void calcPoints(){
mMiddleX = (mTouch.x + mCornerX) / 2 ;
mMiddleY = (mTouch.y + mCornerY) / 2 ;
mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY)
* (mCornerY - mMiddleY) / (mCornerX - mMiddleX);
mBezierControl1.y = mCornerY;
mBezierControl2.x = mCornerX;
mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX)
* (mCornerX - mMiddleX) / (mCornerY - mMiddleY);
// Log.i("hmg","mTouchX"+mTouch.x+"mTouchY"+mTouch.y);
// Log.i("hmg","mBezierControl1.x"+mBezierControl1.x
// +"mBezierControl1.y"+mBezierControl1.y);
// Log.i("hmg","mBezierControl2.x"+mBezierControl2.x
// +"mBezierControl2.y"+mBezierControl2.y);
mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x)
/ 2 ;
mBezierStart1.y = mCornerY;
// 当mBezierStart1.x<0或者mBezierStart1.x>480时
// 如果继续翻页,会出现BUG故在此限制
if (mTouch.x > 0 && mTouch.x < mWidth){
if (mBezierStart1.x < 0 || mBezierStart1.x > mWidth){
if (mBezierStart1.x < 0 )
mBezierStart1.x = mWidth - mBezierStart1.x;
float f1 = Math.abs(mCornerX - mTouch.x);
float f2 = mWidth * f1 / mBezierStart1.x;
mTouch.x = Math.abs(mCornerX - f2);
float f3 = Math.abs(mCornerX - mTouch.x)
* Math.abs(mCornerY - mTouch.y) / f1;
mTouch.y = Math.abs(mCornerY - f3);
mMiddleX = (mTouch.x + mCornerX) / 2 ;
mMiddleY = (mTouch.y + mCornerY) / 2 ;
mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY)
* (mCornerY - mMiddleY) / (mCornerX - mMiddleX);
mBezierControl1.y = mCornerY;
mBezierControl2.x = mCornerX;
mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX)
* (mCornerX - mMiddleX) / (mCornerY - mMiddleY);
// Log.i("hmg","mTouchX-->"+mTouch.x+"mTouchY-->"
// +mTouch.y);
// Log.i("hmg","mBezierControl1.x--"+mBezierControl1.x
// +"mBezierControl1.y--"+mBezierControl1.y);
// Log.i("hmg","mBezierControl2.x--"+mBezierControl2.x
// +"mBezierControl2.y--"+mBezierControl2.y);
mBezierStart1.x = mBezierControl1.x
- (mCornerX - mBezierControl1.x) / 2 ;
}
}
mBezierStart2.x = mCornerX;
mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y)
/ 2 ;
mTouchToCornerDis = ( float )Math.hypot((mTouch.x - mCornerX),
(mTouch.y - mCornerY));
mBezierEnd1 = getCross(mTouch,mBezierControl1,mBezierStart1,
mBezierStart2);
mBezierEnd2 = getCross(mTouch,mBezierControl2,mBezierStart1,
mBezierStart2);
// Log.i("hmg","mBezierEnd1.x"+mBezierEnd1.x+"mBezierEnd1.y"
// +mBezierEnd1.y);
// Log.i("hmg","mBezierEnd2.x"+mBezierEnd2.x+"mBezierEnd2.y"
// +mBezierEnd2.y);
/*
*mBeziervertex1.x推导
*((mBezierStart1.x+mBezierEnd1.x)/2+mBezierControl1.x)/2化简等价于
*(mBezierStart1.x+2*mBezierControl1.x+mBezierEnd1.x)/4
*/
mBeziervertex1.x = (mBezierStart1.x + 2 * mBezierControl1.x + mBezierEnd1.x) / 4 ;
mBeziervertex1.y = ( 2 * mBezierControl1.y + mBezierStart1.y + mBezierEnd1.y) / 4 ;
mBeziervertex2.x = (mBezierStart2.x + 2 * mBezierControl2.x + mBezierEnd2.x) / 4 ;
mBeziervertex2.y = ( 2 * mBezierControl2.y + mBezierStart2.y + mBezierEnd2.y) / 4 ;
}
private void drawCurrentPageArea(Canvascanvas,Bitmapbitmap,Pathpath){
mPath0.reset();
mPath0.moveTo(mBezierStart1.x,mBezierStart1.y);
mPath0.quadTo(mBezierControl1.x,mBezierControl1.y,mBezierEnd1.x,
mBezierEnd1.y);
mPath0.lineTo(mTouch.x,mTouch.y);
mPath0.lineTo(mBezierEnd2.x,mBezierEnd2.y);
mPath0.quadTo(mBezierControl2.x,mBezierControl2.y,mBezierStart2.x,
mBezierStart2.y);
mPath0.lineTo(mCornerX,mCornerY);
mPath0.close();
canvas.save();
canvas.clipPath(path,Region.Op.XOR);
canvas.drawBitmap(bitmap, 0 , 0 , null );
canvas.restore();
}
private void drawNextPageAreaAndShadow(Canvascanvas,Bitmapbitmap){
mPath1.reset();
mPath1.moveTo(mBezierStart1.x,mBezierStart1.y);
mPath1.lineTo(mBeziervertex1.x,mBeziervertex1.y);
mPath1.lineTo(mBeziervertex2.x,mBeziervertex2.y);
mPath1.lineTo(mBezierStart2.x,mBezierStart2.y);
mPath1.lineTo(mCornerX,mCornerY);
mPath1.close();
mDegrees = ( float )Math.toDegrees(Math.atan2(mBezierControl1.x
- mCornerX,mBezierControl2.y - mCornerY));
int leftx;
int rightx;
GradientDrawablemBackShadowDrawable;
if (mIsRTandLB){
leftx = ( int )(mBezierStart1.x);
rightx = ( int )(mBezierStart1.x + mTouchToCornerDis / 4 );
mBackShadowDrawable = mBackShadowDrawableLR;
} else {
leftx = ( int )(mBezierStart1.x - mTouchToCornerDis / 4 );
rightx = ( int )mBezierStart1.x;
mBackShadowDrawable = mBackShadowDrawableRL;
}
canvas.save();
canvas.clipPath(mPath0);
canvas.clipPath(mPath1,Region.Op.INTERSECT);
canvas.drawBitmap(bitmap, 0 , 0 , null );
canvas.rotate(mDegrees,mBezierStart1.x,mBezierStart1.y);
mBackShadowDrawable.setBounds(leftx,( int )mBezierStart1.y,rightx,
( int )(mMaxLength + mBezierStart1.y));
mBackShadowDrawable.draw(canvas);
canvas.restore();
}
public void setBitmaps(Bitmapbm1,Bitmapbm2){
mCurPageBitmap = bm1;
mNextPageBitmap = bm2;
}
public void setScreen( int w, int h){
mWidth = w;
mHeight = h;
}
@Override
protected void onDraw(Canvascanvas){
canvas.drawColor( 0xFFAAAAAA );
calcPoints();
drawCurrentPageArea(canvas,mCurPageBitmap,mPath0);
drawNextPageAreaAndShadow(canvas,mNextPageBitmap);
drawCurrentPageShadow(canvas);
drawCurrentBackArea(canvas,mCurPageBitmap);
}
/**
*Author:hmg25Version:1.0Description:创建阴影的GradientDrawable
*/
private void createDrawable(){
int []color = { 0x333333 , 0xb0333333 };
mFolderShadowDrawableRL = new GradientDrawable(
GradientDrawable.Orientation.RIGHT_LEFT,color);
mFolderShadowDrawableRL
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mFolderShadowDrawableLR = new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,color);
mFolderShadowDrawableLR
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mBackShadowColors = new int []{ 0xff111111 , 0x111111 };
mBackShadowDrawableRL = new GradientDrawable(
GradientDrawable.Orientation.RIGHT_LEFT,mBackShadowColors);
mBackShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mBackShadowDrawableLR = new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,mBackShadowColors);
mBackShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mFrontShadowColors = new int []{ 0x80111111 , 0x111111 };
mFrontShadowDrawableVLR = new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,mFrontShadowColors);
mFrontShadowDrawableVLR
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mFrontShadowDrawableVRL = new GradientDrawable(
GradientDrawable.Orientation.RIGHT_LEFT,mFrontShadowColors);
mFrontShadowDrawableVRL
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mFrontShadowDrawableHTB = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,mFrontShadowColors);
mFrontShadowDrawableHTB
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mFrontShadowDrawableHBT = new GradientDrawable(
GradientDrawable.Orientation.BOTTOM_TOP,mFrontShadowColors);
mFrontShadowDrawableHBT
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
}
/**
*Author:hmg25Version:1.0Description:绘制翻起页的阴影
*/
public void drawCurrentPageShadow(Canvascanvas){
double degree;
if (mIsRTandLB){
degree = Math.PI
/ 4
- Math.atan2(mBezierControl1.y - mTouch.y,mTouch.x
- mBezierControl1.x);
} else {
degree = Math.PI
/ 4
- Math.atan2(mTouch.y - mBezierControl1.y,mTouch.x
- mBezierControl1.x);
}
// 翻起页阴影顶点与touch点的距离
double d1 = ( float ) 25 * 1.414 * Math.cos(degree);
double d2 = ( float ) 25 * 1.414 * Math.sin(degree);
float x = ( float )(mTouch.x + d1);
float y;
if (mIsRTandLB){
y = ( float )(mTouch.y + d2);
} else {
y = ( float )(mTouch.y - d2);
}
mPath1.reset();
mPath1.moveTo(x,y);
mPath1.lineTo(mTouch.x,mTouch.y);
mPath1.lineTo(mBezierControl1.x,mBezierControl1.y);
mPath1.lineTo(mBezierStart1.x,mBezierStart1.y);
mPath1.close();
float rotateDegrees;
canvas.save();
canvas.clipPath(mPath0,Region.Op.XOR);
canvas.clipPath(mPath1,Region.Op.INTERSECT);
int leftx;
int rightx;
GradientDrawablemCurrentPageShadow;
if (mIsRTandLB){
leftx = ( int )(mBezierControl1.x);
rightx = ( int )mBezierControl1.x + 25 ;
mCurrentPageShadow = mFrontShadowDrawableVLR;
} else {
leftx = ( int )(mBezierControl1.x - 25 );
rightx = ( int )mBezierControl1.x + 1 ;
mCurrentPageShadow = mFrontShadowDrawableVRL;
}
rotateDegrees = ( float )Math.toDegrees(Math.atan2(mTouch.x
- mBezierControl1.x,mBezierControl1.y - mTouch.y));
canvas.rotate(rotateDegrees,mBezierControl1.x,mBezierControl1.y);
mCurrentPageShadow.setBounds(leftx,
( int )(mBezierControl1.y - mMaxLength),rightx,
( int )(mBezierControl1.y));
mCurrentPageShadow.draw(canvas);
canvas.restore();
mPath1.reset();
mPath1.moveTo(x,y);
mPath1.lineTo(mTouch.x,mTouch.y);
mPath1.lineTo(mBezierControl2.x,mBezierControl2.y);
mPath1.lineTo(mBezierStart2.x,mBezierStart2.y);
mPath1.close();
canvas.save();
canvas.clipPath(mPath0,Region.Op.XOR);
canvas.clipPath(mPath1,Region.Op.INTERSECT);
if (mIsRTandLB){
leftx = ( int )(mBezierControl2.y);
rightx = ( int )(mBezierControl2.y + 25 );
mCurrentPageShadow = mFrontShadowDrawableHTB;
} else {
leftx = ( int )(mBezierControl2.y - 25 );
rightx = ( int )(mBezierControl2.y + 1 );
mCurrentPageShadow = mFrontShadowDrawableHBT;
}
rotateDegrees = ( float )Math.toDegrees(Math.atan2(mBezierControl2.y
- mTouch.y,mBezierControl2.x - mTouch.x));
canvas.rotate(rotateDegrees,mBezierControl2.x,mBezierControl2.y);
float temp;
if (mBezierControl2.y < 0 )
temp = mBezierControl2.y - mHeight;
else
temp = mBezierControl2.y;
int hmg = ( int )Math.hypot(mBezierControl2.x,temp);
if (hmg > mMaxLength)
mCurrentPageShadow
.setBounds(( int )(mBezierControl2.x - 25 ) - hmg,leftx,
( int )(mBezierControl2.x + mMaxLength) - hmg,
rightx);
else
mCurrentPageShadow.setBounds(
( int )(mBezierControl2.x - mMaxLength),leftx,
( int )(mBezierControl2.x),rightx);
// Log.i("hmg","mBezierControl2.x"+mBezierControl2.x
// +"mBezierControl2.y"+mBezierControl2.y);
mCurrentPageShadow.draw(canvas);
canvas.restore();
}
/**
*Author:hmg25Version:1.0Description:绘制翻起页背面
*/
private void drawCurrentBackArea(Canvascanvas,Bitmapbitmap){
int i = ( int )(mBezierStart1.x + mBezierControl1.x) / 2 ;
float f1 = Math.abs(i - mBezierControl1.x);
int i1 = ( int )(mBezierStart2.y + mBezierControl2.y) / 2 ;
float f2 = Math.abs(i1 - mBezierControl2.y);
float f3 = Math.min(f1,f2);
mPath1.reset();
mPath1.moveTo(mBeziervertex2.x,mBeziervertex2.y);
mPath1.lineTo(mBeziervertex1.x,mBeziervertex1.y);
mPath1.lineTo(mBezierEnd1.x,mBezierEnd1.y);
mPath1.lineTo(mTouch.x,mTouch.y);
mPath1.lineTo(mBezierEnd2.x,mBezierEnd2.y);
mPath1.close();
GradientDrawablemFolderShadowDrawable;
int left;
int right;
if (mIsRTandLB){
left = ( int )(mBezierStart1.x - 1 );
right = ( int )(mBezierStart1.x + f3 + 1 );
mFolderShadowDrawable = mFolderShadowDrawableLR;
} else {
left = ( int )(mBezierStart1.x - f3 - 1 );
right = ( int )(mBezierStart1.x + 1 );
mFolderShadowDrawable = mFolderShadowDrawableRL;
}
canvas.save();
canvas.clipPath(mPath0);
canvas.clipPath(mPath1,Region.Op.INTERSECT);
mPaint.setColorFilter(mColorMatrixFilter);
float dis = ( float )Math.hypot(mCornerX - mBezierControl1.x,
mBezierControl2.y - mCornerY);
float f8 = (mCornerX - mBezierControl1.x) / dis;
float f9 = (mBezierControl2.y - mCornerY) / dis;
mMatrixArray[ 0 ] = 1 - 2 * f9 * f9;
mMatrixArray[ 1 ] = 2 * f8 * f9;
mMatrixArray[ 3 ] = mMatrixArray[ 1 ];
mMatrixArray[ 4 ] = 1 - 2 * f8 * f8;
mMatrix.reset();
mMatrix.setValues(mMatrixArray);
mMatrix.preTranslate( - mBezierControl1.x, - mBezierControl1.y);
mMatrix.postTranslate(mBezierControl1.x,mBezierControl1.y);
canvas.drawBitmap(bitmap,mMatrix,mPaint);
// canvas.drawBitmap(bitmap,mMatrix,null);
mPaint.setColorFilter( null );
canvas.rotate(mDegrees,mBezierStart1.x,mBezierStart1.y);
mFolderShadowDrawable.setBounds(left,( int )mBezierStart1.y,right,
( int )(mBezierStart1.y + mMaxLength));
mFolderShadowDrawable.draw(canvas);
canvas.restore();
}
public void computeScroll(){
super .computeScroll();
if (mScroller.computeScrollOffset()){
float x = mScroller.getCurrX();
float y = mScroller.getCurrY();
mTouch.x = x;
mTouch.y = y;
postInvalidate();
}
}
private void startAnimation( int delayMillis){
int dx,dy;
// dx水平方向滑动的距离,负值会使滚动向左滚动
// dy垂直方向滑动的距离,负值会使滚动向上滚动
if (mCornerX > 0 ){
dx = - ( int )(mWidth + mTouch.x);
} else {
dx = ( int )(mWidth - mTouch.x + mWidth);
}
if (mCornerY > 0 ){
dy = ( int )(mHeight - mTouch.y);
} else {
dy = ( int )( 1 - mTouch.y); // 防止mTouch.y最终变为0
}
mScroller.startScroll(( int )mTouch.x,( int )mTouch.y,dx,dy,
delayMillis);
}
public void abortAnimation(){
if ( ! mScroller.isFinished()){
mScroller.abortAnimation();
}
}
public boolean canDragOver(){
if (mTouchToCornerDis > mWidth / 10 )
return true ;
return false ;
}
/**
*Author:hmg25Version:1.0Description:是否从左边翻向右边
*/
public boolean DragToRight(){
if (mCornerX > 0 )
return false ;
return true ;
}
}
/**
*Author:hmg25
*Description:
*/
package sf.hmg.turntest;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;
import java.util.Vector;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
public class BookPageFactory{
private Filebook_file = null ;
private MappedByteBufferm_mbBuf = null ;
private int m_mbBufLen = 0 ;
private int m_mbBufBegin = 0 ;
private int m_mbBufEnd = 0 ;
private Stringm_strCharsetName = " GBK " ;
private Bitmapm_book_bg = null ;
private int mWidth;
private int mHeight;
private Vector < String > m_lines = new Vector < String > ();
private int m_fontSize = 24 ;
private int m_textColor = Color.BLACK;
private int m_backColor = 0xffff9e85 ; // 背景颜色
private int marginWidth = 15 ; // 左右与边缘的距离
private int marginHeight = 20 ; // 上下与边缘的距离
private int mLineCount; // 每页可以显示的行数
private float mVisibleHeight; // 绘制内容的宽
private float mVisibleWidth; // 绘制内容的宽
private boolean m_isfirstPage,m_islastPage;
// privateintm_nLineSpaceing=5;
private PaintmPaint;
public BookPageFactory( int w, int h){
// TODOAuto-generatedconstructorstub
mWidth = w;
mHeight = h;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setTextAlign(Align.LEFT);
mPaint.setTextSize(m_fontSize);
mPaint.setColor(m_textColor);
mVisibleWidth = mWidth - marginWidth * 2 ;
mVisibleHeight = mHeight - marginHeight * 2 ;
mLineCount = ( int )(mVisibleHeight / m_fontSize); // 可显示的行数
}
public void openbook(StringstrFilePath) throws IOException{
book_file = new File(strFilePath);
long lLen = book_file.length();
m_mbBufLen = ( int )lLen;
m_mbBuf = new RandomAccessFile(book_file, " r " ).getChannel().map(
FileChannel.MapMode.READ_ONLY, 0 ,lLen);
}
protected byte []readParagraphBack( int nFromPos){
int nEnd = nFromPos;
int i;
byte b0,b1;
if (m_strCharsetName.equals( " UTF-16LE " )){
i = nEnd - 2 ;
while (i > 0 ){
b0 = m_mbBuf.get(i);
b1 = m_mbBuf.get(i + 1 );
if (b0 == 0x0a && b1 == 0x00 && i != nEnd - 2 ){
i += 2 ;
break ;
}
i -- ;
}
} else if (m_strCharsetName.equals( " UTF-16BE " )){
i = nEnd - 2 ;
while (i > 0 ){
b0 = m_mbBuf.get(i);
b1 = m_mbBuf.get(i + 1 );
if (b0 == 0x00 && b1 == 0x0a && i != nEnd - 2 ){
i += 2 ;
break ;
}
i -- ;
}
} else {
i = nEnd - 1 ;
while (i > 0 ){
b0 = m_mbBuf.get(i);
if (b0 == 0x0a && i != nEnd - 1 ){
i ++ ;
break ;
}
i -- ;
}
}
if (i < 0 )
i = 0 ;
int nParaSize = nEnd - i;
int j;
byte []buf = new byte [nParaSize];
for (j = 0 ;j < nParaSize;j ++ ){
buf[j] = m_mbBuf.get(i + j);
}
return buf;
}
// 读取上一段落
protected byte []readParagraphForward( int nFromPos){
int nStart = nFromPos;
int i = nStart;
byte b0,b1;
// 根据编码格式判断换行
if (m_strCharsetName.equals( " UTF-16LE " )){
while (i < m_mbBufLen - 1 ){
b0 = m_mbBuf.get(i ++ );
b1 = m_mbBuf.get(i ++ );
if (b0 == 0x0a && b1 == 0x00 ){
break ;
}
}
} else if (m_strCharsetName.equals( " UTF-16BE " )){
while (i < m_mbBufLen - 1 ){
b0 = m_mbBuf.get(i ++ );
b1 = m_mbBuf.get(i ++ );
if (b0 == 0x00 && b1 == 0x0a ){
break ;
}
}
} else {
while (i < m_mbBufLen){
b0 = m_mbBuf.get(i ++ );
if (b0 == 0x0a ){
break ;
}
}
}
int nParaSize = i - nStart;
byte []buf = new byte [nParaSize];
for (i = 0 ;i < nParaSize;i ++ ){
buf[i] = m_mbBuf.get(nFromPos + i);
}
return buf;
}
protected Vector < String > pageDown(){
StringstrParagraph = "" ;
Vector < String > lines = new Vector < String > ();
while (lines.size() < mLineCount && m_mbBufEnd < m_mbBufLen){
byte []paraBuf = readParagraphForward(m_mbBufEnd); // 读取一个段落
m_mbBufEnd += paraBuf.length;
try {
strParagraph = new String(paraBuf,m_strCharsetName);
} catch (UnsupportedEncodingExceptione){
// TODOAuto-generatedcatchblock
e.printStackTrace();
}
StringstrReturn = "" ;
if (strParagraph.indexOf( " \r\n " ) != - 1 ){
strReturn = " \r\n " ;
strParagraph = strParagraph.replaceAll( " \r\n " , "" );
} else if (strParagraph.indexOf( " \n " ) != - 1 ){
strReturn = " \n " ;
strParagraph = strParagraph.replaceAll( " \n " , "" );
}
if (strParagraph.length() == 0 ){
lines.add(strParagraph);
}
while (strParagraph.length() > 0 ){
int nSize = mPaint.breakText(strParagraph, true ,mVisibleWidth,
null );
lines.add(strParagraph.substring( 0 ,nSize));
strParagraph = strParagraph.substring(nSize);
if (lines.size() >= mLineCount){
break ;
}
}
if (strParagraph.length() != 0 ){
try {
m_mbBufEnd -= (strParagraph + strReturn)
.getBytes(m_strCharsetName).length;
} catch (UnsupportedEncodingExceptione){
// TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
return lines;
}
protected void pageUp(){
if (m_mbBufBegin < 0 )
m_mbBufBegin = 0 ;
Vector < String > lines = new Vector < String > ();
StringstrParagraph = "" ;
while (lines.size() < mLineCount && m_mbBufBegin > 0 ){
Vector < String > paraLines = new Vector < String > ();
byte []paraBuf = readParagraphBack(m_mbBufBegin);
m_mbBufBegin -= paraBuf.length;
try {
strParagraph = new String(paraBuf,m_strCharsetName);
} catch (UnsupportedEncodingExceptione){
// TODOAuto-generatedcatchblock
e.printStackTrace();
}
strParagraph = strParagraph.replaceAll( " \r\n " , "" );
strParagraph = strParagraph.replaceAll( " \n " , "" );
if (strParagraph.length() == 0 ){
paraLines.add(strParagraph);
}
while (strParagraph.length() > 0 ){
int nSize = mPaint.breakText(strParagraph, true ,mVisibleWidth,
null );
paraLines.add(strParagraph.substring( 0 ,nSize));
strParagraph = strParagraph.substring(nSize);
}
lines.addAll( 0 ,paraLines);
}
while (lines.size() > mLineCount){
try {
m_mbBufBegin += lines.get( 0 ).getBytes(m_strCharsetName).length;
lines.remove( 0 );
} catch (UnsupportedEncodingExceptione){
// TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
m_mbBufEnd = m_mbBufBegin;
return ;
}
protected void prePage() throws IOException{
if (m_mbBufBegin <= 0 ){
m_mbBufBegin = 0 ;
m_isfirstPage = true ;
return ;
} else m_isfirstPage = false ;
m_lines.clear();
pageUp();
m_lines = pageDown();
}
public void nextPage() throws IOException{
if (m_mbBufEnd >= m_mbBufLen){
m_islastPage = true ;
return ;
} else m_islastPage = false ;
m_lines.clear();
m_mbBufBegin = m_mbBufEnd;
m_lines = pageDown();
}
public void onDraw(Canvasc){
if (m_lines.size() == 0 )
m_lines = pageDown();
if (m_lines.size() > 0 ){
if (m_book_bg == null )
c.drawColor(m_backColor);
else
c.drawBitmap(m_book_bg, 0 , 0 , null );
int y = marginHeight;
for (StringstrLine:m_lines){
y += m_fontSize;
c.drawText(strLine,marginWidth,y,mPaint);
}
}
float fPercent = ( float )(m_mbBufBegin * 1.0 / m_mbBufLen);
DecimalFormatdf = new DecimalFormat( " #0.0 " );
StringstrPercent = df.format(fPercent * 100 ) + " % " ;
int nPercentWidth = ( int )mPaint.measureText( " 999.9% " ) + 1 ;
c.drawText(strPercent,mWidth - nPercentWidth,mHeight - 5 ,mPaint);
}
public void setBgBitmap(BitmapBG){
m_book_bg = BG;
}
public boolean isfirstPage(){
return m_isfirstPage;
}
public boolean islastPage(){
return m_islastPage;
}
}
package sf.hmg.turntest;
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
public class turntest extends Activity{
/** Calledwhentheactivityisfirstcreated. */
private PageWidgetmPageWidget;
BitmapmCurPageBitmap,mNextPageBitmap;
CanvasmCurPageCanvas,mNextPageCanvas;
BookPageFactorypagefactory;
@Override
public void onCreate(BundlesavedInstanceState){
super .onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
mPageWidget = new PageWidget( this );
setContentView(mPageWidget);
mCurPageBitmap = Bitmap.createBitmap( 480 , 800 ,Bitmap.Config.ARGB_8888);
mNextPageBitmap = Bitmap
.createBitmap( 480 , 800 ,Bitmap.Config.ARGB_8888);
mCurPageCanvas = new Canvas(mCurPageBitmap);
mNextPageCanvas = new Canvas(mNextPageBitmap);
pagefactory = new BookPageFactory( 480 , 800 );
pagefactory.setBgBitmap(BitmapFactory.decodeResource(
this .getResources(),R.drawable.bg));
try {
pagefactory.openbook( " /sdcard/test.txt " );
pagefactory.onDraw(mCurPageCanvas);
} catch (IOExceptione1){
// TODOAuto-generatedcatchblock
e1.printStackTrace();
Toast.makeText( this , " 电子书不存在,请将《test.txt》放在SD卡根目录下 " ,
Toast.LENGTH_SHORT).show();
}
mPageWidget.setBitmaps(mCurPageBitmap,mCurPageBitmap);
mPageWidget.setOnTouchListener( new OnTouchListener(){
@Override
public boolean onTouch(Viewv,MotionEvente){
// TODOAuto-generatedmethodstub
boolean ret = false ;
if (v == mPageWidget){
if (e.getAction() == MotionEvent.ACTION_DOWN){
mPageWidget.abortAnimation();
mPageWidget.calcCornerXY(e.getX(),e.getY());
pagefactory.onDraw(mCurPageCanvas);
if (mPageWidget.DragToRight()){
try {
pagefactory.prePage();
} catch (IOExceptione1){
// TODOAuto-generatedcatchblock
e1.printStackTrace();
}
if (pagefactory.isfirstPage()) return false ;
pagefactory.onDraw(mNextPageCanvas);
} else {
try {
pagefactory.nextPage();
} catch (IOExceptione1){
// TODOAuto-generatedcatchblock
e1.printStackTrace();
}
if (pagefactory.islastPage()) return false ;
pagefactory.onDraw(mNextPageCanvas);
}
mPageWidget.setBitmaps(mCurPageBitmap,mNextPageBitmap);
}
ret = mPageWidget.doTouchEvent(e);
return ret;
}
return false ;
}
});
}
}
package sf.hmg.turntest;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Region;
import android.graphics.drawable.GradientDrawable;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
public class PageWidget extends View{
private static final StringTAG = " hmg " ;
private int mWidth = 480 ;
private int mHeight = 800 ;
private int mCornerX = 0 ; // 拖拽点对应的页脚
private int mCornerY = 0 ;
private PathmPath0;
private PathmPath1;
BitmapmCurPageBitmap = null ; // 当前页
BitmapmNextPageBitmap = null ;
PointFmTouch = new PointF(); // 拖拽点
PointFmBezierStart1 = new PointF(); // 贝塞尔曲线起始点
PointFmBezierControl1 = new PointF(); // 贝塞尔曲线控制点
PointFmBeziervertex1 = new PointF(); // 贝塞尔曲线顶点
PointFmBezierEnd1 = new PointF(); // 贝塞尔曲线结束点
PointFmBezierStart2 = new PointF(); // 另一条贝塞尔曲线
PointFmBezierControl2 = new PointF();
PointFmBeziervertex2 = new PointF();
PointFmBezierEnd2 = new PointF();
float mMiddleX;
float mMiddleY;
float mDegrees;
float mTouchToCornerDis;
ColorMatrixColorFiltermColorMatrixFilter;
MatrixmMatrix;
float []mMatrixArray = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1.0f };
boolean mIsRTandLB; // 是否属于右上左下
float mMaxLength = ( float )Math.hypot(mWidth,mHeight);
int []mBackShadowColors;
int []mFrontShadowColors;
GradientDrawablemBackShadowDrawableLR;
GradientDrawablemBackShadowDrawableRL;
GradientDrawablemFolderShadowDrawableLR;
GradientDrawablemFolderShadowDrawableRL;
GradientDrawablemFrontShadowDrawableHBT;
GradientDrawablemFrontShadowDrawableHTB;
GradientDrawablemFrontShadowDrawableVLR;
GradientDrawablemFrontShadowDrawableVRL;
PaintmPaint;
ScrollermScroller;
public PageWidget(Contextcontext){
super (context);
// TODOAuto-generatedconstructorstub
mPath0 = new Path();
mPath1 = new Path();
createDrawable();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
ColorMatrixcm = new ColorMatrix();
float array[] = { 0.55f , 0 , 0 , 0 , 80.0f , 0 , 0.55f , 0 , 0 , 80.0f , 0 , 0 ,
0.55f , 0 , 80.0f , 0 , 0 , 0 , 0.2f , 0 };
cm.set(array);
mColorMatrixFilter = new ColorMatrixColorFilter(cm);
mMatrix = new Matrix();
mScroller = new Scroller(getContext());
mTouch.x = 0.01f ; // 不让x,y为0,否则在点计算时会有问题
mTouch.y = 0.01f ;
}
/**
*Author:hmg25Version:1.0Description:计算拖拽点对应的拖拽脚
*/
public void calcCornerXY( float x, float y){
if (x <= mWidth / 2 )
mCornerX = 0 ;
else
mCornerX = mWidth;
if (y <= mHeight / 2 )
mCornerY = 0 ;
else
mCornerY = mHeight;
if ((mCornerX == 0 && mCornerY == mHeight)
|| (mCornerX == mWidth && mCornerY == 0 ))
mIsRTandLB = true ;
else
mIsRTandLB = false ;
}
public boolean doTouchEvent(MotionEventevent){
// TODOAuto-generatedmethodstub
if (event.getAction() == MotionEvent.ACTION_MOVE){
mTouch.x = event.getX();
mTouch.y = event.getY();
this .postInvalidate();
}
if (event.getAction() == MotionEvent.ACTION_DOWN){
mTouch.x = event.getX();
mTouch.y = event.getY();
// calcCornerXY(mTouch.x,mTouch.y);
// this.postInvalidate();
}
if (event.getAction() == MotionEvent.ACTION_UP){
if (canDragOver()){
startAnimation( 1200 );
} else {
mTouch.x = mCornerX - 0.09f ;
mTouch.y = mCornerY - 0.09f ;
}
this .postInvalidate();
}
// returnsuper.onTouchEvent(event);
return true ;
}
/**
*Author:hmg25Version:1.0Description:求解直线P1P2和直线P3P4的交点坐标
*/
public PointFgetCross(PointFP1,PointFP2,PointFP3,PointFP4){
PointFCrossP = new PointF();
// 二元函数通式:y=ax+b
float a1 = (P2.y - P1.y) / (P2.x - P1.x);
float b1 = ((P1.x * P2.y) - (P2.x * P1.y)) / (P1.x - P2.x);
float a2 = (P4.y - P3.y) / (P4.x - P3.x);
float b2 = ((P3.x * P4.y) - (P4.x * P3.y)) / (P3.x - P4.x);
CrossP.x = (b2 - b1) / (a1 - a2);
CrossP.y = a1 * CrossP.x + b1;
return CrossP;
}
private void calcPoints(){
mMiddleX = (mTouch.x + mCornerX) / 2 ;
mMiddleY = (mTouch.y + mCornerY) / 2 ;
mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY)
* (mCornerY - mMiddleY) / (mCornerX - mMiddleX);
mBezierControl1.y = mCornerY;
mBezierControl2.x = mCornerX;
mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX)
* (mCornerX - mMiddleX) / (mCornerY - mMiddleY);
// Log.i("hmg","mTouchX"+mTouch.x+"mTouchY"+mTouch.y);
// Log.i("hmg","mBezierControl1.x"+mBezierControl1.x
// +"mBezierControl1.y"+mBezierControl1.y);
// Log.i("hmg","mBezierControl2.x"+mBezierControl2.x
// +"mBezierControl2.y"+mBezierControl2.y);
mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x)
/ 2 ;
mBezierStart1.y = mCornerY;
// 当mBezierStart1.x<0或者mBezierStart1.x>480时
// 如果继续翻页,会出现BUG故在此限制
if (mTouch.x > 0 && mTouch.x < mWidth){
if (mBezierStart1.x < 0 || mBezierStart1.x > mWidth){
if (mBezierStart1.x < 0 )
mBezierStart1.x = mWidth - mBezierStart1.x;
float f1 = Math.abs(mCornerX - mTouch.x);
float f2 = mWidth * f1 / mBezierStart1.x;
mTouch.x = Math.abs(mCornerX - f2);
float f3 = Math.abs(mCornerX - mTouch.x)
* Math.abs(mCornerY - mTouch.y) / f1;
mTouch.y = Math.abs(mCornerY - f3);
mMiddleX = (mTouch.x + mCornerX) / 2 ;
mMiddleY = (mTouch.y + mCornerY) / 2 ;
mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY)
* (mCornerY - mMiddleY) / (mCornerX - mMiddleX);
mBezierControl1.y = mCornerY;
mBezierControl2.x = mCornerX;
mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX)
* (mCornerX - mMiddleX) / (mCornerY - mMiddleY);
// Log.i("hmg","mTouchX-->"+mTouch.x+"mTouchY-->"
// +mTouch.y);
// Log.i("hmg","mBezierControl1.x--"+mBezierControl1.x
// +"mBezierControl1.y--"+mBezierControl1.y);
// Log.i("hmg","mBezierControl2.x--"+mBezierControl2.x
// +"mBezierControl2.y--"+mBezierControl2.y);
mBezierStart1.x = mBezierControl1.x
- (mCornerX - mBezierControl1.x) / 2 ;
}
}
mBezierStart2.x = mCornerX;
mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y)
/ 2 ;
mTouchToCornerDis = ( float )Math.hypot((mTouch.x - mCornerX),
(mTouch.y - mCornerY));
mBezierEnd1 = getCross(mTouch,mBezierControl1,mBezierStart1,
mBezierStart2);
mBezierEnd2 = getCross(mTouch,mBezierControl2,mBezierStart1,
mBezierStart2);
// Log.i("hmg","mBezierEnd1.x"+mBezierEnd1.x+"mBezierEnd1.y"
// +mBezierEnd1.y);
// Log.i("hmg","mBezierEnd2.x"+mBezierEnd2.x+"mBezierEnd2.y"
// +mBezierEnd2.y);
/*
*mBeziervertex1.x推导
*((mBezierStart1.x+mBezierEnd1.x)/2+mBezierControl1.x)/2化简等价于
*(mBezierStart1.x+2*mBezierControl1.x+mBezierEnd1.x)/4
*/
mBeziervertex1.x = (mBezierStart1.x + 2 * mBezierControl1.x + mBezierEnd1.x) / 4 ;
mBeziervertex1.y = ( 2 * mBezierControl1.y + mBezierStart1.y + mBezierEnd1.y) / 4 ;
mBeziervertex2.x = (mBezierStart2.x + 2 * mBezierControl2.x + mBezierEnd2.x) / 4 ;
mBeziervertex2.y = ( 2 * mBezierControl2.y + mBezierStart2.y + mBezierEnd2.y) / 4 ;
}
private void drawCurrentPageArea(Canvascanvas,Bitmapbitmap,Pathpath){
mPath0.reset();
mPath0.moveTo(mBezierStart1.x,mBezierStart1.y);
mPath0.quadTo(mBezierControl1.x,mBezierControl1.y,mBezierEnd1.x,
mBezierEnd1.y);
mPath0.lineTo(mTouch.x,mTouch.y);
mPath0.lineTo(mBezierEnd2.x,mBezierEnd2.y);
mPath0.quadTo(mBezierControl2.x,mBezierControl2.y,mBezierStart2.x,
mBezierStart2.y);
mPath0.lineTo(mCornerX,mCornerY);
mPath0.close();
canvas.save();
canvas.clipPath(path,Region.Op.XOR);
canvas.drawBitmap(bitmap, 0 , 0 , null );
canvas.restore();
}
private void drawNextPageAreaAndShadow(Canvascanvas,Bitmapbitmap){
mPath1.reset();
mPath1.moveTo(mBezierStart1.x,mBezierStart1.y);
mPath1.lineTo(mBeziervertex1.x,mBeziervertex1.y);
mPath1.lineTo(mBeziervertex2.x,mBeziervertex2.y);
mPath1.lineTo(mBezierStart2.x,mBezierStart2.y);
mPath1.lineTo(mCornerX,mCornerY);
mPath1.close();
mDegrees = ( float )Math.toDegrees(Math.atan2(mBezierControl1.x
- mCornerX,mBezierControl2.y - mCornerY));
int leftx;
int rightx;
GradientDrawablemBackShadowDrawable;
if (mIsRTandLB){
leftx = ( int )(mBezierStart1.x);
rightx = ( int )(mBezierStart1.x + mTouchToCornerDis / 4 );
mBackShadowDrawable = mBackShadowDrawableLR;
} else {
leftx = ( int )(mBezierStart1.x - mTouchToCornerDis / 4 );
rightx = ( int )mBezierStart1.x;
mBackShadowDrawable = mBackShadowDrawableRL;
}
canvas.save();
canvas.clipPath(mPath0);
canvas.clipPath(mPath1,Region.Op.INTERSECT);
canvas.drawBitmap(bitmap, 0 , 0 , null );
canvas.rotate(mDegrees,mBezierStart1.x,mBezierStart1.y);
mBackShadowDrawable.setBounds(leftx,( int )mBezierStart1.y,rightx,
( int )(mMaxLength + mBezierStart1.y));
mBackShadowDrawable.draw(canvas);
canvas.restore();
}
public void setBitmaps(Bitmapbm1,Bitmapbm2){
mCurPageBitmap = bm1;
mNextPageBitmap = bm2;
}
public void setScreen( int w, int h){
mWidth = w;
mHeight = h;
}
@Override
protected void onDraw(Canvascanvas){
canvas.drawColor( 0xFFAAAAAA );
calcPoints();
drawCurrentPageArea(canvas,mCurPageBitmap,mPath0);
drawNextPageAreaAndShadow(canvas,mNextPageBitmap);
drawCurrentPageShadow(canvas);
drawCurrentBackArea(canvas,mCurPageBitmap);
}
/**
*Author:hmg25Version:1.0Description:创建阴影的GradientDrawable
*/
private void createDrawable(){
int []color = { 0x333333 , 0xb0333333 };
mFolderShadowDrawableRL = new GradientDrawable(
GradientDrawable.Orientation.RIGHT_LEFT,color);
mFolderShadowDrawableRL
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mFolderShadowDrawableLR = new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,color);
mFolderShadowDrawableLR
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mBackShadowColors = new int []{ 0xff111111 , 0x111111 };
mBackShadowDrawableRL = new GradientDrawable(
GradientDrawable.Orientation.RIGHT_LEFT,mBackShadowColors);
mBackShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mBackShadowDrawableLR = new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,mBackShadowColors);
mBackShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mFrontShadowColors = new int []{ 0x80111111 , 0x111111 };
mFrontShadowDrawableVLR = new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,mFrontShadowColors);
mFrontShadowDrawableVLR
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mFrontShadowDrawableVRL = new GradientDrawable(
GradientDrawable.Orientation.RIGHT_LEFT,mFrontShadowColors);
mFrontShadowDrawableVRL
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mFrontShadowDrawableHTB = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,mFrontShadowColors);
mFrontShadowDrawableHTB
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
mFrontShadowDrawableHBT = new GradientDrawable(
GradientDrawable.Orientation.BOTTOM_TOP,mFrontShadowColors);
mFrontShadowDrawableHBT
.setGradientType(GradientDrawable.LINEAR_GRADIENT);
}
/**
*Author:hmg25Version:1.0Description:绘制翻起页的阴影
*/
public void drawCurrentPageShadow(Canvascanvas){
double degree;
if (mIsRTandLB){
degree = Math.PI
/ 4
- Math.atan2(mBezierControl1.y - mTouch.y,mTouch.x
- mBezierControl1.x);
} else {
degree = Math.PI
/ 4
- Math.atan2(mTouch.y - mBezierControl1.y,mTouch.x
- mBezierControl1.x);
}
// 翻起页阴影顶点与touch点的距离
double d1 = ( float ) 25 * 1.414 * Math.cos(degree);
double d2 = ( float ) 25 * 1.414 * Math.sin(degree);
float x = ( float )(mTouch.x + d1);
float y;
if (mIsRTandLB){
y = ( float )(mTouch.y + d2);
} else {
y = ( float )(mTouch.y - d2);
}
mPath1.reset();
mPath1.moveTo(x,y);
mPath1.lineTo(mTouch.x,mTouch.y);
mPath1.lineTo(mBezierControl1.x,mBezierControl1.y);
mPath1.lineTo(mBezierStart1.x,mBezierStart1.y);
mPath1.close();
float rotateDegrees;
canvas.save();
canvas.clipPath(mPath0,Region.Op.XOR);
canvas.clipPath(mPath1,Region.Op.INTERSECT);
int leftx;
int rightx;
GradientDrawablemCurrentPageShadow;
if (mIsRTandLB){
leftx = ( int )(mBezierControl1.x);
rightx = ( int )mBezierControl1.x + 25 ;
mCurrentPageShadow = mFrontShadowDrawableVLR;
} else {
leftx = ( int )(mBezierControl1.x - 25 );
rightx = ( int )mBezierControl1.x + 1 ;
mCurrentPageShadow = mFrontShadowDrawableVRL;
}
rotateDegrees = ( float )Math.toDegrees(Math.atan2(mTouch.x
- mBezierControl1.x,mBezierControl1.y - mTouch.y));
canvas.rotate(rotateDegrees,mBezierControl1.x,mBezierControl1.y);
mCurrentPageShadow.setBounds(leftx,
( int )(mBezierControl1.y - mMaxLength),rightx,
( int )(mBezierControl1.y));
mCurrentPageShadow.draw(canvas);
canvas.restore();
mPath1.reset();
mPath1.moveTo(x,y);
mPath1.lineTo(mTouch.x,mTouch.y);
mPath1.lineTo(mBezierControl2.x,mBezierControl2.y);
mPath1.lineTo(mBezierStart2.x,mBezierStart2.y);
mPath1.close();
canvas.save();
canvas.clipPath(mPath0,Region.Op.XOR);
canvas.clipPath(mPath1,Region.Op.INTERSECT);
if (mIsRTandLB){
leftx = ( int )(mBezierControl2.y);
rightx = ( int )(mBezierControl2.y + 25 );
mCurrentPageShadow = mFrontShadowDrawableHTB;
} else {
leftx = ( int )(mBezierControl2.y - 25 );
rightx = ( int )(mBezierControl2.y + 1 );
mCurrentPageShadow = mFrontShadowDrawableHBT;
}
rotateDegrees = ( float )Math.toDegrees(Math.atan2(mBezierControl2.y
- mTouch.y,mBezierControl2.x - mTouch.x));
canvas.rotate(rotateDegrees,mBezierControl2.x,mBezierControl2.y);
float temp;
if (mBezierControl2.y < 0 )
temp = mBezierControl2.y - mHeight;
else
temp = mBezierControl2.y;
int hmg = ( int )Math.hypot(mBezierControl2.x,temp);
if (hmg > mMaxLength)
mCurrentPageShadow
.setBounds(( int )(mBezierControl2.x - 25 ) - hmg,leftx,
( int )(mBezierControl2.x + mMaxLength) - hmg,
rightx);
else
mCurrentPageShadow.setBounds(
( int )(mBezierControl2.x - mMaxLength),leftx,
( int )(mBezierControl2.x),rightx);
// Log.i("hmg","mBezierControl2.x"+mBezierControl2.x
// +"mBezierControl2.y"+mBezierControl2.y);
mCurrentPageShadow.draw(canvas);
canvas.restore();
}
/**
*Author:hmg25Version:1.0Description:绘制翻起页背面
*/
private void drawCurrentBackArea(Canvascanvas,Bitmapbitmap){
int i = ( int )(mBezierStart1.x + mBezierControl1.x) / 2 ;
float f1 = Math.abs(i - mBezierControl1.x);
int i1 = ( int )(mBezierStart2.y + mBezierControl2.y) / 2 ;
float f2 = Math.abs(i1 - mBezierControl2.y);
float f3 = Math.min(f1,f2);
mPath1.reset();
mPath1.moveTo(mBeziervertex2.x,mBeziervertex2.y);
mPath1.lineTo(mBeziervertex1.x,mBeziervertex1.y);
mPath1.lineTo(mBezierEnd1.x,mBezierEnd1.y);
mPath1.lineTo(mTouch.x,mTouch.y);
mPath1.lineTo(mBezierEnd2.x,mBezierEnd2.y);
mPath1.close();
GradientDrawablemFolderShadowDrawable;
int left;
int right;
if (mIsRTandLB){
left = ( int )(mBezierStart1.x - 1 );
right = ( int )(mBezierStart1.x + f3 + 1 );
mFolderShadowDrawable = mFolderShadowDrawableLR;
} else {
left = ( int )(mBezierStart1.x - f3 - 1 );
right = ( int )(mBezierStart1.x + 1 );
mFolderShadowDrawable = mFolderShadowDrawableRL;
}
canvas.save();
canvas.clipPath(mPath0);
canvas.clipPath(mPath1,Region.Op.INTERSECT);
mPaint.setColorFilter(mColorMatrixFilter);
float dis = ( float )Math.hypot(mCornerX - mBezierControl1.x,
mBezierControl2.y - mCornerY);
float f8 = (mCornerX - mBezierControl1.x) / dis;
float f9 = (mBezierControl2.y - mCornerY) / dis;
mMatrixArray[ 0 ] = 1 - 2 * f9 * f9;
mMatrixArray[ 1 ] = 2 * f8 * f9;
mMatrixArray[ 3 ] = mMatrixArray[ 1 ];
mMatrixArray[ 4 ] = 1 - 2 * f8 * f8;
mMatrix.reset();
mMatrix.setValues(mMatrixArray);
mMatrix.preTranslate( - mBezierControl1.x, - mBezierControl1.y);
mMatrix.postTranslate(mBezierControl1.x,mBezierControl1.y);
canvas.drawBitmap(bitmap,mMatrix,mPaint);
// canvas.drawBitmap(bitmap,mMatrix,null);
mPaint.setColorFilter( null );
canvas.rotate(mDegrees,mBezierStart1.x,mBezierStart1.y);
mFolderShadowDrawable.setBounds(left,( int )mBezierStart1.y,right,
( int )(mBezierStart1.y + mMaxLength));
mFolderShadowDrawable.draw(canvas);
canvas.restore();
}
public void computeScroll(){
super .computeScroll();
if (mScroller.computeScrollOffset()){
float x = mScroller.getCurrX();
float y = mScroller.getCurrY();
mTouch.x = x;
mTouch.y = y;
postInvalidate();
}
}
private void startAnimation( int delayMillis){
int dx,dy;
// dx水平方向滑动的距离,负值会使滚动向左滚动
// dy垂直方向滑动的距离,负值会使滚动向上滚动
if (mCornerX > 0 ){
dx = - ( int )(mWidth + mTouch.x);
} else {
dx = ( int )(mWidth - mTouch.x + mWidth);
}
if (mCornerY > 0 ){
dy = ( int )(mHeight - mTouch.y);
} else {
dy = ( int )( 1 - mTouch.y); // 防止mTouch.y最终变为0
}
mScroller.startScroll(( int )mTouch.x,( int )mTouch.y,dx,dy,
delayMillis);
}
public void abortAnimation(){
if ( ! mScroller.isFinished()){
mScroller.abortAnimation();
}
}
public boolean canDragOver(){
if (mTouchToCornerDis > mWidth / 10 )
return true ;
return false ;
}
/**
*Author:hmg25Version:1.0Description:是否从左边翻向右边
*/
public boolean DragToRight(){
if (mCornerX > 0 )
return false ;
return true ;
}
}
/**
*Author:hmg25
*Description:
*/
package sf.hmg.turntest;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;
import java.util.Vector;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
public class BookPageFactory{
private Filebook_file = null ;
private MappedByteBufferm_mbBuf = null ;
private int m_mbBufLen = 0 ;
private int m_mbBufBegin = 0 ;
private int m_mbBufEnd = 0 ;
private Stringm_strCharsetName = " GBK " ;
private Bitmapm_book_bg = null ;
private int mWidth;
private int mHeight;
private Vector < String > m_lines = new Vector < String > ();
private int m_fontSize = 24 ;
private int m_textColor = Color.BLACK;
private int m_backColor = 0xffff9e85 ; // 背景颜色
private int marginWidth = 15 ; // 左右与边缘的距离
private int marginHeight = 20 ; // 上下与边缘的距离
private int mLineCount; // 每页可以显示的行数
private float mVisibleHeight; // 绘制内容的宽
private float mVisibleWidth; // 绘制内容的宽
private boolean m_isfirstPage,m_islastPage;
// privateintm_nLineSpaceing=5;
private PaintmPaint;
public BookPageFactory( int w, int h){
// TODOAuto-generatedconstructorstub
mWidth = w;
mHeight = h;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setTextAlign(Align.LEFT);
mPaint.setTextSize(m_fontSize);
mPaint.setColor(m_textColor);
mVisibleWidth = mWidth - marginWidth * 2 ;
mVisibleHeight = mHeight - marginHeight * 2 ;
mLineCount = ( int )(mVisibleHeight / m_fontSize); // 可显示的行数
}
public void openbook(StringstrFilePath) throws IOException{
book_file = new File(strFilePath);
long lLen = book_file.length();
m_mbBufLen = ( int )lLen;
m_mbBuf = new RandomAccessFile(book_file, " r " ).getChannel().map(
FileChannel.MapMode.READ_ONLY, 0 ,lLen);
}
protected byte []readParagraphBack( int nFromPos){
int nEnd = nFromPos;
int i;
byte b0,b1;
if (m_strCharsetName.equals( " UTF-16LE " )){
i = nEnd - 2 ;
while (i > 0 ){
b0 = m_mbBuf.get(i);
b1 = m_mbBuf.get(i + 1 );
if (b0 == 0x0a && b1 == 0x00 && i != nEnd - 2 ){
i += 2 ;
break ;
}
i -- ;
}
} else if (m_strCharsetName.equals( " UTF-16BE " )){
i = nEnd - 2 ;
while (i > 0 ){
b0 = m_mbBuf.get(i);
b1 = m_mbBuf.get(i + 1 );
if (b0 == 0x00 && b1 == 0x0a && i != nEnd - 2 ){
i += 2 ;
break ;
}
i -- ;
}
} else {
i = nEnd - 1 ;
while (i > 0 ){
b0 = m_mbBuf.get(i);
if (b0 == 0x0a && i != nEnd - 1 ){
i ++ ;
break ;
}
i -- ;
}
}
if (i < 0 )
i = 0 ;
int nParaSize = nEnd - i;
int j;
byte []buf = new byte [nParaSize];
for (j = 0 ;j < nParaSize;j ++ ){
buf[j] = m_mbBuf.get(i + j);
}
return buf;
}
// 读取上一段落
protected byte []readParagraphForward( int nFromPos){
int nStart = nFromPos;
int i = nStart;
byte b0,b1;
// 根据编码格式判断换行
if (m_strCharsetName.equals( " UTF-16LE " )){
while (i < m_mbBufLen - 1 ){
b0 = m_mbBuf.get(i ++ );
b1 = m_mbBuf.get(i ++ );
if (b0 == 0x0a && b1 == 0x00 ){
break ;
}
}
} else if (m_strCharsetName.equals( " UTF-16BE " )){
while (i < m_mbBufLen - 1 ){
b0 = m_mbBuf.get(i ++ );
b1 = m_mbBuf.get(i ++ );
if (b0 == 0x00 && b1 == 0x0a ){
break ;
}
}
} else {
while (i < m_mbBufLen){
b0 = m_mbBuf.get(i ++ );
if (b0 == 0x0a ){
break ;
}
}
}
int nParaSize = i - nStart;
byte []buf = new byte [nParaSize];
for (i = 0 ;i < nParaSize;i ++ ){
buf[i] = m_mbBuf.get(nFromPos + i);
}
return buf;
}
protected Vector < String > pageDown(){
StringstrParagraph = "" ;
Vector < String > lines = new Vector < String > ();
while (lines.size() < mLineCount && m_mbBufEnd < m_mbBufLen){
byte []paraBuf = readParagraphForward(m_mbBufEnd); // 读取一个段落
m_mbBufEnd += paraBuf.length;
try {
strParagraph = new String(paraBuf,m_strCharsetName);
} catch (UnsupportedEncodingExceptione){
// TODOAuto-generatedcatchblock
e.printStackTrace();
}
StringstrReturn = "" ;
if (strParagraph.indexOf( " \r\n " ) != - 1 ){
strReturn = " \r\n " ;
strParagraph = strParagraph.replaceAll( " \r\n " , "" );
} else if (strParagraph.indexOf( " \n " ) != - 1 ){
strReturn = " \n " ;
strParagraph = strParagraph.replaceAll( " \n " , "" );
}
if (strParagraph.length() == 0 ){
lines.add(strParagraph);
}
while (strParagraph.length() > 0 ){
int nSize = mPaint.breakText(strParagraph, true ,mVisibleWidth,
null );
lines.add(strParagraph.substring( 0 ,nSize));
strParagraph = strParagraph.substring(nSize);
if (lines.size() >= mLineCount){
break ;
}
}
if (strParagraph.length() != 0 ){
try {
m_mbBufEnd -= (strParagraph + strReturn)
.getBytes(m_strCharsetName).length;
} catch (UnsupportedEncodingExceptione){
// TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
return lines;
}
protected void pageUp(){
if (m_mbBufBegin < 0 )
m_mbBufBegin = 0 ;
Vector < String > lines = new Vector < String > ();
StringstrParagraph = "" ;
while (lines.size() < mLineCount && m_mbBufBegin > 0 ){
Vector < String > paraLines = new Vector < String > ();
byte []paraBuf = readParagraphBack(m_mbBufBegin);
m_mbBufBegin -= paraBuf.length;
try {
strParagraph = new String(paraBuf,m_strCharsetName);
} catch (UnsupportedEncodingExceptione){
// TODOAuto-generatedcatchblock
e.printStackTrace();
}
strParagraph = strParagraph.replaceAll( " \r\n " , "" );
strParagraph = strParagraph.replaceAll( " \n " , "" );
if (strParagraph.length() == 0 ){
paraLines.add(strParagraph);
}
while (strParagraph.length() > 0 ){
int nSize = mPaint.breakText(strParagraph, true ,mVisibleWidth,
null );
paraLines.add(strParagraph.substring( 0 ,nSize));
strParagraph = strParagraph.substring(nSize);
}
lines.addAll( 0 ,paraLines);
}
while (lines.size() > mLineCount){
try {
m_mbBufBegin += lines.get( 0 ).getBytes(m_strCharsetName).length;
lines.remove( 0 );
} catch (UnsupportedEncodingExceptione){
// TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
m_mbBufEnd = m_mbBufBegin;
return ;
}
protected void prePage() throws IOException{
if (m_mbBufBegin <= 0 ){
m_mbBufBegin = 0 ;
m_isfirstPage = true ;
return ;
} else m_isfirstPage = false ;
m_lines.clear();
pageUp();
m_lines = pageDown();
}
public void nextPage() throws IOException{
if (m_mbBufEnd >= m_mbBufLen){
m_islastPage = true ;
return ;
} else m_islastPage = false ;
m_lines.clear();
m_mbBufBegin = m_mbBufEnd;
m_lines = pageDown();
}
public void onDraw(Canvasc){
if (m_lines.size() == 0 )
m_lines = pageDown();
if (m_lines.size() > 0 ){
if (m_book_bg == null )
c.drawColor(m_backColor);
else
c.drawBitmap(m_book_bg, 0 , 0 , null );
int y = marginHeight;
for (StringstrLine:m_lines){
y += m_fontSize;
c.drawText(strLine,marginWidth,y,mPaint);
}
}
float fPercent = ( float )(m_mbBufBegin * 1.0 / m_mbBufLen);
DecimalFormatdf = new DecimalFormat( " #0.0 " );
StringstrPercent = df.format(fPercent * 100 ) + " % " ;
int nPercentWidth = ( int )mPaint.measureText( " 999.9% " ) + 1 ;
c.drawText(strPercent,mWidth - nPercentWidth,mHeight - 5 ,mPaint);
}
public void setBgBitmap(BitmapBG){
m_book_bg = BG;
}
public boolean isfirstPage(){
return m_isfirstPage;
}
public boolean islastPage(){
return m_islastPage;
}
}
package sf.hmg.turntest;
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
public class turntest extends Activity{
/** Calledwhentheactivityisfirstcreated. */
private PageWidgetmPageWidget;
BitmapmCurPageBitmap,mNextPageBitmap;
CanvasmCurPageCanvas,mNextPageCanvas;
BookPageFactorypagefactory;
@Override
public void onCreate(BundlesavedInstanceState){
super .onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
mPageWidget = new PageWidget( this );
setContentView(mPageWidget);
mCurPageBitmap = Bitmap.createBitmap( 480 , 800 ,Bitmap.Config.ARGB_8888);
mNextPageBitmap = Bitmap
.createBitmap( 480 , 800 ,Bitmap.Config.ARGB_8888);
mCurPageCanvas = new Canvas(mCurPageBitmap);
mNextPageCanvas = new Canvas(mNextPageBitmap);
pagefactory = new BookPageFactory( 480 , 800 );
pagefactory.setBgBitmap(BitmapFactory.decodeResource(
this .getResources(),R.drawable.bg));
try {
pagefactory.openbook( " /sdcard/test.txt " );
pagefactory.onDraw(mCurPageCanvas);
} catch (IOExceptione1){
// TODOAuto-generatedcatchblock
e1.printStackTrace();
Toast.makeText( this , " 电子书不存在,请将《test.txt》放在SD卡根目录下 " ,
Toast.LENGTH_SHORT).show();
}
mPageWidget.setBitmaps(mCurPageBitmap,mCurPageBitmap);
mPageWidget.setOnTouchListener( new OnTouchListener(){
@Override
public boolean onTouch(Viewv,MotionEvente){
// TODOAuto-generatedmethodstub
boolean ret = false ;
if (v == mPageWidget){
if (e.getAction() == MotionEvent.ACTION_DOWN){
mPageWidget.abortAnimation();
mPageWidget.calcCornerXY(e.getX(),e.getY());
pagefactory.onDraw(mCurPageCanvas);
if (mPageWidget.DragToRight()){
try {
pagefactory.prePage();
} catch (IOExceptione1){
// TODOAuto-generatedcatchblock
e1.printStackTrace();
}
if (pagefactory.isfirstPage()) return false ;
pagefactory.onDraw(mNextPageCanvas);
} else {
try {
pagefactory.nextPage();
} catch (IOExceptione1){
// TODOAuto-generatedcatchblock
e1.printStackTrace();
}
if (pagefactory.islastPage()) return false ;
pagefactory.onDraw(mNextPageCanvas);
}
mPageWidget.setBitmaps(mCurPageBitmap,mNextPageBitmap);
}
ret = mPageWidget.doTouchEvent(e);
return ret;
}
return false ;
}
});
}
}
更多相关文章
- Android(安卓)三角标签(自定义Textview控件)
- android 图形开发实例
- Android直播系统平台搭建之图片实现阴影效果的方法小结
- Android实现图表绘制和展示
- Android之——自己定义TextView
- Android绘图之绘制太极图
- Android(安卓)中的 OpenGL 简单入门 (下)
- Android(安卓)开发Rect
- Android(安卓)Drawable