分享

Windows mobile 开发入门—开发绚丽滑动效果

 江江385 2015-09-23
前言
    在这里制作一个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来计算位置,具体实现请看代码。

 

参考:http://iphoneui./

下载:http://files.cnblogs.com/mediar/MobileTest.rar

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约