前言
在这里制作一个9宫格的小程序,如果超过9个,那么就自动翻页。翻页采用划动实现,并且有惯性作用。 原理 mobile手机里滑动效果主要是原理是支持屏幕的触摸,当我们按下、松开时系统分别可以捕捉到相应的坐标位置,然后动态的改变布局,从而达到划动的效果。 由于mobile还没有支持图片button,所以我们做出一个辅佐类,当按下、弹开时分别使用钢笔绘制不同的图片到屏幕。 Code 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毫秒,认为是单击。 Code
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>
Code
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是分页时在下方的位置产生一个小圆点,代表页数和当前页。
Code
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) void Form1_MouseMove(object sender, MouseEventArgs e) mouse按下时,记录坐标,弹起时,计算偏移量,并且重绘UI.这对手机的性能有一定的要求,可能会有点卡,但是我个人觉得还是可以接受.不知各位有没有更好的方法.
实现惯性 当划动到边的松开时候,如果有下一页,则翻到下一页,如果没有,则慢慢的返回到原来的位置。 实现这个功能主要是使用一个timer控件。用TIMER来计算位置,具体实现请看代码。
|
|
来自: 江江385 > 《windows mobile》