2014-11-6Android学习------Android 仿真翻页效果实现--------贝塞尔曲线(二)

写一篇文章很辛苦啊!!!

转载请注明,联系请邮件[email protected]


我学习Android都是结合源代码去学习,这样比较直观,非常清楚的看清效果,觉得很好,今天的学习源码是网上找的源码 百度搜就知道很多下载的地方  网上源码的名字叫:Android仿真翻页效果.zip我的博客写的比较乱,如果本篇文章没有看懂,

请先看上篇文章,地址:http://blog.csdn.net/u014737138/article/details/40898293


要想实现一种翻页的效果,就是当我的手指点在手机界面上的时候能够像翻书那样有一种很直观的效果,要想实现这样的效果,

首先必须要知道一个知识点,就是:渐变式的背景    GradientDrawable

关于这个类有一些常量:

GradientDrawable.Orientation BL_TR                从绘制渐变左下到右上
GradientDrawable.Orientation BOTTOM_TOP   绘制渐变,从底部到顶部
GradientDrawable.Orientation BR_TL                从右下角到左上角的绘制渐变
GradientDrawable.Orientation LEFT_RIGHT      绘制渐变从左侧到右侧
GradientDrawable.Orientation RIGHT_LEFT      从向左右侧绘制渐变
GradientDrawable.Orientation TL_BR               绘制渐变,从左上角向右下角
GradientDrawable.Orientation TOP_BOTTOM   从顶部至底部绘制渐变
GradientDrawable.Orientation TR_BL               从右上角到左下角的绘制渐变

我们首先看看效果,然后你就有明显的感受了:

2014-11-6Android学习------Android 仿真翻页效果实现--------贝塞尔曲线(二)_第1张图片2014-11-6Android学习------Android 仿真翻页效果实现--------贝塞尔曲线(二)_第2张图片

通过这幅图片,大家应该有很直观的印象了,知道什么是渐变式背景了把

接下来我们就是如何去实现这样的效果

1.首先我们要知道,我们能够从很多地方翻页,从左上角开始,右上角开始,左下角,右下角,

我们翻到什么位置,就是对应的这个四个角,

2.我们必须要知道,当我们翻页的时候,其实是出现了三种概念上的阴影效果:前面的,后面的,以及被夹在中间的

用上面的图我们可以看到三种主调色:黄,绿,灰  他们分别对应着前,后,中间的色彩,

另外这个阴影色是渐变的,它有中立体感

3.知道了这三种状态下的阴影,但是方向还没有确定,所以这里就是一种组合形式的渐变式背景了,例如,前面阴影从左下到右上

如此一来,我们就必须先定义这些变量了:

GradientDrawable mBackShadowDrawableLR;//后面的阴影效果,从左边到右边
GradientDrawable mBackShadowDrawableRL;//后面的阴影效果,从右边到左边
GradientDrawable mFolderShadowDrawableLR;//夹在中间的阴影效果,从左边到右边
GradientDrawable mFolderShadowDrawableRL;//夹在中间的阴影效果,从右边到左边

GradientDrawable mFrontShadowDrawableHBT;//前面的阴影效果,右下角到左上角
GradientDrawable mFrontShadowDrawableHTB;//前面的阴影效果,从左上到右下
GradientDrawable mFrontShadowDrawableVLR;//前面的阴影效果,从左到右
GradientDrawable mFrontShadowDrawableVRL;//前面的阴影效果,从右到左

当我们把这些变量定义出来了,我们就需要去初始化它,

public GradientDrawable (GradientDrawable.Orientation orientation, int[] colors)
Create a new gradient drawable given an orientation and an array of colors for the gradient.

参数:常量orientation代表渐变的效果模式,colors数组,代表渐变的颜色,从什么颜色到什么颜色

这样一来,我们还需要先定义一个颜色的数组,类型为int

int[] mBackShadowColors;//后面的阴影颜色
int[] mFrontShadowColors;//前面的阴影颜色

接下来事先确定他们的颜色:黄 绿 灰

0x80888888, 0x888888 
0xFF111111, 0x111111
0x333333, 0xB0333333

接下来就是去写构造这些渐变式背景的函数了:

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[] { 0x80888888, 0x888888 };
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);
}


好了,上面的代码就处理完我们需要预定的背景了

二.接下来首先需要考虑的是,如何把这些背景画到画布上去呢。前面的知识点都说了,要想把这些背景画到画布上去,需要一个

位图对象,Bitmap,这里比较特殊,我们需要画三个位图,分别对应着前,后,中间,

1.那么我们需要去定义这三个位图变量

Bitmap mCurPageBitmap = null; // 前面,当前页,黄色
Bitmap mCurPageBackBitmap = null;//夹在中间的的,灰色
Bitmap mNextPageBitmap = null;//后面的 绿色

设置函数:作用不大,基本用不上

public void setBitmaps(Bitmap bm1, Bitmap bm2, Bitmap bm3) {
mCurPageBitmap = bm1;
mCurPageBackBitmap = bm2;
mNextPageBitmap = bm3;
}

2.接下来还需要画笔 画布 路径 等相关变量

private Bitmap mBitmap;//打开界面时的视图,上面的三个位图都是在这个初始的位图上绘制出来
private Canvas mCanvas;//画布
private Paint mBitmapPaint;//画位图的画笔
Paint paint;//手指拖到翻页就是画一条曲线

private Path mPath0;//路径0  对应当前页  灰色的路径
private Path mPath1;//路径1  对应前面的页 黄色的路径

3.接下来需要定义的是坐标,手指触摸事件的触发是通过坐标的改变来画出这个曲线的

private int mCornerX = 0; // 拖拽点对应的页脚 这个变量表示翻页的起始点对应的四个角的坐标,界面上四个角
private int mCornerY = 0;

float mMiddleX;//代表界面宽度的一半,他们是用来判断页脚坐标的
float mMiddleY;//代表高度的一半,

        float mDegrees;//角度,主要是显示的时候那种立体的角度,也就是页脚坐标和你手指拖动的过程中会产生角度,很重要

4.定义贝塞尔曲线需要的坐标点:

PointF mTouch = new PointF(); // 拖拽点,
PointF mBezierStart1 = new PointF(); // 贝塞尔曲线起始点。第一条贝塞尔曲线对应的是黄色 前面的
PointF mBezierControl1 = new PointF(); // 贝塞尔曲线控制点
PointF mBeziervertex1 = new PointF(); // 贝塞尔曲线顶点
PointF mBezierEnd1 = new PointF(); // 贝塞尔曲线结束点


PointF mBezierStart2 = new PointF(); // 另一条贝塞尔曲线  对应的是绿色 后面的
PointF mBezierControl2 = new PointF();
PointF mBeziervertex2 = new PointF();
PointF mBezierEnd2 = new PointF();

5.默认创造的位图的高宽, 也就是你模拟器的类型吧
private int mWidth = 480;
private int mHeight = 800;

6.要计算出手指触到的坐标到页脚坐标的直线距离,需要用到一个变量

float mTouchToCornerDis;

这个变量的初始化为:

mTouchToCornerDis = (float) Math.hypot((mTouch.x - mCornerX),(mTouch.y - mCornerY));

这个数学函数的意思是:java.lang.Math.hypot(double x, double y) 返回sqrt(x2 +y2没有中间的上溢或下溢

这个变量对画贝塞尔曲线有参考作用:

7.还需要一个判断是不是特定方向的变量

boolean mIsRTandLB; // 是否属于右上左下


三.变量定义完之后我们就需要初始化

1.由于我们当前的类是继承View类的,有两件事要干,第一:构造函数需要重写,第二:重载onDraw()函数

构造函数:

public PageWidget(Context context) {
super(context);
// TODO Auto-generated constructor stub
mPath0 = new Path();//灰色。夹在中间的贝塞尔曲线路径的初始化
mPath1 = new Path();//黄色,前面的贝塞尔曲线路径的初始化
createDrawable();//渐变式位图的初始化
// ---------------------------------------
mBitmap = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);//创造视图的背景
mCanvas = new Canvas(mBitmap);//在这个背景上加载画布
mBitmapPaint = new Paint(Paint.DITHER_FLAG);//在画布上绘制背景的画笔


mCurPageBitmap = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);//黄色的位图
Canvas canvas = new Canvas(mCurPageBitmap);//在位图上加载画布
paint = new Paint();//这个位图上需要一个画笔
canvas.drawColor(Color.YELLOW);//设置颜色为黄色
canvas.drawBitmap(mCurPageBitmap, 0, 0, paint);//把当前的位图画上去


mNextPageBitmap = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);//绿色的位图
canvas = new Canvas(mNextPageBitmap);//在这个位图上加载画布
canvas.drawColor(Color.GREEN);//设置颜色为绿色
canvas.drawBitmap(mNextPageBitmap, 0, 0, paint);//把这个位图画出来
}

onDraw():

@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);//设置画布的颜色
calcPoints();//计算坐标点,也就是给两个贝塞尔路径曲线的各个坐标进行初始化已经跟踪,
drawCurrentPageArea(mCanvas, mCurPageBitmap, mPath0);//在黄色位图上画出对应贝塞尔曲线
drawNextPageAreaAndShadow(mCanvas, mNextPageBitmap);//在绿色位图上画对阴影效果
drawCurrentPageShadow(mCanvas);//黄色位图上也有阴影效果
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);//在默认设置的位图上画上设计的位图
}

2.如何去确定坐标呢?首先是要找到这些坐标,然后再去计算贝塞尔曲线的各个坐标点

1)找到坐标,是需要做触摸监听事件处理的

@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
if (event.getAction() == MotionEvent.ACTION_MOVE) {//按下并拖动
mCanvas.drawColor(0xFFAAAAAA);//设置颜色
mTouch.x = event.getX();//拖动的x坐标
mTouch.y = event.getY();//拖动的y坐标
this.postInvalidate();//更新视图
}
if (event.getAction() == MotionEvent.ACTION_DOWN) {按下
mCanvas.drawColor(0xFFAAAAAA);
mTouch.x = event.getX();
mTouch.y = event.getY();
calcCornerXY(mTouch.x, mTouch.y);//如果按下了,我们需要去计算它对应的页脚坐标
this.postInvalidate();
}
if (event.getAction() == MotionEvent.ACTION_UP) {//松开
mCanvas.drawColor(0xFFAAAAAA);
mTouch.x = mCornerX;//松开之后x坐标回到页脚的x坐标
mTouch.y = mCornerY;//松开之后y坐标回到页脚的y坐标

// 其实这里还可以做其他的处理,松开之后实现成功翻页等等,
this.postInvalidate();
}
// return super.onTouchEvent(event);
return true;
}

2)当我们的触摸坐标有了,接下来就是根据这个坐标去计算画出贝塞尔曲线所需要到的坐标

1)).计算页脚坐标

private void calcCornerXY(float x, float y) {
if (x <= mWidth / 2)//如果手指触摸点的x坐标小于宽度的一半,页脚的x坐标就是0,也就是左上角
mCornerX = 0;
else//右上角
mCornerX = mWidth;//当触摸点的x坐标超过屏幕宽度的一半的时候,页脚的x坐标就是宽度的值
if (y <= mHeight / 2)//如果触摸点的高度小于屏幕高度的一半,页脚的y坐标就是0,左上角
mCornerY = 0;
else//右下角
mCornerY = mHeight;//如果触摸点的高度大于屏幕的高度的一半,页脚的y坐标就是高度,
if ((mCornerX == 0 && mCornerY == mHeight)//代表是左下角
|| (mCornerX == mWidth && mCornerY == 0))//代表右上角
mIsRTandLB = true;//这个标志设置true
else
mIsRTandLB = false;//否则标志设置false
}

2)).计算贝塞尔曲线需要的各个点的坐标:

private void calcPoints() {

//坐标的中间点的值,触摸点的x,y坐标与页脚坐标的和的一半
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);

//第一条贝塞尔曲线的起始点坐标,也就是黄色的那个位图,这个计算值请看数学方法
mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x)/ 2;
mBezierStart1.y = mCornerY;
//第二条贝塞尔曲线的起始点坐标,也就是绿色的那个位图,这个计算值请看数学方法
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);
//贝塞尔曲线顶点坐标的初始化,这个计算值请看数学方法
/*
* 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;

}

3)).两条直线的交点计算:

public PointF getCross(PointF P1, PointF P2, PointF P3, PointF P4) {
PointF CrossP = 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;
}

3)坐标都做完了之后,我们接下来就是绘制贝塞尔曲线:

1)).当前的位图,也就是黄色的

private void drawCurrentPageArea(Canvas canvas, Bitmap bitmap, Path path) {
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();//取出画布的状态,一般跟save()同时出现,匹配响应
}

画布属性解释:

1.canvas.clipRect(30, 30, 70, 70, Region.Op.XOR);最后一个参数有多个选择分别是:

            //DIFFERENCE是第一次不同于第二次的部分显示出来
            //REPLACE是显示第二次的
            //REVERSE_DIFFERENCE 是第二次不同于第一次的部分显示
            //INTERSECT交集显示
            //UNION全部显示
            //XOR补集 就是全集的减去交集剩余部分显示

2.

canvas.save();和canvas.restore();是两个相互匹配出现的,作用是用来保存画布的状态和取出保存的状态的。这里稍微解释一下,

  当我们对画布进行旋转,缩放,平移等操作的时候其实我们是想对特定的元素进行操作,比如图片,一个矩形等,但是当你用canvas的方法来进行这些操作的时候,其实是对整个画布进行了操作,那么之后在画布上的元素都会受到影响,所以我们在操作之前调用canvas.save()来保存画布当前的状态,当操作之后取出之前保存过的状态,这样就不会对其他的元素进行影响

2))画出绿色部分的贝塞尔曲线以及阴影的效果

private void drawNextPageAreaAndShadow(Canvas canvas, Bitmap bitmap) {
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));
float f5 = mTouchToCornerDis / 4;//这个值在后面被直接使用了右边的表达式
int leftx;
int rightx;
GradientDrawable mBackShadowDrawable;//渐变式背景灰色的阴影效果
if (mIsRTandLB) {//左下右上的方式
leftx = (int) (mBezierStart1.x - 1);
rightx = (int) (mBezierStart1.x + mTouchToCornerDis / 4 + 1);
mBackShadowDrawable = mBackShadowDrawableLR;//渐变式效果是从左到右
} else {
leftx = (int) (mBezierStart1.x - mTouchToCornerDis / 4 - 1);
rightx = (int) mBezierStart1.x + 1;
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();//取出画布的状态
}

度的计算:数学方法:

java.lang.Math.toDegrees(double angrad)转换以弧度为单位测得的角度大致相等的角度,以度衡量。

上面的函数是把弧度转换成度,

java.lang.Math.atan2(double y,double x)返回正切值 tan(θ) = y / x

返回值为笛卡尔平面中的角度,该角度由 x 轴和起点为原点 (0,0)、终点为 (x,y) 的向量构成。

3)).画出当前页,就是黄色部分的阴影效果

public void drawCurrentPageShadow(Canvas canvas) {

// 注:拖拽顶点的阴影,定位有问题,待修改~~
double d1 = Math.atan2(mBezierControl1.y - mTouch.y, mTouch.x- mBezierControl1.x);
double d3 = (float) 25 / Math.cos(d1);
float x = (float) (mTouch.x - d3);
float y = (float) (mTouch.y - d3);

// 前面阴影的第一边,请仔细看图,无论从哪个方向翻页,都是在前面产生两个阴影效果
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;
GradientDrawable mCurrentPageShadow;//阴影部分的渐变式效果
if (mIsRTandLB) {//如果方向是左下右上
leftx = (int) (mBezierControl1.x);
rightx = (int) mBezierControl1.x + 25;
mCurrentPageShadow = mFrontShadowDrawableVLR;//渐变式效果从左向右
} else {//否则
leftx = (int) (mBezierControl1.x - 25);
rightx = (int) mBezierControl1.x;
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 - 500),
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);
mCurrentPageShadow = mFrontShadowDrawableHBT;//渐变式效果右上到左下
}

//旋转的角度
rotateDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl2.y
- mTouch.y, mBezierControl2.x - mTouch.x));
canvas.rotate(rotateDegrees, mBezierControl2.x, mBezierControl2.y);
mCurrentPageShadow.setBounds((int) (mBezierControl2.x - 500), leftx,
(int) (mBezierControl2.x), rightx);//设置边界
mCurrentPageShadow.draw(canvas);//把这个阴影绘制出来
canvas.restore();//取出画布的状态
}


到这里,整个代码就分析完毕了,实现的效果就如文章开头给出的效果

源码地址:http://download.csdn.net/detail/u014737138/8133913

你可能感兴趣的:(Android学习)