当前位置:  编程技术>移动开发
本页文章导读:
    ▪xmpp及时聊天客户端部分应用源码        xmpp即时聊天客户端部分应用源码今天给大家分享一下xmpp即时聊天客户端部分应用源码,前两篇介绍了如何通过XMPP来发送消息和接收消息,这一篇我们主要介绍如何来美化我们的聊天程序,.........
    ▪ Google Chrome中的高性能网络(2)        Google Chrome中的高性能网络(二) Chrome Predictor的预测功能优化 Chrome会随着使用变得更快。 它这个特性是通过一个单例对象Predictor来实现的。这个对象在浏览器内核进程(Browser Kernel Process)中实例.........
    ▪ 高仿QQ的手机管家的小火箭加紧       高仿QQ的手机管家的小火箭加速1、前言 相信很多人都用过腾讯的手机管家,用过这个App的人都应该知道桌面的火箭一键加速这个功能,当然这里我不是推荐大家去使用手机管家,相反这个功.........

[1]xmpp及时聊天客户端部分应用源码
    来源: 互联网  发布时间: 2014-02-18
xmpp即时聊天客户端部分应用源码

今天给大家分享一下xmpp即时聊天客户端部分应用源码,前两篇介绍了如何通过XMPP来发送消息和接收消息,这一篇我们主要介绍如何来美化我们的聊天程序,看一下最终效果呢,当然源程序也会在最后放出


好了,我们来看一下我们写的程序

这里我们自定义了TableViewCell


一行是显示发布日期,一行是显示发送的消息,还有一个是背景

[java] view plaincopy
  • -(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{  
  •       
  •     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];  
  •     if (self) {  
  •         //日期标签  
  •         senderAndTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, 300, 20)];  
  •         //居中显示  
  •         senderAndTimeLabel.textAlignment = UITextAlignmentCenter;  
  •         senderAndTimeLabel.font = [UIFont systemFontOfSize:11.0];  
  •         //文字颜色  
  •         senderAndTimeLabel.textColor = [UIColor lightGrayColor];  
  •         [self.contentView addSubview:senderAndTimeLabel];  
  •           
  •         //背景图  
  •         bgImageView = [[UIImageView alloc] initWithFrame:CGRectZero];  
  •         [self.contentView addSubview:bgImageView];  
  •           
  •         //聊天信息  
  •         messageContentView = [[UITextView alloc] init];  
  •         messageContentView.backgroundColor = [UIColor clearColor];  
  •         //不可编辑  
  •         messageContentView.editable = NO;  
  •         messageContentView.scrollEnabled = NO;  
  •         [messageContentView sizeToFit];  
  •         [self.contentView addSubview:messageContentView];  
  •   
  •     }  
  •       
  •     return self;  
  •       
  • }  
  • 定义好,在UITableViewCell中将Cell改成我们自己定义的Cell

    [java] view plaincopy
  • -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{  
  •       
  •     static NSString *identifier = @"msgCell";  
  •       
  •     KKMessageCell *cell =(KKMessageCell *)[tableView dequeueReusableCellWithIdentifier:identifier];  
  •       
  •     if (cell == nil) {  
  •         cell = [[KKMessageCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];  
  •     }  
  •       
  •     NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];  
  •       
  •     //发送者  
  •     NSString *sender = [dict objectForKey:@"sender"];  
  •     //消息  
  •     NSString *message = [dict objectForKey:@"msg"];  
  •     //时间  
  •     NSString *time = [dict objectForKey:@"time"];  
  •       
  •     CGSize textSize = {260.0 ,10000.0};  
  •     CGSize size = [message sizeWithFont:[UIFont boldSystemFontOfSize:13] constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];  
  •       
  •     size.width +=(padding/2);  
  •       
  •     cell.messageContentView.text = message;  
  •     cell.accessoryType = UITableViewCellAccessoryNone;  
  •     cell.userInteractionEnabled = NO;  
  •       
  •     UIImage *bgImage = nil;  
  •       
  •     //发送消息  
  •     if ([sender isEqualToString:@"you"]) {  
  •         //背景图  
  •         bgImage = [[UIImage imageNamed:@"BlueBubble2.png"] stretchableImageWithLeftCapWidth:20 topCapHeight:15];  
  •         [cell.messageContentView setFrame:CGRectMake(padding, padding*2, size.width, size.height)];  
  •           
  •         [cell.bgImageView setFrame:CGRectMake(cell.messageContentView.frame.origin.x - padding/2, cell.messageContentView.frame.origin.y - padding/2, size.width + padding, size.height + padding)];  
  •     }else {  
  •           
  •         bgImage = [[UIImage imageNamed:@"GreenBubble2.png"] stretchableImageWithLeftCapWidth:14 topCapHeight:15];  
  •           
  •         [cell.messageContentView setFrame:CGRectMake(320-size.width - padding, padding*2, size.width, size.height)];  
  •         [cell.bgImageView setFrame:CGRectMake(cell.messageContentView.frame.origin.x - padding/2, cell.messageContentView.frame.origin.y - padding/2, size.width + padding, size.height + padding)];  
  •     }  
  •       
  •     cell.bgImageView.image = bgImage;  
  •     cell.senderAndTimeLabel.text = [NSString stringWithFormat:@"%@ %@", sender, time];  
  •   
  •     return cell;  
  •       
  • }  
  • 在这个Cell里设置了发送的消息的背景图和接收消息的背景图

    这里在字典里有一个"time"

    这是我们接收和发送消息的时间

    [java] view plaincopy
  • +(NSString *)getCurrentTime{  
  •       
  •     NSDate *nowUTC = [NSDate date];  
  •       
  •     NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];  
  •     [dateFormatter setTimeZone:[NSTimeZone localTimeZone]];  
  •     [dateFormatter setDateStyle:NSDateFormatterMediumStyle];  
  •     [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];  
  •       
  •     return [dateFormatter stringFromDate:nowUTC];  
  •       
  • }  
  • 在AppDelegate.m中

    将我们收到消息的内容也做一下调整

    [java] view plaincopy
  • - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{  
  •       
  • //   ......  
  •       
  •     NSMutableDictionary *dict = [NSMutableDictionary dictionary];  
  •     [dict setObject:msg forKey:@"msg"];  
  •     [dict setObject:from forKey:@"sender"];  
  •     //消息接收到的时间  
  •     [dict setObject:[Statics getCurrentTime] forKey:@"time"];  
  •       
  •    ......  
  •       
  • }  
  • 最后我们再设置一下每一行显示的高度

    [java] view plaincopy
  • //每一行的高度  
  • -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{  
  •       
  •     NSMutableDictionary *dict  = [messages objectAtIndex:indexPath.row];  
  •     NSString *msg = [dict objectForKey:@"msg"];  
  •       
  •     CGSize textSize = {260.0 , 10000.0};  
  •     CGSize size = [msg sizeWithFont:[UIFont boldSystemFontOfSize:13] constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];  
  •       
  •     size.height += padding*2;  
  •       
  •     CGFloat height = size.height < 65 ? 65 : size.height;  
  •       
  •     return height;  
  •       
  • }  
  • ,对了,在发送消息的时候,别忘了也加上

    [java] view plaincopy
  • - (IBAction)sendButton:(id)sender {  
  •       
  •     //本地输入框中的信息  
  •     ......  
  •       
  •     if (message.length > 0) {  
  •           
  •         .....  
  •           
  •         NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];  
  •           
  •         [dictionary setObject:message forKey:@"msg"];  
  •         [dictionary setObject:@"you" forKey:@"sender"];  
  •         [dictionary setObject:[Statics getCurrentTime] forKey:@"time"];  
  •   
  •         [messages addObject:dictionary];  
  •           
  •         //重新刷新tableView  
  •         [self.tView reloadData];  
  •           
  •     }  
  •       
  •       
  • }  
  • 好了,这里关于XMPP发送消息的教程就结束了,以后我们会详细介绍其他关于XMPP的内容

     

    文件有点大了,就没有上传上去了,喜欢的朋友可以下载看看吧。

     

    download


        
    [2] Google Chrome中的高性能网络(2)
        来源: 互联网  发布时间: 2014-02-18
    Google Chrome中的高性能网络(二)
    Chrome Predictor的预测功能优化

    Chrome会随着使用变得更快。 它这个特性是通过一个单例对象Predictor来实现的。这个对象在浏览器内核进程(Browser Kernel Process)中实例化,它唯一的职责就是观察和学习当前网络活动方式,提前预估用户下一步的操作。下面是一个示例:

    • 用户将鼠标停留在一个链接上,就预示着一个用户的偏好以及下一步的浏览行为。这时Chrome就可以提前进行DNS Lookup及TCP握手。用户的点击操作平均需要将近200ms,在这个时间就可能处理完DNS和TCP相关的操作, 也就是省去几百毫秒的延迟时间。
    • 当在地址栏(Omnibox/URL bar) 触发高可能性选项时,就同样会触发一个DNS lookup和TCP预连接(pre-connect),甚至在一个不可见的页签中进行预渲染(pre-render)!
    • 我们每个人都一串天天会访问的网站, Chrome会研究在这些页面上的子资源, 并且尝试进行预解析(pre-resolve), 甚至可能会进行预加载(pre-fetch)以优化浏览体验。 


    除了上面三项,还有很多..


    Chrome会在你使用过程中学习Web的拓扑结构,而不单单是你的浏览模式。理想的话,它将为你省去数百毫秒的延迟, 更接近于即时页面加载的状态. 正是为了这个目标,Chrome投入了以下的核心优化技术:


    DNS预解析(pre-resolve) 提前解析主机地址,以减少DNS延迟 TCP预连接(pre-connect) 提前连接到目标服务器,以减少TCP握手延迟 资源预加载(prefetching) 提前加载页面的核心资源,以加载页面显示 页面预渲染(prerendering)     提前获取整个页面和相关子资源,这样可以做到及时显示


    每一个决策都包含着一个或多个的优化, 用来克服大量的限制因素.  不过毕竟都只是预测性的优化策略,如果效果不理想,就会引入多余的处理和网络传输。甚至可能会带来一些加载时间上的负体验。


    Chrome如何处理这些问题呢? Predictor会尽量收集各种信息,诸如用户操作,历史浏览数据,以及来自渲染引擎(render)和网络模块自身的信息。


    和Chrome中负责网络事务调度的ResourceDispatcherHost不同,Predictor对象会针对用户和网络事务创建一组过滤器(filter):

    • IPC channel filter用来监控来自render进程的事务。
    • 每个请求上都会加一个ConnectInterceptor 对象,这样就可以跟踪网络传输的模式以及每一个请求的度量数据。

    渲染进程(render process)会在一系列的事件下发送消息到浏览器进程(browser process), 这些事件被定义在一个枚举(ResolutionMotivation)中以便于使用 (url_info.h):

    enum ResolutionMotivation {
      MOUSE_OVER_MOTIVATED,     // 鼠标悬停.
      OMNIBOX_MOTIVATED,        // Omni-box建议进行解析.
      STARTUP_LIST_MOTIVATED,   // 这是在前10个启动项中的资源.
      EARLY_LOAD_MOTIVATED,     // 有时需要使用prefetched来提前建立连接.
    
      // 下面定义了预加载评估的方式,会由一个navigation变量指定.
      // referring_url_也需要同时指定.
      STATIC_REFERAL_MOTIVATED,  // 外部数据库(External Database)建议进行解析。
      LEARNED_REFERAL_MOTIVATED, // 前一次浏览(prior navigation建议进行解析.
      SELF_REFERAL_MOTIVATED,    // 猜测下一个连接是不是需要进行解析.
    
      // <略> ...
    };
    

    通过这些给定的事件,Predictor的目标就可以评估它成功的可能性, 然后再适时触发操作。每一项事件都有其成功的机率、优先级以及时间戳,这些可以在内部维护一个用优先级管理的队列,也是优化的一个手段。最终,对于这个队列中发出的每一个请求的成功率,都可以被Predictor追踪到。基于这些数据,Predictor就可以进一步优化它的决策。


    Chrome网络架构小结
    • Chrome使用多进程架构,将渲染进程同浏览器进程隔离开来。
    • Chrome维护着一个资源分发器的实例(a single instance of the resource dispatcher), 它运行在浏览器内核进程,并在各个渲染进程间共享。
    • 网络层是跨平台的,大部分情况下以单进程库存在。
    • 网络层使用非阻塞式(no-blocking)操作来管理所有网络任务。
    • 共享的网络层支持有效的资源排序、复用、并为浏览器提供在多进程间进行全局优化的能力。
    • 每一个渲染进程通过IPC和资源分发器(resource dispatcher)通讯。
    • 资源分发器(Resource dispatcher)通过自定义的IPC Filter解析资源请求。
    • Predictor在解析资源请求和响应网络事务中学习,并对后续的网络请求进行优化。
    • Predictor会根据学习到的网络事务模式预测性的进行DNS解析, TCP握手,甚至是资源请求,为用户实际操作时节省数百毫秒的时间。


    了解晦涩的内部细节后,让我们来看一下用户可以感受到的优化。一切从全新的Chrome开始。


    优化冷启动(Cold-Boot)体验 

    第一次启动浏览器,它当然不可能了解你的使用习惯和喜欢的页面。但事实上,我们大多数会在浏览器的冷启动后做些类似的事情,比如到电子邮箱查看邮件,加一些新闻页面、社交页面及内部页面到我的最爱,诸如此类。这些页面各有不同,但它们仍然具有一些相似性,所以Predictor仍然可以对这个过程提速。


    Chrome记下了用户在全新启动浏览器时最常用的10个域名。当浏览器启动时,Chrome会提前对这些域名进行DNS预解析。你可以在Chrome中使用chrome://dns查看到这个列表。在打开页面的最上面的表格中会列出启动时的备选域名列表。


    通过Omnibox优化与用户的交互

    引入Omnibox是Chrome的一项创新, 并不是简单地处理目标的URL。除了记录之前访问过的页面URL,它还与搜索引擎的整合,并且支持在历史记录中进行全文搜索(比如,直接输入页面名称)。

    当用户输入时,Omnibox自动发起一个行为,要么查找浏览记录中的URL, 要么进行一次搜索。每一次发起的操作都会被加以评分,以统计它的性能。你可以在Chrome输入chrome://predictors来观察这些数据。


    Chrome维护着一个历史记录,内容包括用户输入的前置文字,采用的行为,以命中的资数。 在上面的列表,你可以看到,当输入g时,有76%的机会尝试打开Gmail. 如果再补充一个m (就是gm), 打开Gmail的可能性增加到99.8%。

    那么网络模块会做什么呢?上表中的黄色和绿色对于ResourceDispatcher非常重要。如果有一个一般可能性的页面(黄色), Chrome就是发起DNS预解析。如果有一个高可能性的页面(绿色),Chrome还会在DNS解析后发起TCP预连接。如果这两项都完成了,用户仍然继续录入,Chrome就会在一个隐藏的页签进行预渲染(pre-render)。


    相对的,如果输入的前置文字找不到合适的匹配项目,Chrome会向搜索引擎服务者发起DNS预解析和TCP预连,以获取相似的搜索结果。


    平均而言用户从填写查询内容到评估给出的建议需要花费数百毫秒。 此时Chrome可以在后台进行预解析,预连接,甚至进行预渲染。再当用户准备按下回车键时,大量的网络延迟已经被提前处理掉了。


    优化缓存性能 

    最快的请求就是没有请求。 无论何时讨论性能,都不能不谈缓存。相信你已经为页面上所有资源的都提供了Expires, ETag, Last-Modified和Cache-Control这些响应头信息(response headers)。什么? 还没有?那你还是先处理好再来看吧!


    Chrome有两种不同的内部缓存的实现:一种备份于本地磁盘(local disk),另一种则存储于内存(in-memory)中。内存模式(in-memory)主要应用于无痕浏览模式(Incognito browsing mode),并在关闭窗口清除掉。 两种方式使用了相同的内部接口(disk_cache::Backend, 和disk_cache::Entry),大大简化了系统架构。如果你想实现一个自己的缓存算法,可以很容易地实现进去。


    在内部,磁盘缓存(disk cache)实现了它自己的一组数据结构, 它们被存储在一个单独的缓存目录里。其中有索引文件(在浏览器启动时加载到内存中),数据文件(存储着实际数据,以及HTTP头以及其它信息)。比较有趣的是,16KB以下的文件存储于共同的数据块文件中(data block-files,即小文件集中存储于一个大文件中),其它较大的文件才会存储到自己专属的文件中。最后,磁盘缓存的淘汰策略是维护一个LRU,通过比如访问频率和资源的使用时间(age)的度量进行管理。



    在Chrome开个页签,输入chrome://net-internals/#httpCache。 如果你要看到实际的HTTP数据和缓存的响应处理,可以打开chrome://cache, 里面会列出所有缓存中可用的资源。打开每一项,还可以看到详细的数据头等信息。


    优化DNS预连接

    前面已经多次提到了DNS预解析,在深入实现之前,先汇总一下DNS预解析的场景和理由:

    • 运行在渲染进程中的WebKit文档解析器(document parser), 会为当前页面上所有的链接提供一个主机名(hostname)列表,Chrome可以选择是否提前解析。
    • 当用户要打开页面时,渲染进程先会触发一个鼠标悬停(hover)或按键(button down)事件。
    • Omnibox可能会针对一个高可能性的建议页面发起解析请求。
    • Chrome Predictor会基于过往浏览记录和资源请求数据发起主机解析请求。(下面会详细解释。)
    • 页面本身会显式地要求Chrome对某些主机名称进行预解析。

    上述各项对于Chrome都只是一个线索。 Chrome并不保证预解析一定会被执行,所有的线索会由Predictor进行评估,以决定后续的操作。最坏的情况下,可能无法及时解析主机名,用户就必须等待一个DNS解析时间,然后是TCP连接时间,最后是资源加载时间。Predictor会记下这个场景,在未来决策时相应地加以参考。总之,一定是越用越快。


    之前提过到Chrome可以记住每个页面的拓扑(topology),并可以基于这个信息进行加速。还记得吧,平均每个页面带有88个资源,分别来自于30多个独立的主机。每打开这个页面,Chrome会记下资源中比较常用的主机名,在后续的浏览过程中,Chrome就会发起针对某些主机或者全部主机的DNS解析,甚至是TCP预连接!



    使用chrome://dns 就可以观察到上面的数据(Google+页面), 其中有6个子资源对应的主机名,并记录了DNS预解析发生的次数,TCP预连接发生的次数,以及到每个主机的请求次数。这些数据就可以让Chrome Predictor执行相应的优化决策。

    除了内部事件通知外,页面设计者可以在页面中嵌入如下的语句请求浏览器进行预解析:


      <link rel="dns-prefetch" href="//host_name_to_prefetch.com">
    


    之所以有这个需求,一个典型的例子是重定向(redirects). Chrome本身没办法判断出这种模式,通过这种方式则可以让浏览器提前进行解析。


    具体的实现也是因版本而有所差异,总体而言,Chrome中的DNS处理有两个主要的实现:1.基于历史数据(historically), 通过调用平台无关的getaddrinfo()系统函数实现。2.代理操作系统的DNS处理方法,这种方法正在被Chrome自行实现的一套异步DNS解析机制(asynchronous DNS resolver)所取代。


    依赖于系统的实现,代码少而且简单,但是getaddrInfo()是一个阻塞式的系统调用,无法有效地并行多个查询操作。经验数据还显示,并行请求过多甚至会超出路由器的负额。Chrome为此设计了一个复杂的机制。对于其中带有worker-pool的预解析, Chrome只是简单的发送getaddrinfo() 调用, 同时阻塞worker thread直到收到响应数据。因为系统有DNS缓存的原因,针对解析过的主机,解析操作会立即返回。 这个过程简单,有效。


    但还不够! getaddrinfo()隐藏了太多有用的信息,比如Time-to-live(TTL)时间戳, DNS缓存的状态等。于是Chrome决定自己实现一套跨平台的异步DNS解析器。


    这个新技术可以支持以下优化:

    • 更好地控制重转的时机,有能力并行执行多个查询操作。
    • 清晰地记录TTLs。
    • 更好地处理IPv4和IPv6的兼容。
    • 基于RTT和其它事件,针对不同服务器进行错误处理(failover)

    Chrome仍然进行着持续的优化. 通过chrome://histograms/DNS可以观察到DNS度量数据:


    上面的柱状图展示了DNS预解析延迟时间的分布:比如将近50%(最右侧)的查询在20ms内完成。这些数据基于最近的浏览操作(采样9869次),用户可以选择是否报告这些使用数据,然后这些数据会以匿名的形式交由工程团队加以分析,这样就可以了解到功能的性能,以及未来如何进一步调整。周而复始,不断优化。

    转载请注明出处:http://blog.csdn.net/horkychen
    前一篇:Google Chrome中的高性能网络(一)
    原文地址: http://www.igvita.com/posa/high-performance-networking-in-google-chrome/


    3楼u0118693163天前 15:57感谢分享2楼mynote4天前 22:54精辟,好文章。1楼suannai03144天前 10:53您的文章已被推荐到博客首页和个人页侧边栏推荐文章,感谢您的分享。

        
    [3] 高仿QQ的手机管家的小火箭加紧
        来源: 互联网  发布时间: 2014-02-18
    高仿QQ的手机管家的小火箭加速

    1、前言

    相信很多人都用过腾讯的手机管家,用过这个App的人都应该知道桌面的火箭一键加速这个功能,当然这里我不是推荐大家去使用手机管家,相反这个功能大家还是小心为妙,我的U8800加完速之后快是快了,但这家伙把我手机的任务栏的进程都给搞蹦死了,去年买了个表啊。。。

    吐槽不多说,来正题,最近刚好在学UI设计就去研究一下这个小火箭是怎么做出来的。先来了解一下小火箭有神马动作先,首先在没有触碰它时,就是一个电源的显示或是

    一个图标依附在屏幕的两侧,点击变成小火箭,可以跟随拖动,当没有放到指定位置就在次回去屏幕两侧。当放到了指定位置就会出现一个火箭发射的动画。了解完效果,我

    们继续说。

    2、完成的效果图


    3、简单设计过程

    自定义一个View完成火箭的拖动、显示,然后拖动到指定位置后就回调一个接口播放火箭发射动画。自定义View里面的关键就是动态的改变matrix,以达到火箭移动的效果

    4、核心代码

    自定义View的代码

    package com.spring.lettel;
    
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
    import android.graphics.Paint;
    import android.graphics.Point;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    
    /**
     * 火箭主体类
     * @author wissea
     *
     */
    public class Rocket extends View {
    
    	private Bitmap bitmap;
    	private Bitmap rocket;
    	//文字栏的三种状态
    	private Bitmap[] stand = {
    			BitmapFactory.decodeResource(getResources(),
    					R.drawable.desktop_bg_tips_1),
    			BitmapFactory.decodeResource(getResources(),
    					R.drawable.desktop_bg_tips_2),
    			BitmapFactory.decodeResource(getResources(),
    					R.drawable.desktop_bg_tips_3) };
    	private Matrix matrix = new Matrix();
    	private Paint paint = new Paint();
    
    	// 是否触摸
    	private boolean isTouch = false;
    	private Point point = new Point();
    
    	private LocationChangeListener changeListener	=null;
    	//记录屏幕的大小
    	private int screenW;
    	private int screenH;
    
    	//灰机和提示是否重合了
    	private boolean isFly = false;
    
    	public Rocket(Context context, AttributeSet attrs, int defStyle) {
    		super(context, attrs, defStyle);
    	}
    
    	public Rocket(Context context, AttributeSet attrs) {
    		super(context, attrs);
    		bitmap = BitmapFactory.decodeResource(getResources(),
    				R.drawable.floating_desktop_bg_danger);
    		rocket = BitmapFactory.decodeResource(getResources(),
    				R.drawable.desktop_rocket_launch_1);
    		screenW = ((Activity) context).getWindowManager().getDefaultDisplay()
    				.getWidth();
    		screenH = ((Activity) context).getWindowManager().getDefaultDisplay()
    				.getHeight();
    	}
    
    	public Rocket(Context context) {
    		super(context);
    	}
    
    	@Override
    	protected void onDraw(Canvas canvas) {
    		super.onDraw(canvas);
    		//判断Touch
    		if (!isTouch) {
    			matrix.reset();
    			if (isFly) {
    				if(changeListener!=null)
    					changeListener.onchange();
    			} else {
    				if (point.x < screenW / 2) {
    					matrix.postTranslate(0, point.y);
    				} else {
    					matrix.postTranslate(screenW - bitmap.getWidth(), point.y);
    				}
    				canvas.drawBitmap(bitmap, matrix, paint);
    			}
    		} else {
    			matrix.reset();
    			int c = point.x % 2;
    			matrix.postTranslate(screenW / 2 - stand[c].getWidth() / 2, screenH
    					- stand[c].getHeight() - 100);
    			//判断重合
    			if (Math.abs(screenW / 2 - (point.x - rocket.getWidth()/2)) < stand[c]
    					.getWidth() / 2
    					&& Math.abs(screenH - stand[c].getHeight() - 100
    							- (point.y - rocket.getHeight())) < stand[c]
    								.getHeight()) {
    				canvas.drawBitmap(stand[2], matrix, paint);
    				isFly = true;
    			} else {
    				isFly		=false;
    				canvas.drawBitmap(stand[c], matrix, paint);
    			}
    			matrix.reset();
    			matrix.postTranslate(point.x - rocket.getWidth()/2,
    					point.y - rocket.getHeight());
    			canvas.drawBitmap(rocket, matrix, paint);
    		}
    
    	}
    
    	@Override
    	public boolean onTouchEvent(MotionEvent event) {
    		switch (event.getAction()) {
    		case MotionEvent.ACTION_DOWN:
    			//过滤无效点击
    			if ((event.getX() < screenW - bitmap.getWidth() && event.getX() > bitmap
    					.getWidth())
    					|| Math.abs(point.y - event.getY()) > bitmap.getHeight()) {
    				return false;
    			}
    			isTouch = true;
    			break;
    		case MotionEvent.ACTION_MOVE:
    			//更新坐标
    			point.x = (int) event.getX();
    			point.y = (int) event.getY();
    			break;
    		case MotionEvent.ACTION_CANCEL:
    			isTouch = false;
    			break;
    		case MotionEvent.ACTION_UP:
    			isTouch = false;
    			break;
    		}
    		invalidate();
    		return true;
    	}
    	//重置状态
    	public void reset(){
    		isFly	=false;
    		point.y		=screenH/2;
    		invalidate();
    	}
    	//监听重合
    	public void setOnChangeListener(LocationChangeListener changeListener){
    		this.changeListener			=changeListener;
    	}
    
    }
    

    5、总结

    这个UI制作的时候老是纠结于,在View里面播放动画,找了老半天没有找到解决方法,最后就把动画放到了外面回调一下,虽然大体的效果出来了,但个人觉得还是有

    不完善的地方,比如发射动画不是很平滑,没有加入电量显示,没有控制边界,小火箭拉到屏幕外后就看不到控制的小圆点了。最后欢迎大家的讨论,和指点。


    项目源码


    5楼weidi1989前天 16:20求一个gif截图工具,谢谢!nway.ping.li@gmail.comRe: hxc2008q昨天 17:49回复weidi1989n这个还真没有,纯手工打造4楼u011908543前天 11:53http://pp.163.com/sfzyfd/pp/10771140.htmlnhttp://pp.163.com/sfzyfd/pp/10771141.htmlnhttp://photo.163.com/2907819113@qq.com/#m=2&aid=257662720&pid=8474759220nhttp://photo.163.com/2907819113@qq.com/#m=2&aid=257662720&pid=8474788840nhttp://photo.163.com/2907819113@qq.com/#m=2&aid=257662720&pid=8474788836nhttp://photo.163.com/2907819113@qq.com/#m=2&aid=257662720&pid=8474798601nhttp://photo.163.com/2907819113@qq.com/#m=2&aid=257662720&pid=8474798600nhttp://photo.163.com/2907819113@qq.com/#m=2&aid=257662720&pid=8474808629nhttp://photo.163.com/2907819113@qq.com/#m=2&aid=257662720&pid=8474768975nhttp://t.163.com/event/info/eventId/-5955234399273042569nhttp://zhan.renren.com/lysfzy?gid=3602888498042794817nhttp://www.docin.com/p-695529349.htmlnhttp://ishare.iask.sina.com.cn/f/61219729.htmlnhttp://t.home.news.cn/interview/lysfzy3楼suannai0314前天 11:36您的文章已被推荐到博客首页和个人页侧边栏推荐文章,感谢您的分享。2楼Perley3天前 13:35工程可以运行,效果还不错,顶一个!nPS:楼主可以去腾讯面试了Re: hxc2008q前天 10:46回复Perleyn哎,去年腾讯的笔试题都没有趟过去1楼qq5231152374天前 17:42我敲代码的时候也老是纠结怎么设计类,感觉时mvc没弄熟悉。Re: hxc2008q4天前 18:11回复qq523115237n个人觉得熟能生巧吧,写多了一点,总结一下,就不纠结了Re: qq5231152373天前 12:15回复hxc2008qn嗯,大学的时候主要是写短代码没涉及到这些,现在多写点就习惯了。n楼主不用回复了,免得我心里觉得不回复你过意不去。就永远都终止不了了。

        
    最新技术文章:
    ▪Android开发之登录验证实例教程
    ▪Android开发之注册登录方法示例
    ▪Android获取手机SIM卡运营商信息的方法
    ▪Android实现将已发送的短信写入短信数据库的...
    ▪Android发送短信功能代码
    ▪Android根据电话号码获得联系人头像实例代码
    ▪Android中GPS定位的用法实例
    ▪Android实现退出时关闭所有Activity的方法
    ▪Android实现文件的分割和组装
    ▪Android录音应用实例教程
    ▪Android双击返回键退出程序的实现方法
    ▪Android实现侦听电池状态显示、电量及充电动...
    ▪Android获取当前已连接的wifi信号强度的方法
    ▪Android实现动态显示或隐藏密码输入框的内容
    ▪根据USER-AGENT判断手机类型并跳转到相应的app...
    ▪Android Touch事件分发过程详解
    ▪Android中实现为TextView添加多个可点击的文本
    ▪Android程序设计之AIDL实例详解
    ▪Android显式启动与隐式启动Activity的区别介绍
    ▪Android按钮单击事件的四种常用写法总结
    ▪Android消息处理机制Looper和Handler详解
    ▪Android实现Back功能代码片段总结
    ▪Android实用的代码片段 常用代码总结
    ▪Android实现弹出键盘的方法
    ▪Android中通过view方式获取当前Activity的屏幕截...
    ▪Android提高之自定义Menu(TabMenu)实现方法
    ▪Android提高之多方向抽屉实现方法
    ▪Android提高之MediaPlayer播放网络音频的实现方法...
    ▪Android提高之MediaPlayer播放网络视频的实现方法...
    ▪Android提高之手游转电视游戏的模拟操控
     


    站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3