当前位置:  编程技术>移动开发
本页文章导读:
    ▪Coroutine,您究竟干了什么?(小续)        Coroutine,你究竟干了什么?(小续)  前篇中讲了一些自己关于Coroutine的理解,后来陆陆续续的又想到了一些,在此简单记录一下,内容不多,故作“小”续吧 :)     之前的示例程序基.........
    ▪ 上万网友力荐的30份Android腾挪开发技术文档汇总        上万网友力荐的30份Android移动开发技术文档汇总在优势方面,Android平台首先就是其开发性,开发的平台允许任何移动终端厂商加入到Android联盟中来。显著的开放性可以使其拥有更多的开发者.........
    ▪ hitTest:withEvent       hitTest:withEvent:窗口对象使用点击检测(hit-testing)以及响应链(responder chain) 来查找接收该触摸事件的视图. iOS系统检测到手指触摸(Touch)操作时会将其放入当前活动Application的事件队列, UIApp.........

[1]Coroutine,您究竟干了什么?(小续)
    来源: 互联网  发布时间: 2014-02-18
Coroutine,你究竟干了什么?(小续)

  前篇中讲了一些自己关于Coroutine的理解,后来陆陆续续的又想到了一些,在此简单记录一下,内容不多,故作“小”续吧 :)

 

  之前的示例程序基本实现了一个自己的WaitForSeconds,功能上及使用上都与Unity自建的WaitForSeconds类似,另外的,如果我们进一步考虑WaitForFixedUpdate和WaitForEndOfFrame这类的YieldInstruction,我们是否也可以自己实现?其中的原理又是什么呢?

  先让我们来看一张MonoBehaviour的生命周期图(外国友人所做,原帖在这里):

  从图中我们可以看到,Unity对于MonoBehaviour中Coroutine的处理,实际上并不是简单的单一步骤,而是采取了类似分阶段处理的方式:即在每次FixedUpdate之后进行WaitForFixedUpdate的处理,每次Update之后进行WaitForSeconds的处理,而在每一帧结束之前,进行WaitForEndOfFrame的处理。那么依此而看,先前示例中简单的LateUpdate模拟就有些捉襟见肘了:WaitForSeconds可能勉强还可以应付,但是像WaitForFixedUpdate以及WaitForEndOfFrame这类YieldInstruction,这种方式便应付不来了……

  不过如果从原理上来讲的话,上面的那些YieldInstruction还是相似的,问题都集中于何时调用IEnumerator的MoveNext()操作而已,如WaitForSeconds,就是在其延时结束之后调用MoveNext(),而像WaitForFixedUpdate,便是在每次FixedUpdate之后才调用MoveNext(),另外的WaitForEndOfFrame,则是在每帧结束之前调用对应的IEnumerator的MoveNext()。如果需要实际实现的话,目前想到的一种方法便是创建几种不同类型的CoroutineManager,譬如WaitForSecondsCoroutineManager、WaitForFixedUpdateCoroutineManager等等,用于在不同更新时刻处理其中的IEnumerator,原理上都是控制IEnumerator MoveNext()的实际,在此我并没有加以实现,一是自己懒惰了些(……),二是Unity本身也未明显提供用以实现这类处理的回调方法,不过有兴趣的朋友倒是可以试试 :)

  另外想到的一个问题就是StartCoroutine的嵌套问题,即在某一个Coroutine中又以yield return的方式开启了另一个Coroutine,例如以下代码:

void Start() {

// start unity coroutine

StartCoroutine(UnityCoroutine());

}

IEnumerator UnityCoroutine() {

Debug.Log("Unity coroutine begin at time : " + Time.time);

yield return new WaitForSeconds(2);

yield return StartCoroutine(InnerUnityCoroutine());

Debug.Log("Unity coroutine end at time : " + Time.time);

}

IEnumerator InnerUnityCoroutine() {

Debug.Log("Inner Unity coroutine begin at time : " + Time.time);

yield return new WaitForSeconds(2);

Debug.Log("Inner Unity coroutine end at time : " + Time.time);

}

  那么“外层”的UnityCoroutine只有在“内层”的InnerUnityCoroutine“执行”完毕之后才会继续“执行”,程序结果大概是这个样子:

  在此简单一提,必须要采用yield return的方式才可以实现这种嵌套执行效果,简单的一个StartCoroutine只能创建一个“平行”的Coroutine,并不会产生嵌套效果,譬如如下代码:

void Start() {

// start unity coroutine

StartCoroutine(UnityCoroutine());

}

IEnumerator UnityCoroutine() {

Debug.Log("Unity coroutine begin at time : " + Time.time);

yield return new WaitForSeconds(2);

StartCoroutine(InnerUnityCoroutine());

Debug.Log("Unity coroutine end at time : " + Time.time);

}

IEnumerator InnerUnityCoroutine() {

Debug.Log("Inner Unity coroutine begin at time : " + Time.time);

yield return new WaitForSeconds(2);

Debug.Log("Inner Unity coroutine end at time : " + Time.time);

}

  那么最终的执行结果便会是这个样子:

  OK,那么如果我们需要自己实现这种嵌套机制,应该怎么做呢?实际上还是在特殊类型判断上做文章!在Unity中,每次调用StartCoroutine都会返回一个特殊的Coroutine类型,而这个类型便是我们实现嵌套Coroutine的突破口!好了,首先让我们实现一下自己的Coroutine类型:

//

//    <maintainer>Hugo</maintainer>

//    <summary>coroutine simple class</summary>

//

using UnityEngine;

using System.Collections.Generic;

public class CoroutineSimple {

public Stack<System.Collections.IEnumerator> innerEnumeratorStack;

public CoroutineSimple(Stack<System.Collections.IEnumerator> enumeratorStack) {

    innerEnumeratorStack = enumeratorStack;

}

}

  此处的Stack<System.Collections.IEnumerator>可能有些奇怪,实际上也确实如此(汗……),使用这种方式也仅是为了降低一点代码复杂度,因为我们现在要支持嵌套的Coroutine,于是使用了Stack<System.Collections.IEnumerator>这种类型,即每次我们都仅是处理某个Stack<System.Collections.IEnumerator>顶部的IEnumerator,一旦发现有嵌套的Coroutine产生,那便直接将对应的IEnumerator压栈,可能这么说还是有些许模糊,看一下新的CoroutineManager代码应该会更清晰一些:

//

//    <maintainer>Hugo</maintainer>

//    <summary>simple coroutine manager class</summary>

//

using UnityEngine;

using System.Collections.Generic;

public class CoroutineManager : MonoBehaviour {

public static CoroutineManager Instance {

    get;

private set;

}

 

List<Stack<System.Collections.IEnumerator>> m_enumerators = new List<Stack<System.Collections.IEnumerator>>();

List<Stack<System.Collections.IEnumerator>> m_enumeratorsBuffer = new List<Stack<System.Collections.IEnumerator>>();

void Awake() {

    if (Instance == null) {

    Instance = this;

}

else {

    Debug.LogError("Multi-instances of CoroutineManager");

}

}

void LateUpdate() {

    for (int i = 0; i < m_enumerators.Count; ++i) {

// handle CoroutineYieldInstruction here

if (m_enumerators[i].Peek().Current is CoroutineYieldInstruction) {

    CoroutineYieldInstruction yieldInstruction = m_enumerators[i].Peek().Current as CoroutineYieldInstruction;

if (!yieldInstruction.IsDone()) {

    continue;

}

}

// do normal move next

if (!m_enumerators[i].Peek().MoveNext()) {

m_enumerators[i].Pop();

if (m_enumerators[i].Count <= 0) {

        m_enumeratorsBuffer.Add(m_enumerators[i]);

}

continue;

}

if (m_enumerators[i].Peek().Current is CoroutineSimple) {

    // here we just push new enumerator

CoroutineSimple coroutineSimple = m_enumerators[i].Peek().Current as CoroutineSimple;

m_enumerators[i].Push(coroutineSimple.innerEnumeratorStack.Peek());

// NOTE: very tricky

// TODO: clear

m_enumerators.Remove(coroutineSimple.innerEnumeratorStack);

}

// other special enumerator here ...

}

// remove end enumerator

for (int i = 0; i < m_enumeratorsBuffer.Count; ++i) {

    m_enumerators.Remove(m_enumeratorsBuffer[i]);

}

m_enumeratorsBuffer.Clear();

}

public CoroutineSimple StartCoroutineSimple(System.Collections.IEnumerator enumerator) {

Stack<System.Collections.IEnumerator> newEnumeratorStack = new Stack<System.Collections.IEnumerator>();

newEnumeratorStack.Push(enumerator);

m_enumerators.Add(newEnumeratorStack);

return new CoroutineSimple(newEnumeratorStack);

}

}

  代码味道不是很好,还有不少Tricky,但是也算基本实现了嵌套的Coroutine处理,写个简单的“单元测试”:

  void Start() {

// start unity coroutine

StartCoroutine(UnityCoroutine());

    // start self coroutine

CoroutineManager.Instance.StartCoroutineSimple(SelfCoroutine());

}

IEnumerator UnityCoroutine() {

Debug.Log("Unity coroutine begin at time : " + Time.time);

yield return new WaitForSeconds(5);

yield return StartCoroutine(InnerUnityCoroutine());

Debug.Log("Unity coroutine end at time : " + Time.time);

}

IEnumerator SelfCoroutine() {

Debug.Log("Self coroutine begin at time : " + Time.time);

yield return new CoroutineWaitForSeconds(5);

yield return CoroutineManager.Instance.StartCoroutineSimple(InnerSelfCoroutine());

Debug.Log("Self coroutine end at time : " + Time.time);

}

IEnumerator InnerUnityCoroutine() {

    Debug.Log("Inner Unity Coroutine begin at time : " + Time.time);

yield return new WaitForSeconds(5);

yield return StartCoroutine(DeepUnityCoroutine());

Debug.Log("Inner Unity Coroutine end at time : " + Time.time);

}

IEnumerator DeepUnityCoroutine() {

    Debug.Log("Deep Unity Coroutine begin at time : " + Time.time);

yield return new WaitForSeconds(5);

Debug.Log("Deep Unity Coroutine end at time : " + Time.time);

}

IEnumerator InnerSelfCoroutine() {

Debug.Log("Inner Self Coroutine begin at time : " + Time.time);

yield return new CoroutineWaitForSeconds(5);

yield return CoroutineManager.Instance.StartCoroutineSimple(DeepSelfCoroutine());

Debug.Log("Inner Self Coroutine end at time : " + Time.time);

}

IEnumerator DeepSelfCoroutine() {

Debug.Log("Deep Self Coroutine begin at time : " + Time.time);

yield return new CoroutineWaitForSeconds(5);

Debug.Log("Deep Self Coroutine end at time : " + Time.time);

}

  执行结果基本如人所料:

  

 不过平心而论,虽然上面的示例实现了类似的Coroutine效果,但是从很多方面来看,Unity自建的Coroutine控制都更好更细致,自己实现的Coroutine则相对粗糙了不少,而且不要忘了,我们目前还不支持WaitForFixedUpdate、WaitForEndOfFrame、WWW这类的特殊类型呢!当然我们可以继续精化程序,但是我毕竟不是一个热爱重造车轮的人,上面的那些个代码也仅是为了学习一下Coroutine的原理,仅此而已,那么就让我们暂时到此为止吧~ :)

  下次再见了~~~


    
[2] 上万网友力荐的30份Android腾挪开发技术文档汇总
    来源: 互联网  发布时间: 2014-02-18
上万网友力荐的30份Android移动开发技术文档汇总

在优势方面,Android平台首先就是其开发性,开发的平台允许任何移动终端厂商加入到Android联盟中来。显著的开放性可以使其拥有更多的开发者,随着用户和应用的日益丰富,一个崭新的平台也将很快走向成熟。本文档为大家整理了一些广大网友喜欢的Android文档,希望对大家学习android开发有所帮助。

Google Android SDK开发范例大全(完整版)
《大话企业级android开发》完整版电子书
Android开发教程笔记
《Android 2.0游戏开发实战宝典》清晰影印版
《深入浅出Android--google手持设备应用程序设计》
Android应用框架原理与程序设计(第三简中版)
Android最佳学习路线图
《Android高级编程》中文高清电子版
《andbook》中文版【学习Android的入门级书】
Android 中文API合集(50篇)【chm】
[免豆下载]7本Android编程电子书合集
《Android入门到精通详解》清晰电子版
《Google Android手机游戏设计达人讲座》1-16章电子书
大话企业级android开发全14篇[中文书签高清版pdf]
Android终极开发教程 [PDF电子书]
Android开发问题集锦第1—6期
Android应用开发必备Java基础知识【电子书】
《Android基础教程》PDF电子书(影印版)
android应用开发详解源码下载
Android开发基础教程整理版【PDF】
Android应用框架原理与程序设计36技【PDF】
Android从入门到精通教程(PDF)
Android中文版教程集(exe电子书)
黑马程序员2013年Android培训教程(125集)
经典Android开发源代码大全
Android开发基础视频教程

    
[3] hitTest:withEvent
    来源: 互联网  发布时间: 2014-02-18
hitTest:withEvent:
窗口对象使用点击检测(hit-testing)以及响应链(responder chain) 来查找接收该触摸事件的视图.
iOS系统检测到手指触摸(Touch)操作时会将其放入当前活动Application的事件队列,
UIApplication会从事件队列中取出触摸事件并传递给key window(当前接收用户事件的窗口)处理,window对象首先会使用hitTest:withEvent:方法寻找此Touch操作初始点所在的视图(View),
即需要将触摸事件传递给其处理的视图,称之为hit-test view。




- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;   // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;   // default returns YES if point is in bounds




window对象会在首先在view hierarchy的顶级view上调用hitTest:withEvent:,此方法会在视图层级结构中的每个视图上调用pointInside:withEvent:,如果pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操作发生的位置,这个视图也就是hit-test view。




The implementation of hitTest:withEvent: in UIResponder does the following:




It calls pointInside:withEvent: of self
If the return is NO, hitTest:withEvent: returns nil. the end of the story.
If the return is YES, it sends hitTest:withEvent: messages to its subviews. it starts from the top-level subview, and continues to other views until a subview returns a non-nil object, or all subviews receive the message.
If a subview returns a non-nil object in the first time, the first hitTest:withEvent: returns that object. the end of the story.
If no subview returns a non-nil object, the first hitTest:withEvent: returns self
This process repeats recursively, so normally the leaf view of the view hierarchy is returned eventually.




However, you might override hitTest:withEvent to do something differently. In many cases, overriding pointInside:withEvent: is simpler and still provides enough options to tweak event handling in your application.
hitTest:withEvent: ===>调用pointInside:withEvent: ===> (point函数返回NO,结束分支,返回nil) // 返回YES ===> (当前view没有subview,hitTest返回self) // 当前view有subviews ===>从subviews的最上层view开始遍历,递归调用hitTest:withEvent:,直到hitTest返回第一个非nil对象 ===>(hitTest:withEvent:)
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
}
 
   这个函数的用处是判断当前的点击或者触摸事件的点是否在当前的view中。
   它被hitTest:withEvent:调用,通过对每个子视图调用pointInside:withEvent:决定最终哪个视图来响应此事件。如果 PointInside:withEvent:返回YES,然后子视图的继承树就会被遍历(遍历顺序中最先响应的为:与用户最接近的那个视图。 it starts from the top-level subview),即子视图的子视图继续调用递归这个函数,直到找到可以响应的子视图(这个子视图的hitTest:withEvent:会返回self,而不是nil);否则,视图的继承树就会被忽略。




    当我们需要重写某个UIView的继承类UIViewInherit的时候,如果需要重写hitTest:withEvent:方法,就会出现是否调用[super hitTest:withEvent:]方法的疑问?究竟是否需要都是看具体需求,这里只是说明调与不调的效果。
    如果不调用,那么重写的方法hitTest:withEvent:只会调用重写后的代码,根据所重写的代码返回self或nil,如果返回self那么你的这个UIViewInherit类会接受你的按键,然后调用touches系列方法;否则返回nil那么传递给UIViewInherit类的按键到此为止,它不接受它的父view给它的按键,即不会调用touches系列方法。这时,PointInside:withEvent:几乎没有作用。
    如果调用,那么[super hitTest:withEvent:]方法首先是根据PointInside:withEvent:的返回值决定是否递归调用所有子View的hitTest:withEvent:方法。对于子View的hitTest:withEvent:方法调用也是一样的过程,这样一直递归下去,直到最先找到的某个递归层次上的子View的hitTest:withEvent:方法返回非nil,这时候,调用即结束,最终会调用这个子View的touches系列方法。
 
     如果我们不想让某个视图响应事件,只需要重载 PointInside:withEvent:方法,让此方法返回NO就行了。

    
最新技术文章:
▪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