用c#和GDI+实现杂志翻页动画效果时间:2010-01-13 blog.csdn.net 周公 -
说明:以前本人参与个一个电子杂志项目,当时要求实现模拟现实生活中的杂志翻页动画效果,别人推荐了这篇文章,最后达到了我想要的效果,今天尝试把这篇文章翻译了一下。希望对英语水平不太好的同行有帮助。如果你的英语水平足够好,我推荐你阅读英文原文,网址是:http://www.codeproject.com/KB/GDI-plus/TurnThePage.aspx,同时希望大家原谅本人的翻译水平。 介绍 图1 翻页效果 这篇文章用来介绍如何在电子书或者电子相册中并列显示图片时创建一种翻页效果,这种翻页效果模仿了现实中的书本翻页情况。 背景 写作这篇文章的灵感来自于一个可重用的用于显示图片的组件的需求。我使用了C#和GDI+来提高我对.net下图形图象编程的理解。 创建这种效果的技术背景来自于一篇文章《FalshMX中的翻页效果》,网址是:http://www.oreillynet.com/pub/a/javascript/2004/09/03/flashhacks.html,作者是Sham Bhangal。Sham在文章里如何在动画效果中使用对称线来控制页面的可见部分。尽管在Flash MX中和在GDI+中的处理有些不同,但是利用对称线来计算页面的可见部分这个概念是相同的。 在这篇文章中,我们假定第3页和第4页是当前页,并且下一个动作是要翻到第5页和第6页。换句话说,我们要展现的是第4页的翻页效果。 动画技巧 下图阐述了在整个动画中的关键区域和变化区域。 图2 关键区域和参数 本文来自编程入门网:http://www.bianceng.cn/Programming/csharp/201001/14287.htm
整个翻页动画可以概括为: 1、完全绘制出第3页和第4页。在绘制完成之后,B和C部分将会遮挡住第4页的原来可见部分。 2、计算出对称线和B和C的裁剪区域。 3、绘制B部分。这是下面的一页的部分区域(第6页)。 4、根据热点进行相应转换,并且进行相应旋转。 5、绘制C部分。这是第4页在翻页过程中显示的它的背面(第5页)的内容。 当前页 《FalshMX中的翻页效果》一文中指出当前页并不参与翻页效果。这就意味着在翻页中的每一面(第3页和第4页)都会首先被不进行任何裁减和转换就绘制出来。B和C这两个可见部分将会在当前页之上进行绘制。 热点 “热点”这个词是我从《FalshMX中的翻页效果》一文中借鉴过来的。热点一词代表在翻页时折痕在水平轴线上的位置,它标明对称线的起始位置。在翻页过程中,热点一直在从页边缘到书中间这段距离之间移动。从页边到热点的这段距离(x)将随着页面的翻动而变化。当热点到达书的中间位置时,动画就停止了,这时x=PAGE_WIDTH。 对称线 对称线代表翻页时页面的折痕。它是用于计算在翻页时参与的页面可见部分。在程序中,对称线控制两件事情: 1、B和C部分的裁剪区域。 本文来自编程入门网:http://www.bianceng.cn/Programming/csharp/201001/14287_2.htm
2、C部分进行转换的坐标原点。 对称线可以用下面两个等式来描述: a = 45 + ( (45 *x) / PAGE_WIDTH ) h = x Tan ( a ) 注意角度a会随着x的变化而变化。这个等式表明当x=0时a = 45度并且当x= PAGE_WIDTH时a = 90度。 当动画开始时,x=0,因此B和C部分并不可见。随着x的增加,对称线就形成了直角三角形的斜边。三角形由三个长度确定:对称线、x和高度h。图2展示了这样一种情况。 随着x的增加,将会出现h>= PAGE_WIDTH的情况。当这种情况出现后,对称线与页面相交的区域将会由三角形变成梯形。梯形的高度就是PAGE_WIDTH。图1就是这种情况。 不管是梯形还是三角形,这个闭合路线都指出了B和C这两个裁减区域。要想看到运行中看到这种带有边框的效果,在提供的源代码中将INCLUDE_DRAW_GRAPHICS_PATH这个参数设置为true就行了。程序将会在闭合路径的外面绘制出一个金色的轮廓。 A部分区域 这部分是要翻动的页面在裁减出B和C部分之后的可见部分(第4页)。 B部分区域 B部分来自于正在翻动的页面的之下的另一页面,在这个例子中指的是第6页的可见部分。B部分区域就是被对称线与页面形成的闭合曲线所裁减的部分。在这个部分之上的页面(第4页)的相应部分将会被直接裁减掉。显而易见,随着x的增加(a也随着增加),这个可见部分将会越来越大。 要想看A和B部分区域的关系,请将INCLUDE_UNDERSIDE_PAGE_IN_ANIMATION变量设置为false。这将把C部分从动画效果中去掉。 C部分区域 C部分区域的图象表示了正在翻动的页面的背面的图象。在这个例子中,C部分区域代表了第5页的可见部分。C部分也是通过对称线指定的,但是是在页面的这一边(对称线的左边)。举个例子,当翻动第4页时,B部分将会是第6页的右下部分,而C部分将会是第5页的左下部分。图3展示了B和C之间的关系。 图3 B和C之间的关系 本文来自编程入门网:http://www.bianceng.cn/Programming/csharp/201001/14287_3.htm
在绘制C部分区域时,我们用了一个后台的图象来辅助,就是pageUndersideImage。这个新图象的裁减区域通过对称线来确定。第5页的图象被绘制在这个新的缓冲区里面,这个新建的图象将会靠近B部分区域绘制。 连接B和C部分区域 当C部分的后台图像已经准备好,它通过下面的步骤绘制: 首先调整系统坐标到热点。 将系统坐标旋转180-2a度,请看图4了解它们的关系。 将含有C部分区域的图像绘制到相应坐标(-x,-PAGE_HEIGHT)。图5标明了这种旋转。 图4 调整角度以匹配对称线 图5 旋转坐标系 我发现沿着对称线排列B和C部分区域非常具有挑战性因为当前页面的颜色容易出“血边”(因为第4页的一些红色像素)。当我绘制B或者C部分区域时,我用了一个变通方法:指定图形对象的pixeloffsetmode以pixeloffsetmode.half方式绘制。 g.PixelOffsetMode= PixelOffsetMode.Half; 我还发现,在绘制C部分区域之前,增加一个像素(或者减掉一个像素)来旋转坐标也可以防止出“血边”。 PathTranslationMatrix.Translate((float)hotSpot.Origin.X+1, (float)hotSpot.Origin.Y); 要使用pixeloffsetmode变通方法,请将源代码中的USE_PIXEL_MODE_OFFSET设置为true。 - 本文来自编程入门网:http://www.bianceng.cn/Programming/csharp/201001/14287_4.htm
绘制动画 每一帧动画都是在timer1_Tick方法中绘制到缓冲区中的CurrentShownBitmap对象上。CurrentShownBitmap方法仅仅是将绘制到屏幕上。 主要功能说明 计算动画中每一帧里B和C部分的图象都是由以下方法完成的: private GraphicsPath GetPageUnderGraphicsPath(int x, refdouble a, int height, int width, bool isUnderSide, TurnType type) 参数x代表从页面边缘到热点处的距离(前面已经说明),height和width参数代表当前页面要显示的高度和宽度。isUnderSide参数用来告诉程序是否在计算C部分区域(正在翻动的那一页的背面),最后一个参数type是表示页面是左翻页还是右翻页。基本上,isUnderSide和type参数是用来获取图形路径的正确性的,参数a如上所述是代表当前角度的。参数a传递的是引用,随后将在绘制C之前用于旋转坐标(见图4和图5)。 使用代码 安装控件 为了简单起见,这个控件有自己的图片。初始化图象的代码在LoadSamples()方法中。这个方法在Sample类的构造方法中调用。 控制翻页的速度和数目 翻页的速度是通过一个timer来控制的,public属性TickSpeed能用来控制翻页速度(毫秒为单位),动画的帧数是通过每个timer间隔热点移动的距离来控制的。public属性暴露给外界以控制已经移动的距离x。 调整高度 沿着背页的顶部裁减是一个问题,public属性HeightAdjustment用于在控件顶部留一点空白区域便于裁剪。 开始动画 这个组件公开两个方法来开始动画。 animateRightPageTurn() and animateLeftPageTurn(). 注意事项 我本来试图解当h=PAGE_HEIGHT时的非线性方程h = x Tan( 45 + ((45 * (x)) / PAGE_WIDTH) )中的x的值,我的这个蛮力办法的代码包含在源代码中。是不是还有一个更优雅的办法呢? 说明:程序的源代码可以到http://download.csdn.net/source/381727下载。 本文来自编程入门网:http://www.bianceng.cn/Programming/csharp/201001/14287_5.htm
用c#和GDI+实现杂志翻页动画效果详解
说明:以前本人参与个一个电子杂志项目,当时要求实现模拟现实生活中的杂志翻页动画效果,别人推荐了这篇文章,最后达到了我想要的效果,今天尝试把这篇文章翻译了一下。希望对英语水平不太好的同行有帮助。如果你的英语水平足够好,我推荐你阅读英文原文,网址是:http://www.codeproject.com/KB/GDI-plus/TurnThePage.ASPx,同时希望大家原谅本人的翻译水平。
介绍 图1 翻页效果
这篇文章用来介绍如何在电子书或者电子相册中并列显示图片时创建一种翻页效果,这种翻页效果模仿了现实中的书本翻页情况。
背景
写作这篇文章的灵感来自于一个可重用的用于显示图片的组件的需求。我使用了C#和GDI+来提高我对.net下图形图象编程的理解。
创建这种效果的技术背景来自于一篇文章《FalshMX中的翻页效果》,网址是:http://www.oreillynet.com/pub/a/JavaScript/2004/09/03/flashhacks.html,作者是Sham Bhangal。Sham在文章里如何在动画效果中使用对称线来控制页面的可见部分。尽管在Flash MX中和在GDI+中的处理有些不同,但是利用对称线来计算页面的可见部分这个概念是相同的。
在这篇文章中,我们假定第3页和第4页是当前页,并且下一个动作是要翻到第5页和第6页。换句话说,我们要展现的是第4页的翻页效果。
动画技巧
下图阐述了在整个动画中的关键区域和变化区域。 图2 关键区域和参数
整个翻页动画可以概括为:
、完全绘制出第3页和第4页。在绘制完成之后,B和C部分将会遮挡住第4页的原来可见部分。
、计算出对称线和B和C的裁剪区域。
、绘制B部分。这是下面的一页的部分区域(第6页)。
、根据热点进行相应转换,并且进行相应旋转。
、绘制C部分。这是第4页在翻页过程中显示的它的背面(第5页)的内容。
当前页
《FalshMX中的翻页效果》一文中指出当前页并不参与翻页效果。这就意味着在翻页中的每一面(第3页和第4页)都会首先被不进行任何裁减和转换就绘制出来。B和C这两个可见部分将会在当前页之上进行绘制。
热点
“热点”这个词是我从《FalshMX中的翻页效果》一文中借鉴过来的。热点一词代表在翻页时折痕在水平轴线上的位置,它标明对称线的起始位置。在翻页过程中,热点一直在从页边缘到书中间这段距离之间移动。从页边到热点的这段距离(x)将随着页面的翻动而变化。当热点到达书的中间位置时,动画就停止了,这时x=PAGE_WIDTH。
对称线
对称线代表翻页时页面的折痕。它是用于计算在翻页时参与的页面可见部分。在程序中,对称线控制两件事情:
、B和C部分的裁剪区域。
、C部分进行转换的坐标原点。
对称线可以用下面两个等式来描述:
a = + ( ( *x) / PAGE_WIDTH )
h = x Tan ( a )
注意角度a会随着x的变化而变化。这个等式表明当x=0时a = 45度并且当x= PAGE_WIDTH时a = 90度。
当动画开始时,x=,因此B和C部分并不可见。随着x的增加,对称线就形成了直角三角形的斜边。三角形由三个长度确定:对称线、x和高度h。图2展示了这样一种情况。
随着x的增加,将会出现h>= PAGE_WIDTH的情况。当这种情况出现后,对称线与页面相交的区域将会由三角形变成梯形。梯形的高度就是PAGE_WIDTH。图1就是这种情况。
不管是梯形还是三角形,这个闭合路线都指出了B和C这两个裁减区域。要想看到运行中看到这种带有边框的效果,在提供的源代码中将INCLUDE_DRAW_GRAPHICS_PATH这个参数设置为true就行了。程序将会在闭合路径的外面绘制出一个金色的轮廓。
A部分区域
这部分是要翻动的页面在裁减出B和C部分之后的可见部分(第4页)。
B部分区域
B部分来自于正在翻动的页面的之下的另一页面,在这个例子中指的是第6页的可见部分。B部分区域就是被对称线与页面形成的闭合曲线所裁减的部分。在这个部分之上的页面(第4页)的相应部分将会被直接裁减掉。显而易见,随着x的增加(a也随着增加),这个可见部分将会越来越大。
要想看A和B部分区域的关系,请将INCLUDE_UNDERSIDE_PAGE_IN_ANIMATION变量设置为false。这将把C部分从动画效果中去掉。
C部分区域
C部分区域的图象表示了正在翻动的页面的背面的图象。在这个例子中,C部分区域代表了第5页的可见部分。C部分也是通过对称线指定的,但是是在页面的这一边(对称线的左边)。举个例子,当翻动第4页时,B部分将会是第6页的右下部分,而C部分将会是第5页的左下部分。图3展示了B和C之间的关系。 图3 B和C之间的关系
在绘制C部分区域时,我们用了一个后台的图象来辅助,就是pageUndersideImage。这个新图象的裁减区域通过对称线来确定。第5页的图象被绘制在这个新的缓冲区里面,这个新建的图象将会靠近B部分区域绘制。
连接B和C部分区域
当C部分的后台图像已经准备好,它通过下面的步骤绘制:
首先调整系统坐标到热点。
将系统坐标旋转180-2a度,请看图4了解它们的关系。
将含有C部分区域的图像绘制到相应坐标(-x,-PAGE_HEIGHT)。图5标明了这种旋转。 图4 调整角度以匹配对称线 图5 旋转坐标系
我发现沿着对称线排列B和C部分区域非常具有挑战性因为当前页面的颜色容易出“血边”(因为第4页的一些红色像素)。当我绘制B或者C部分区域时,我用了一个变通方法:指定图形对象的pixeloffsetmode以pixeloffsetmode.half方式绘制。
g.PixelOffsetMode= PixelOffsetMode.Half;
我还发现,在绘制C部分区域之前,增加一个像素(或者减掉一个像素)来旋转坐标也可以防止出“血边”。
PathTranslationMatrix.Translate((float)hotSpot.Origin.X+,
(float)hotSpot.Origin.Y);
要使用pixeloffsetmode变通方法,请将源代码中的USE_PIXEL_MODE_OFFSET设置为true。
绘制动画
每一帧动画都是在timer1_Tick方法中绘制到缓冲区中的CurrentShownBitmap对象上。CurrentShownBitmap方法仅仅是将绘制到屏幕上。
主要功能说明
计算动画中每一帧里B和C部分的图象都是由以下方法完成的:
private GraphicsPath GetPageUnderGraphicsPath(int x,
refdouble a, int height, int width,
bool isUnderSide, TurnType type)
参数x代表从页面边缘到热点处的距离(前面已经说明),height和width参数代表当前页面要显示的高度和宽度。isUnderSide参数用来告诉程序是否在计算C部分区域(正在翻动的那一页的背面),最后一个参数type是表示页面是左翻页还是右翻页。基本上,isUnderSide和type参数是用来获取图形路径的正确性的,参数a如上所述是代表当前角度的。参数a传递的是引用,随后将在绘制C之前用于旋转坐标(见图4和图5)。
使用代码
安装控件
为了简单起见,这个控件有自己的图片。初始化图象的代码在LoadSamples()方法中。这个方法在Sample类的构造方法中调用。
控制翻页的速度和数目
翻页的速度是通过一个timer来控制的,public属性TickSpeed能用来控制翻页速度(毫秒为单位),动画的帧数是通过每个timer间隔热点移动的距离来控制的。public属性暴露给外界以控制已经移动的距离x。
调整高度
沿着背页的顶部裁减是一个问题,public属性HeightAdjustment用于在控件顶部留一点空白区域便于裁剪。
开始动画
这个组件公开两个方法来开始动画。
animateRightPageTurn() and animateLeftPageTurn().
注意事项
我本来试图解当h=PAGE_HEIGHT时的非线性方程h = x Tan( + (( * (x)) / PAGE_WIDTH) )中的x的值,我的这个蛮力办法的代码包含在源代码中。是不是还有一个更优雅的办法呢?
说明:程序的源代码可以到http://download.csdn.net/source/381727下载。