1.起因
我经常在PS设计网站和游戏界面,看到带条纹形状的进度条,看起来比较酷。所以决定实现一个带滚动效果的条纹进度条。
经过一段时间的尝试之后,完成了如下效果图,且是带有滚动效果的。
实现步骤:
1.素材
各大素材网站都有界面素材,比较出名的是站酷,从上面下载一份素材,尝试用PS截取你想要的图片吧。
我下了一份界面素材,如下图:
这些素材都是PSD分层的,可以省去抠图的时间,再说咱们也不是专业的PS大神,省省抠图的冲动吧。
经过对界面重新更改颜色后,我得到了如下三张图片:
1. 进度条背景图:
2.进度条:
3.进度条条纹,因条纹是白色的,所以为了方便讲解,我将其背景填充为黄色的。实际效果时背景色为透明色。
2.实现
因我们的进度条是图片格式的,在很多界面编程情况下,需要对其拉伸,所以得用一个特殊的方法,对图片进行拉伸,以达到不会失真的效果。
进图条图片是带圆角的矩形,所以我们需要将两边带圆角的图片,先裁切出来,然后在拉伸中间的图片即可。当然,中间的图片也是通过裁切和拼接,以达到拉伸的效果。
编程示意图如下,把裁切过的图片进行拼接,即可达到拉伸的效果,且不会失真(我将裁切图片分开了点空白距离,以便看清):
实现的代码如下:
程序根据输入的nCorner来对左右两边的图片进行裁切,然后先画左边的图像,再画中间的图像,最后再画右边的图像。中间的图像会依照实际的尺寸进行裁切,以达到拉伸的效果。注意这里的拉伸只是水平拉伸,并没有垂直拉伸。
void StretchWidthImage(Graphics& g, Image* pImage, Rect& rcDest, REAL nCorner = 1.0F)
{
if (pImage == NULL || rcDest.Width <= 0 || nCorner <= 0)
{
return;
}
// rcDest's X and Y is relative coordinate.
REAL nImageWidth = (REAL)pImage->GetWidth();
REAL nImageHeight = (REAL)pImage->GetHeight();
REAL nStretchLength = (REAL)(nImageWidth - 2 * nCorner);
REAL X = (REAL)rcDest.X;
REAL Y = (REAL)rcDest.Y;
REAL nLength = (REAL)(rcDest.Width - 2 * nCorner);
// Draw left corner.
g.DrawImage(pImage, RectF(X, Y, nCorner, nImageHeight),
0, 0, nCorner, nImageHeight, UnitPixel);
// If rect length less than image length,
// Using rect length for real drawing length.
REAL nRealLength = nStretchLength;
if (nLength < nStretchLength)
{
nRealLength = nLength;
}
// Draw middle, stretch the length.
REAL nLeftIndex = nCorner + X;
REAL nRightIndex = nCorner + nRealLength + X;
REAL nDrawLength = nRealLength;
while (TRUE)
{
g.DrawImage(pImage, RectF(nLeftIndex, Y, nDrawLength, nImageHeight),
nCorner, 0, nStretchLength, nImageHeight, UnitPixel);
// If length equal 0 means all middle image has finished drawing.
nLength -= nDrawLength;
if (nLength <= 0)
{
break;
}
if (nLength < nDrawLength)
{
nDrawLength = nLength;
}
// Move drawing left Index.
nLeftIndex = nRightIndex;
nRightIndex += nDrawLength;
}
// Draw right corner.
g.DrawImage(pImage, RectF(nRightIndex, Y, nCorner, nImageHeight),
nImageWidth - nCorner, 0, nCorner, nImageHeight, UnitPixel);
}
如果你输入的nCorner比实际图像的左边椭圆的半径要小,就会出现以下裁切不完整的情况,所以你可以根据目测,来指定一个稍大的nCorner值就好了。3.实现条纹及滚动效果
条纹是按照一定的间距,在进度条表面依次进行绘制的,为了不让条纹的绘制超出进度条的范围,所以我用了SetClip函数,来设定绘制范围。代码实现如下:
// Draw progress bar stripe.
BOOL DrawStripe(Graphics& g)
{
if (m_rcProg.Width <= 0)
{
return FALSE;
}
g.SetClip(m_pathProg.m_pPath);
int nLeftIndex = (int)( -(m_imgStripe.GetWidth()) + m_nLeftIndex );
// Draw stripe.
for (int nIndex = nLeftIndex; nIndex < m_rcProg.Width; nIndex += m_nStripeSpace)
{
Rect rc(nIndex, m_rcProg.Y, (int)m_imgStripe.GetWidth(), (int)m_imgStripe.GetHeight());
g.DrawImage(m_imgStripe.m_pImage, rc);
}
return TRUE;
}
这里我将条纹的起始绘制位置,设为了一个负数,以让条纹绘制从进度条最上边开始,且负数可以用作滚动效果的开始位置,如果你的滚动效果从0开始,那么将会导致下面这个情况,条纹开始脱离进度条了:
4.本文代码及工程文件
http://download.csdn.net/detail/renstarone/5773021