Windows mobile 开发入门—开发绚丽滑动效果
在这里制作一个9宫格的小程序,如果超过9个,那么就自动翻页。翻页采用划动实现,并且有惯性作用。
原理
mobile手机里滑动效果主要是原理是支持屏幕的触摸,当我们按下、松开时系统分别可以捕捉到相应的坐标位置,然后动态的改变布局,从而达到划动的效果。
图型button
由于mobile还没有支持图片button,所以我们做出一个辅佐类,当按下、弹开时分别使用钢笔绘制不同的图片到屏幕。
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
namespace iPhoneUI 

{
public class ImageButton 
{
internal Rectangle clientArea;
internal Form owner;
internal Bitmap image;
internal Bitmap imageDown;
internal bool pushed = false;
internal Point location;
internal Point start;
internal int h=30,w=30;
internal bool Enable = false;
private double pressTime = Environment.TickCount;
internal bool pushedOneTime = false;

public string Name
{get;set;}
public bool IsPressedOneTime 
{ 
get
{ return pushedOneTime; } 
set
{ pushedOneTime = value; }
}
public event System.EventHandler Click;
public event System.EventHandler DoubleClick;
public ImageButton(Form owner,int w,int h) 
{
this.w = w;
this.h = h;
this.owner = owner;
Attach(owner);
}
public ImageButton(Form owner,Point location) 
{
this.owner = owner;
Attach(owner);
this.location = location;
this.clientArea = new Rectangle(location.X, location.Y, h, w);
}
public Point Location 
{
set 
{
this.location = value;
this.clientArea = new Rectangle(location.X, location.Y, w, h);
} 
get
{ return location; }
}
public Bitmap Image 
{ 
get
{ return image;}
set 
{
image = value;
if (image != null) 
{
clientArea = new Rectangle(location.X, location.Y, image.Width, image.Height);
}
}
}
public Bitmap ImageDown 
{ 
get
{ return imageDown;} 
set
{ imageDown = value; }
}
public bool HitTest(int x, int y) 
{
return clientArea.Contains(x, y);
}
private void Attach(Form owner) 
{
owner.MouseDown += new MouseEventHandler(owner_MouseDown);
owner.MouseUp += new MouseEventHandler(owner_MouseUp);
owner.DoubleClick += new EventHandler(owner_DoubleClick);
}
void owner_DoubleClick(object sender, EventArgs e) 
{
}
public virtual void owner_MouseUp(object sender, MouseEventArgs e) 
{
if (!Enable)
return;
if (pushed) 
{
using (Graphics gx = owner.CreateGraphics()) 
{
this.pushed = false;
this.Paint(gx);
owner.Invalidate();
}
pushed = false;
if ((Environment.TickCount - pressTime) < 100) 
{
if (Click != null)
Click(this, e);
}
}
// SendMessage(ButtonCode, "Button Pressed");
}
public virtual void owner_MouseDown(object sender, MouseEventArgs e) 
{
if (!Enable)
return;
if (this.HitTest(e.X, e.Y)) 
{
using (Graphics gx = owner.CreateGraphics()) 
{
this.pushed = true;
IsPressedOneTime = true;
this.Paint(gx);
if ((Environment.TickCount - pressTime) < 300) 
{
if (DoubleClick != null)
DoubleClick(this, e);
}
pressTime = Environment.TickCount;
}
start = new Point(e.X, e.Y);
}
}
public void Paint(Graphics gx) 
{
if (!Enable)
return;
//gx.Clear(Color.White);
ImageAttributes attrib = new ImageAttributes();
Color color = GetTransparentColor(image);
attrib.SetColorKey(color, color);
if (!pushed || imageDown == null)
gx.DrawImage(image, clientArea, 0, 0, clientArea.Width, clientArea.Height, GraphicsUnit.Pixel, attrib);
else 
{
gx.DrawImage(imageDown, clientArea, 0, 0, clientArea.Width, clientArea.Height, GraphicsUnit.Pixel, attrib);
}
Brush b = new SolidBrush(Color.Black);
int txtX=clientArea.Location.X;
if(Name.Length<5)//右移5个PIX
txtX+=5;
gx.DrawString(this.Name, owner.Font, b, txtX, clientArea.Bottom);
}
internal Color GetTransparentColor(Bitmap image) 
{
return image.GetPixel(0, 0);
}
}
} 
当mouse按下时,判断是否在图像所在的区域内,就执行按下时绘制图像。并且判断两次按下时间小于300毫秒,就认为是双击,发出注册双击事件。当mouse弹起时,恢复按前的图像,并且如果按下时间间隔不超过100毫秒,认为是单击。
初使化按扭
1
<?xml version="1.0" standalone="yes"?> 2
<DocumentElement> 3
<menu> 4
<Name>测试1</Name> 5
6
<path>Chat 46x46.bmp</path> 7
<pressPath>Chat 46x46.bmp</pressPath> 8
</menu> 9
<menu> 10
<Name>测试1a</Name> 11
12
<path>Chat 46x46.bmp</path> 13
<pressPath>Chat 46x46.bmp</pressPath> 14
</menu> 15
<menu> 16
<Name>测试1b</Name> 17
18
<path>lock 46x46.bmp</path> 19
<pressPath>lock 46x46_pressed.bmp</pressPath> 20
</menu> 21
<menu> 22
<Name>测试1c</Name> 23
24
<path>Internet Explorer 46x46.bmp</path> 25
<pressPath>Internet Explorer 46x46_pressed.bmp</pressPath> 26
</menu> 27
<menu> 28
<Name>测试1d</Name> 29
30
<path>Close 46x46.bmp</path> 31
<pressPath>Close 46x46_pressed.bmp</pressPath> 32
</menu> 33
<menu> 34
<Name>测试1e</Name> 35
36
<path>Chat 46x46.bmp</path> 37
<pressPath>Chat 46x46_pressed.bmp</pressPath> 38
</menu> 39
<menu> 40
<Name>测试1f</Name> 41
42
<path>Camera 46x46.bmp</path> 43
<pressPath>Camera 46x46_pressed.bmp</pressPath> 44
</menu> 45
<menu> 46
<Name>测试1g</Name> 47
48
<path>Camera 46x46.bmp</path> 49
<pressPath>Camera 46x46_pressed.bmp</pressPath> 50
</menu> 51
<menu> 52
<Name> 53
测试1h 54
</Name> 55
56
<path>Camera 46x46.bmp</path> 57
<pressPath>Camera 46x46_pressed.bmp</pressPath> 58
</menu> 59
<menu> 60
<Name> 61
测试1i 62
</Name> 63
> 64
<path>Camera 46x46.bmp</path> 65
<pressPath>Camera 46x46_pressed.bmp</pressPath> 66
</menu> 67
<menu> 68
<Name> 69
测试1j 70
</Name> 71
72
<path>Camera 46x46.bmp</path> 73
<pressPath>Camera 46x46_pressed.bmp</pressPath> 74
</menu> 75
<menu> 76
<Name>测试1k</Name> 77
78
<path>Camera 46x46.bmp</path> 79
<pressPath>Camera 46x46_pressed.bmp</pressPath> 80
</menu> 81
<menu> 82
<Name>测试1l</Name> 83
84
<path>Camera 46x46.bmp</path> 85
<pressPath>Camera 46x46_pressed.bmp</pressPath> 86
</menu> 87
<menu> 88
<Name>测试1m</Name> 89
90
<path>Camera 46x46.bmp</path> 91
<pressPath>Camera 46x46_pressed.bmp</pressPath> 92
</menu> 93
<menu> 94
<Name>测试1n</Name> 95
96
<path>Camera 46x46.bmp</path> 97
<pressPath>Camera 46x46_pressed.bmp</pressPath> 98
</menu> 99
<menu> 100
<Name>测试1o</Name> 101
102
<path>Camera 46x46.bmp</path> 103
<pressPath>Camera 46x46_pressed.bmp</pressPath> 104
</menu> 105
<menu> 106
<Name>测试1p</Name> 107
<path>Camera 46x46.bmp</path> 108
<pressPath>Camera 46x46_pressed.bmp</pressPath> 109
</menu> 110
111
</DocumentElement>
程序中的button,放置在XML中,以方便动态的加载。pat是正常的路径,presspath是按下时显示的图片。
1
private void initMenu() 2

{ 3
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase); 4
DataTable dt = new DataTable(); 5
DataSet ds = new DataSet(); 6
7
ds.ReadXml(path + "\\menu.xml"); 8
dt = ds.Tables[0]; 9
10
foreach (DataRow dr in dt.Rows) 11

{ 12
13
Bitmap b = new Bitmap(path + @"\Images\" + dr["path"].ToString()); 14
ImageButton buttonCalendar = new ImageButton(this, b.Width, b.Height); 15
buttonCalendar.Image = b; 16
buttonCalendar.ImageDown = new Bitmap(path + @"\Images\" + dr["pressPath"].ToString().Trim()); 17
buttonCalendar.Name = dr["Name"].ToString().Trim() ; 18
buttonCalendar.Click += new EventHandler(buttonCalendar_Click); 19
menuList.Add(buttonCalendar); 20
21
} 22
23
point1 = new Bitmap(path + @"\Images\point.png"); 24
point2 = new Bitmap(path + @"\Images\point2.png"); 25
26
27
}
在mobile中获取文件的路径与windows下不同, string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
这样才能找到当前动行的程序路径.
在对XML文件中的初使化,并赋值给图像按钮,并且注册事件
Point是分页时在下方的位置产生一个小圆点,代表页数和当前页。
绘制按扭
1
protected override void OnPaint(PaintEventArgs e) 2

{ 3
int startX = 0; 4
5
int h = 8; 6
List<ImageButton> temList = new List<ImageButton>(); 7
8
int i = 0; 9
10
foreach (ImageButton item in menuList) 11

{ 12
int w = (Width / 3 - item.w) / 2 + startX; 13
14
if (i % 3 == 0) 15

{ 16
h = 8; 17
item.Location = new Point(w, h); 18
} 19
if (i % 3 == 1) 20

{ 21
h += 85; 22
item.Location = new Point(w, h); 23
} 24
if (i % 3 == 2) 25

{ 26
h += 85; 27
item.Location = new Point(w , h); 28
29
startX += Width / 3; 30
} 31
32
item.Enable = true; 33
34
Point p = item.Location; 35
p.X += moveX; 36
// p.Y += moveY; 37
p.X -= this.Width * currentPage; 38
item.Location = p; 39
40
temList.Add(item); 41
42
i++; 43
} 44
gxBuffer = Graphics.FromImage(offBitmap); 45
46
//Graphics gxBuffer = e.Graphics; 47
gxBuffer.Clear(this.BackColor); 48
49
50
foreach (ImageButton item in temList) 51

{ 52
item.Paint(gxBuffer); 53
} 54
55
if (menuList.Count > 9) 56

{ 57
int pageCount = menuList.Count % 9==0?0:1; 58
pageCount += menuList.Count / 9; 59
60
startX=(this.Width-pageCount*10)/2; 61
int startY=this.Height-10; 62
63
for (int j = 0; j < pageCount; j++) 64

{ 65
if(currentPage==j) 66
gxBuffer.DrawImage(point1, startX,startY); 67
else 68
gxBuffer.DrawImage(point2, startX, startY); 69
70
startX += 10; 71
} 72
73
} 74
e.Graphics.DrawImage(offBitmap, 0, 0); 75
76
}
OnPaint 是窗体的方法,它是在调用Invalidate后自动执行。在这里控制每行显示3个,每页显示9个,如果有分页画划分页小圆点。在系统初使化,mouse 按下,弹出时都调用Invalidate方法,放系统重画UI。为了防卡需要override OnPaintBackground,这点我也不是很明白,如果有高手请多指教。
实现划动效果
void Form1_MouseDown(object sender, MouseEventArgs e)
{
x=e.X;
y = e.Y;
}
void Form1_MouseMove(object sender, MouseEventArgs e)
{
moveX = e.X - x;
moveY = e.Y - y;
if ((Math.Abs(moveX) + Math.Abs(moveY)) > 5)
{
this.Invalidate();
}
}
mouse按下时,记录坐标,弹起时,计算偏移量,并且重绘UI.这对手机的性能有一定的要求,可能会有点卡,但是我个人觉得还是可以接受.不知各位有没有更好的方法.
实现惯性
当划动到边的松开时候,如果有下一页,则翻到下一页,如果没有,则慢慢的返回到原来的位置。
实现这个功能主要是使用一个timer控件。用TIMER来计算位置,具体实现请看代码。
浙公网安备 33010602011771号