在好例子网,分享、交流、成长!
您当前所在位置:首页Java 开发实例Android平台开发 → android 带翻页效果的电子杂志 附完整源码下载

android 带翻页效果的电子杂志 附完整源码下载

Android平台开发

下载此实例
  • 开发语言:Java
  • 实例大小:1.50M
  • 下载次数:32
  • 浏览次数:912
  • 发布时间:2013-08-07
  • 实例类别:Android平台开发
  • 发 布 人:crazycode
  • 文件格式:.rar
  • 所需积分:2
 相关标签: Android

实例介绍

【实例简介】电子杂志(带翻页效果)源码,效果非常逼真,想做电子书的朋友可以研究下
【实例截图】

【核心代码】

package com.xiexj.ebook;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.Shader;
import android.graphics.Paint.Style;
import android.graphics.Shader.TileMode;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;

public class SinglePage extends View {

	private boolean isLeftPage = false;
	
	private int pageNo;
	
	private int x;
	
	private int y;
	
	private int width;
	
	private int height;
	
	private Paint paint;
	
	private int dis = 10;
	
	//当前选中的角
	private int chooseCorner = -1;
	
	public static final int LEFT_UP_CORNER = 0;
	
	public static final int LEFT_BOTTOM_CORNER = 1;
	
	public static final int RIGHT_UP_CORNER = 2;
	
	public static final int RIGHT_BOTTOM_CORNER = 3;
	
	//A点的坐标是手指目前的坐标
	private float aX = -1;
	
	private float aY = -1;
	
	//B点的坐标是A点翻起后跟下一页的交叉点
	private float bX = -1;
	
	private float bY = -1;
	
	//C点的坐标是D点翻起后跟下一页的交叉点,可能与D点重复
	private float cX = -1;
	
	private float cY = -1;
	
	//D点的坐标是本页的另一个角的点的坐标
	private float dX = -1;
	
	private float dY = -1;
	
	//旋转的角度
	private float angle = 0;
	
	//翻动页背面的阴影角度
	private float shadowAngle = 0;
	
	//阴影长度
	private float shadowLength = 0;
	
	//阴影的坐标x
	private float sdx = 0;
	
	//阴影的坐标y
	private float sdy = 0;
	
	//是否隐藏层
	private boolean isMask;
	
	//是否是当前显示页
	private boolean isLookPage;
	
	//隐藏层的显示区域
	private Path maskPath;
	
	//翻动页的fx坐标
	private float fx;
	
	//翻动页的fy坐标
	private float fy;
	
	//背景色
	private int bc;
	
	//显示的角
	private int cr;
	
	private BookLayout blo;
	
	private PageContent content;
	
	public SinglePage(Context context,boolean isLeftPage,int pageNo,BookLayout blo,PageContent content) {
		super(context);
		this.isLeftPage = isLeftPage;
		this.pageNo = pageNo;
		this.blo = blo;
		this.content = content;
		paint = new Paint();
		bc = Color.WHITE;
		paint.setARGB(255, Color.red(bc), Color.green(bc), Color.blue(bc));
		paint.setAntiAlias(true);
		isMask = true;
		isLookPage = false;
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		//抗锯齿
		canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));  
		if(isMask){//如果是遮罩层
//			if(blo.getCurrentFlipPage()!=null&&this==blo.getMaskPage(blo.getCurrentFlipPage())){
//				Log.e("SinglePage", "------->pageNo:" pageNo);
//			}
			if(maskPath==null) return;
			float tx = 0;
			float ty = 0;
			switch(cr){
			case LEFT_UP_CORNER:{
				tx = fx;
				ty = fy;
				break;
			}
			case RIGHT_UP_CORNER:{
				tx = fx-width;
				ty = fy;
				break;
			}
			case LEFT_BOTTOM_CORNER:{
				tx = fx;
				ty = fy-height;
				break;
			}
			case RIGHT_BOTTOM_CORNER:{
				tx = fx-width;
				ty = fy-height;
				break;
			}
			}
			canvas.clipPath(maskPath);
			canvas.save();
			canvas.rotate(angle, fx, fy);
			paint.setStyle(Style.FILL);
			paint.setARGB(255, Color.red(bc), Color.green(bc), Color.blue(bc));
			canvas.drawRect(tx,ty,tx width,ty height, paint);
			content.setPosition(tx, ty);
			content.draw(canvas);
			paint.setStyle(Style.STROKE);
			paint.setARGB(255,0,0,0);
			canvas.drawRect(tx,ty,tx width,ty height, paint);
			if(content!=null&&content.isContentPage()){
				if(isLeftPage){
					canvas.drawText("第" (pageNo-1) "页", tx 5, ty height-5, paint);
				}else{
					canvas.drawText("第" (pageNo-1) "页", tx width-5-paint.measureText("第" (pageNo-1) "页"), ty height-5, paint);
				}
			}
			canvas.restore();
			canvas.save();
			canvas.rotate(shadowAngle, sdx, sdy);
			paint.setStyle(Style.FILL);
			shadowLength = (float)Math.sqrt(width*width height*height);
			if(isLeftPage){
				Shader linearShader = new LinearGradient(sdx-50,sdy,sdx,sdy,Color.argb(0, 0, 0, 0),Color.argb(33, 0, 0, 0),TileMode.CLAMP);
				paint.setShader(linearShader);
				canvas.drawRect(sdx-50, sdy, sdx, sdy shadowLength, paint);
			}else{
				Shader linearShader = new LinearGradient(sdx,sdy,sdx 50,sdy,Color.argb(33, 0, 0, 0),Color.argb(0, 0, 0, 0),TileMode.CLAMP);
				paint.setShader(linearShader);
				canvas.drawRect(sdx, sdy, sdx 50, sdy shadowLength, paint);
			}
			paint.setShader(null);
			canvas.restore();
		}else{//显示层
			Path backPath = null;
			if(aX!=-1&&aY!=-1){
				backPath = new Path();
				backPath.moveTo(aX, aY);
				backPath.lineTo(bX, bY);
				backPath.lineTo(cX, cY);
				if(cX!=dX||cY!=dY){
					backPath.lineTo(dX, dY);
				}
				backPath.lineTo(aX, aY);
				float px = -1;
				float py = -1;
				float ox = -1;
				float oy = -1;
				float ex = -1;
				float ey = -1;
				switch(chooseCorner){
				case RIGHT_UP_CORNER:{
					px = x;
					py = y;
					ox = x;
					oy = y height;
					ex = x width;
					ey = y height;
					break;
				}
				case RIGHT_BOTTOM_CORNER:{
					px = x;
					py = y height;
					ox = x;
					oy = y;
					ex = x width;
					ey = y;
					break;
				}
				case LEFT_UP_CORNER:{
					px = width x;
					py = y;
					ox = width x;
					oy = height y;
					ex = x;
					ey = y height;
					break;
				}
				case LEFT_BOTTOM_CORNER:{
					px = width x;
					py = height y;
					ox = width x;
					oy = y;
					ex = x;
					ey = y;
					break;
				}
				}
				maskPath = new Path();
				maskPath.moveTo(bX, bY);
				maskPath.lineTo(px, py);
				maskPath.lineTo(ox, oy);
				if(cX==dX&&cY==dY){
					maskPath.lineTo(ex, ey);
				}
				maskPath.lineTo(cX, cY);
				maskPath.lineTo(bX, bY);
			}
			if(maskPath!=null){
				canvas.clipPath(maskPath);
				canvas.save();
			}
			paint.setStyle(Style.FILL);
			paint.setARGB(255, Color.red(bc), Color.green(bc), Color.blue(bc));
			canvas.drawRect(x,y,x width,y height, paint);
			paint.setARGB(255,0,0,0);		
			paint.setStyle(Style.STROKE);
			content.setPosition(x, y);
			canvas.drawRect(x,y,x width,y height, paint);
			content.draw(canvas);
			if(content!=null&&content.isContentPage()){
				if(isLeftPage){
					canvas.drawText("第" (pageNo-1) "页", x 5, y height-5, paint);
				}else{
					canvas.drawText("第" (pageNo-1) "页", x width-5-paint.measureText("第" (pageNo-1) "页"), y height-5, paint);
				}
			}
			//显示书轴阴影
			paint.setStyle(Style.FILL);
			if(!blo.isFirstOrLastPage(this)){
				if(isLeftPage){
					Shader linearShader = new LinearGradient(x width-50,y,x width,y,Color.argb(0, 0, 0, 0),Color.argb(33, 0, 0, 0),TileMode.CLAMP);
					paint.setShader(linearShader);
					canvas.drawRect(x width-50, y, x width, y height, paint);
				}else{
					Shader linearShader = new LinearGradient(x,y,x 50,y,Color.argb(33, 0, 0, 0),Color.argb(0, 0, 0, 0),TileMode.CLAMP);
					paint.setShader(linearShader);
					canvas.drawRect(x, y, x 50, y height, paint);
				}
				paint.setShader(null);
			}
			
			if(maskPath!=null){
				canvas.restore();
			}
			if(backPath!=null){
				float sdx = -1;
				float sdy = -1;
				if(bY>cY){
					sdy = cY;
					sdx = cX;
				}else{
					sdy = bY;
					sdx = bX;
				}
				blo.flipPage(this, backPath,angle,shadowAngle,aX,aY,sdx,sdy,chooseCorner);
			}
		}
	}
	
	/**
	 * 显示反页遮罩层的区域
	 * @param path
	 * @param angle
	 * @param x
	 * @param y
	 */
	public void onMaskPathDraw(Path path,float angle,float shadowAngle,float x,float y,float sdx,float sdy,int chooseCorner){
		this.maskPath = path;
		this.angle = angle;
		this.shadowAngle = shadowAngle;
		this.fx = x;
		this.fy = y;
		this.sdx = sdx;
		this.sdy = sdy;
		switch(chooseCorner){
		case LEFT_UP_CORNER:{
			cr = RIGHT_UP_CORNER;
			break;
		}
		case RIGHT_UP_CORNER:{
			cr = LEFT_UP_CORNER;
			break;
		}
		case LEFT_BOTTOM_CORNER:{
			cr = RIGHT_BOTTOM_CORNER;
			break;
		}
		case RIGHT_BOTTOM_CORNER:{
			cr = LEFT_BOTTOM_CORNER;
			break;
		}
		}
		postInvalidate();
	}
	
	public void setSize(int w,int h){
		width = w;
		height = h;
		content.setSize(width, height);
	}
	
	public void setPosition(int x,int y){
		this.x = x;
		this.y = y;
		fx = x;
		fy = y;
	}
	
	public void setBackgroundColor(int color){
		this.bc = color;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if(!isLookPage||blo.isAutoFlip()){
			return false;
		}
		int act = event.getAction();
		float hx = event.getX();
		float hy = event.getY();
		switch(act){
		case MotionEvent.ACTION_DOWN:{
			if(isNearCorner(hx, hy)&&isEnableChoose(hx, hy)){
				//初始化翻页的角度
				aX = hx;
				aY = hy;
				calculate();
				postInvalidate();
				blo.setCurrentFlipPage(this);
			}
			break;
		}
		case MotionEvent.ACTION_MOVE:{
			if(chooseCorner!=-1&&isEnableChoose(hx, hy)){
				aX = hx;
				aY = hy;
				calculate();
				postInvalidate();
			}
			break;
		}
		case MotionEvent.ACTION_UP:{
			if(chooseCorner!=-1){
				successOrResetPage();
			}
			break;
		}
		}
		if(chooseCorner==-1){
			return false;
		}
		return true;
	}
	
	//判断是否在页角附近
	private boolean isNearCorner(float hx,float hy){
		//左上角
		int lux = x;
		int luy = y;
		
		//左下角
		int lbx = x;
		int lby = y height;
		
		//右上角
		int rux = x width;
		int ruy = y;
		
		//右下角
		int rbx = x width;
		int rby = y height;
		int[][] pd = {
				{lux,luy},
				{lbx,lby},
				{rux,ruy},
				{rbx,rby}
		};
		for(int i=0;i<pd.length;i  ){
			//计算是否在页角附近,并返回是哪个页角
			if(isLeftPage){
				if(i>=2) continue;
			}else{
				if(i<2) continue;
			}
			if((pd[i][0]-hx)*(pd[i][0]-hx) (pd[i][1]-hy)*(pd[i][1]-hy)<=2*dis*dis){
				chooseCorner = i;
				return true;
			}
		}
		return false;
	}

	//判断是否是有效的翻页坐标
	private boolean isEnableChoose(float hx,float hy){
		boolean flag = false;
		switch(chooseCorner){
		case LEFT_UP_CORNER:{
			if((hx-(width x))*(hx-(width x)) (hy-y)*(hy-y)<=width*width && (hx-(width x))*(hx-(width x)) (hy-(height y))*(hy-(height y))<=width*width height*height){
				flag = true;
			}
			break;
		}
		case LEFT_BOTTOM_CORNER:{
			if((hx-(width x))*(hx-(width x)) (hy-(height y))*(hy-(height y))<=width*width && (hx-(width x))*(hx-(width x)) (hy-y)*(hy-y)<=width*width height*height){
				flag = true;
			}
			break;
		}
		case RIGHT_UP_CORNER:{
			if((hx-x)*(hx-x) (hy-y)*(hy-y)<=width*width && (hx-x)*(hx-x) (hy-(height y))*(hy-(height y))<=width*width height*height){
				flag = true;
			}
			break;
		}
		case RIGHT_BOTTOM_CORNER:{
			if((hx-x)*(hx-x) (hy-(height y))*(hy-(height y))<=width*width && (hx-x)*(hx-x) (hy-y)*(hy-y)<=width*width height*height){
				flag = true;
			}
			break;
		}
		}
//		Log.e("Page","isEnableChoose " flag);
		return flag;
	}
	
	//判断是否成功翻页还是取消翻页
	private void successOrResetPage(){
		float sx = -1;
		float sy = -1;
		float fx = -1;
		float fy = -1;
		
		//手松开的时候,如果另一侧的角翻动幅度更大的话,以那个角作为A点,启动自动翻书动作
		if(isLeftPage){
			if(dX>aX){
				aX = dX;
				aY = dY;
				if(chooseCorner==LEFT_UP_CORNER){
					chooseCorner = LEFT_BOTTOM_CORNER;
				}else{
					chooseCorner = LEFT_UP_CORNER;
				}
			}
		}else{
			if(dX<aX){
				aX = dX;
				aY = dY;
				if(chooseCorner==RIGHT_UP_CORNER){
					chooseCorner = RIGHT_BOTTOM_CORNER;
				}else{
					chooseCorner = RIGHT_UP_CORNER;
				}
			}
		}
		calculate();
		
		//计算成功或失败翻页后,被触碰的页角需要达到的坐标
		switch(chooseCorner){
		case LEFT_UP_CORNER:{
			sx = x width*2;
			sy = y;
			fx = x;
			fy = y;
			break;
		}
		case LEFT_BOTTOM_CORNER:{
			sx = x width*2;
			sy = y height;
			fx = x;
			fy = y height;
			break;
		}
		case RIGHT_UP_CORNER:{
			sx = x-width;
			sy = y;
			fx = x width;
			fy = y;
			break;
		}
		case RIGHT_BOTTOM_CORNER:{
			sx = x-width;
			sy = y height;
			fx = x width;
			fy = y height;
			break;
		}
		}
		if(isLeftPage&&(aX>=x width*3/2||dX>=x width*3/2)){
			autoFlipPage(sx, sy, true);
		}else if(!isLeftPage&&(aX<=x-width/2||dX<=x-width/2)){
			autoFlipPage(sx, sy, true);
		}else{
			autoFlipPage(fx,fy,false);
		}
	}
	
	//当在翻页过程中,手松开页角的时候,自动执行翻页动作,让翻页更真实
	private void autoFlipPage(final float tx,final float ty,final boolean isSuccessFlip){
		blo.setAutoFlip(true);
		new Thread(){
			public void run(){
				int count = 1;
				boolean flag = false;
				while(true){
					try {
						flag=autoMovePageCorner(tx, ty,count  );
						Thread.sleep(100);
						if(flag) break;
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				//清除翻页参数
				chooseCorner = -1;
				clearPosition();
				if(isSuccessFlip){
					handler.post(new Runnable(){
						public void run(){
							blo.setCurrentFlipPage(null);
							blo.successFlipPage(SinglePage.this, true);
						}
					});
				}else{
					handler.post(new Runnable(){
						public void run(){
							blo.setCurrentFlipPage(null);
							blo.successFlipPage(SinglePage.this, false);
						}
					});
				}
				blo.setAutoFlip(false);
			}
		}.start();
	}
	
	private Handler handler = new Handler();
	
	//线程内部,自动移动页角
	private boolean autoMovePageCorner(float tx,float ty,int num){
		boolean isFinish = false;
		if((aX-tx)*(aX-tx) (aY-ty)*(aY-ty)<=dis*dis){
			isFinish = true;
		}else{
			handler.post(new Runnable(){
				public void run(){
					postInvalidate();
				}
			});
			aX = aX-num*(aX-tx)/10;
			aY = aY-num*(aY-ty)/10;
			calculate();
		}
		return isFinish;
	}
	
	//根据A点计算其余点
	private void calculate(){
		float px = -1;
		float py = -1;
		float ox = -1;
		float oy = -1;
		switch(chooseCorner){
		case LEFT_UP_CORNER:{
			px = x;
			py = y;
			ox = x;
			oy = y height;
			bY = y;
			cX = x;
			cY = y height;
			break;
		}
		case LEFT_BOTTOM_CORNER:{
			px = x;
			py = y height;
			ox = x;
			oy = y;
			bY = y height;
			cX = x;
			cY = y;
			break;
		}
		case RIGHT_UP_CORNER:{
			px = width x;
			py = y;
			ox = width x;
			oy = height y;
			bY = y;
			cX = x width;
			cY = y height;
			break;
		}
		case RIGHT_BOTTOM_CORNER:{
			px = width x;
			py = height y;
			ox = width x;
			oy = y;
			bY = y height;
			cX = x width;
			cY = y;
			break;
		}
		}
		if(aY==py){
			bY = aY;
			bX = (aX px)/2;
			dY = oy;
			dX = aX;
			cX = (aX ox)/2;
			cY = oy;
			angle = 0;
			return;
		}
		MNLine lineOne = MNLine.initLine(aX, aY, px, py);
		MNLine lineTwo = lineOne.getPBLine((aX px)/2, (aY py)/2);
		bX = lineTwo.getXbyY(bY);
		float tempCY = lineTwo.getYbyX(cX);
		if(tempCY>=y&&tempCY<=y height){//在左或右边交叉,是三角型,
			cY = tempCY;
			dX = cX;
			dY = cY;
		}else{
			cX = lineTwo.getXbyY(cY);
			//将直线平移,经过页的另一个角
			lineOne.change(ox, oy);
			float[] xAndY = lineOne.getCross(lineTwo);
			dX = 2*xAndY[0]-ox;
			dY = 2*xAndY[1]-oy;
		}
		if(((Float)bX).isNaN()||((Float)bY).isNaN()||((Float)cX).isNaN()||((Float)cY).isNaN()||((Float)dX).isNaN()||((Float)dY).isNaN()){
			clearPosition();
		}else{
			MNLine lineThree = MNLine.initLine(aX, aY, dX, dY);
			angle = (float)(Math.atan(lineThree.getA())*180/Math.PI);
			if(angle>0){
				if(aX<=dX&&aY<=dY&&chooseCorner==RIGHT_BOTTOM_CORNER){
					angle = 90 angle;
				}else if(aX>=dX&&aY>=dY&&chooseCorner==LEFT_UP_CORNER){
					angle = 90 angle;
				}else{
					angle = angle-90;
				}
			}else{
				if(aX<=dX&&aY>=dY&&chooseCorner==RIGHT_UP_CORNER){
					angle = -90 angle;
				}else if(aX>=dX&&aY<=dY&&chooseCorner==LEFT_BOTTOM_CORNER){
					angle = -90 angle;
				}else{
					angle = angle 90;
				}
			}
			shadowAngle = (float)(Math.atan(lineTwo.getA())*180/Math.PI);
			if(shadowAngle>0){
				shadowAngle = shadowAngle-90;
			}else{
				shadowAngle = shadowAngle 90;
			}
		}
	}
	
	public void setMaskPage(boolean flag){
		isMask = flag;
	}
	
	public void setLookPage(boolean flag){
		isLookPage = flag;
		isMask = !flag;
	}
	
	public void reset(){
		clearPosition();
		angle = 0;
		shadowAngle = 0;
		shadowLength = 0;
		fx = x;
		fy = y;
		sdx = -1;
		sdy = -1;
		cr = -1;
		maskPath = null;
		isMask = true;
		isLookPage = false;
	}
	
	public PageContent getPageContent(){
		return content;
	}
	
	private void clearPosition(){
		aX = -1;
		aY = -1;
		bX = -1;
		bY = -1;
		cX = -1;
		cY = -1;
		dX = -1;
		dY = -1;
	}
}

标签: Android

实例下载地址

android 带翻页效果的电子杂志 附完整源码下载

不能下载?内容有错? 点击这里报错 + 投诉 + 提问

好例子网口号:伸出你的我的手 — 分享

网友评论

发表评论

(您的评论需要经过审核才能显示)

查看所有0条评论>>

小贴士

感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。

  • 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
  • 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
  • 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
  • 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。

关于好例子网

本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明

;
报警