看书软件都会有很炫的翻页效果。一个好的看书软件,我想,它必须具备这些基本功能:
1、下载书籍
2、直接读取txt文件的内容
3、智能排版
4、智能计算出页数,看书进度
5、绚丽的翻页效果
6、可以拖动翻页和点击翻页
7、可以向前翻页,也可以向后翻页
8、书签功能
9、夜间模式
10、页面背景切换(如粉红浪漫背景,羊皮纸背景,蓝色夜空背景、护目背景等)
我从翻页效果开始研究。
这是第一个翻页效果的demo,非常的简单,只有二个功能:
1、手拖动页面实现垂直翻页
2、点击自动向前翻页和向后翻页
截图:
这个例子翻页的原理很简单,实际上就是在屏幕上绘制三个部分的图片:最上层页的正面部分,上层页的背面部分,底层页的正面部分。当然,因为拖动和自动翻的原因,有些部分显示有些部分不显示,如此就形成了翻页的效果。
代码如下:
入口Activity:MyPageTurnDemo01Activity,它就像一个容器装着PageView
/** * 翻页效果的第一个demo * @author haozi * */ public class MyPageTurnDemo01Activity extends Activity { private MyPageView mPageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 初始化View initMyPageView(); // 设置界面布局 setContentView(mPageView); } /** * 初始化View */ private void initMyPageView(){ Display display = getWindowManager().getDefaultDisplay(); int width = display.getWidth(); int height = display.getHeight(); mPageView = new MyPageView(this, width, height); } }
/** * 在上面显示一页一页的翻页 * @author haozi * */ public class MyPageView extends View { private Context context; private Bitmap foreBitmap; private Bitmap backBitmap; private Bitmap foreBitmapBack; private int width; private int height; private Paint mPaint; // 画笔 private PointF touchPointer; // 触摸点 private PointF movePointer; private GradientDrawable gradientDrawableRL; // 阴影从右到左渐变 private GradientDrawable gradientDrawableLR; // 阴影从左到右渐变 private Scroller mScroller; // 滚动器 private boolean flag; /** * 构造方法 * @param context 调用方的上下文 * @param width 设备的宽度,单位是像素 * @param height 设备的高度,单位是像素 */ public MyPageView(Context context, int width, int height) { super(context); this.context = context; this.width = width; this.height = height; // 初始化一些必须品 initSomething(); // 初始化第一张和第二张的页面 initForeAndBackPages(); } public MyPageView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public MyPageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } /** * 初始化画笔工具 */ private void initSomething(){ // 点击时候View能够获取焦点 setFocusableInTouchMode(true); // 初始化画笔 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // 初始化触摸点 touchPointer = new PointF(); movePointer = new PointF(); // 初始化阴影渐变,由亮到暗 int[] gradientColor = new int[]{0x00333333, 0xb0333333}; gradientDrawableLR = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, gradientColor); gradientDrawableRL = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, gradientColor); // 初始化滚动器,利用滚动条来实现接触点放开后的动画效果 mScroller = new Scroller(context); } /** * 初始化第一张和第二张的页面 */ private void initForeAndBackPages(){ // 第一张页面 Bitmap firstBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.first_page); foreBitmap = Bitmap.createScaledBitmap(firstBitmap, width, height, false); // 第二张页面 Bitmap secondBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.second_page); backBitmap = Bitmap.createScaledBitmap(secondBitmap, width, height, false); // 翻页的背面 Matrix m = new Matrix(); m.preScale(-1, 1); foreBitmapBack = Bitmap.createBitmap(foreBitmap, 0, 0, foreBitmap.getWidth(), foreBitmap.getHeight(), m, true); } @Override public void computeScroll() { if(mScroller.computeScrollOffset()){ movePointer.set(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } @Override protected void onDraw(Canvas canvas) { // 设置画笔,无锯齿 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); // 画前一页 canvas.drawBitmap(foreBitmap, 0, 0, mPaint); if(flag){// 触碰屏幕了 // 计算出对折点 float halfCut = movePointer.x + (width - movePointer.x)*4/10; // 画翻页的背面 canvas.save(); canvas.clipRect(movePointer.x, 0, halfCut, height); paint.setColorFilter(null); canvas.drawBitmap(foreBitmapBack, movePointer.x, 0, paint); canvas.restore(); // 画后一页翻开露出的部分 canvas.save(); canvas.clipRect(0, 0, halfCut, height); canvas.clipRect(halfCut, 0, width, height, Region.Op.REVERSE_DIFFERENCE); paint.setColorFilter(null); canvas.drawBitmap(backBitmap, 0, 0, paint); canvas.restore(); // 画出翻页对折处投下的阴影 // 对折处画左侧阴影 if((halfCut - movePointer.x) > 70){ gradientDrawableLR.setBounds((int)halfCut-70, 0, (int)halfCut, (int)height); }else{ gradientDrawableLR.setBounds((int)movePointer.x, 0, (int)halfCut, (int)height); } gradientDrawableLR.draw(canvas); // 对折处画右侧阴影 if((halfCut - movePointer.x) > 30){ gradientDrawableRL.setBounds((int)halfCut, 0, (int)halfCut + 30, (int)height); }else{ gradientDrawableRL.setBounds((int)halfCut, 0, (int)(2*halfCut - movePointer.x), (int)height); } gradientDrawableRL.draw(canvas); } } @Override public boolean onTouchEvent(MotionEvent event) { if(event.getAction() == MotionEvent.ACTION_DOWN){ flag = true; // 得到点击屏幕按下时候的触摸点坐标 touchPointer.x = event.getX(); touchPointer.y = event.getY(); }else if(event.getAction() == MotionEvent.ACTION_MOVE){ // 得到点击屏幕按下时候的触摸点坐标 float x = event.getX(); float y = event.getY(); movePointer.set(x, y); movePointer.set(x, y); postInvalidate(); }else if(event.getAction() == MotionEvent.ACTION_UP){ float endX = event.getX(); float endY = event.getY(); if(touchPointer.x > endX){ // 向左翻页 mScroller.startScroll((int)movePointer.x, (int)movePointer.y, (int)(-width-movePointer.x), 0, 1000); }else if(touchPointer.x < endX){ // 向右翻页 mScroller.startScroll((int)movePointer.x, (int)movePointer.y, (int)(width-movePointer.x), 0, 1000); }else if(touchPointer.x == endX && touchPointer.y == endY){// 点击翻页 if(touchPointer.x < width/2){// 向右翻 mScroller.startScroll((int)-width, (int)touchPointer.y, (int)2*width, 0, 1000); }else{// 向左翻 mScroller.startScroll((int)width, (int)touchPointer.y, (int)-2*width, 0, 1000); } } postInvalidate(); } return true; } }