Permalink
Browse files

Add Capturing demo.

  • Loading branch information...
1 parent 50a6af1 commit 2ad44814c2e54049997bbe42e212389432160b20 @ialexi ialexi committed Apr 17, 2010
@@ -89,4 +89,71 @@
</head><body><div class="header"><a href="../../index.html" class="img"><img src="../../resources/logo.png" /></a><a href="../../index.html" class="here">Documentation
</a><a href="../../reference/index.html" class="item">SproutCore Reference
</a></div><div class="content"><h1>Capturing</h1>
+
+<p>There are many instances where you may have to capture touches. We'll consider scroll views,
+however, because it is very easy to explain <em>why</em> they need to be able to.</p>
+
+<p>If you are implementing a scroll view, you'll need to capture the touch before the target view gets it.</p>
+
+<p>This is because scroll views have some subtle quirks. For instance, a touch should not pass
+through to the actual target until a split-second has passed&emdash;this is to prevent flicker should
+the user decide to scroll rather than touch the target. Also, it needs to add itself to what is
+called the "touch responder stack" <em>before</em> the target view, so that the target view can hand control back
+simply as discussed above.</p>
+
+<h2>Touch Responder Stack</h2>
+
+<p>Very briefly mentioned in the "Touch Events" article, the <em>touch responder</em> is the view which
+"owns" a touch—the view which gets all touchesDragged events and the touchEnd for that touch.</p>
+
+<p>However, in our scroll view case, we want to pass control to the target view, but allow it
+to <em>transfer control back</em> (a process covered in "Releasing"). That means it needs to know
+what view to hand it back to. Also, what if you had a scroll view <em>within</em> a scroll view?</p>
+
+<p>To solve these issues, there is a "stack" of those views to which control can be passed back to.</p>
+
+<p>You generally work with it by either:</p>
+
+<ul>
+<li>Specifically telling it to "stack" your view when capturing a touch.</li>
+<li>Telling it to change touch responder to a touch responder in the stack (see Releasing)</li>
+</ul>
+
+<h2>Capturing</h2>
+
+<p>Capturing the touch is simple. Before starting at the target view and working its
+way up to the root calling touchStart (the same way all SproutCore events work),
+SproutCore's touch events go the opposite direction, starting at the root and working their way down
+to the target, calling a method named captureTouch:</p>
+
+<pre><code class='syntax js'><span class="variable">captureTouch</span>: <span class="keyword">function</span>(<span class="variable">touch</span>) {
+</code></pre>
+
+<p>If the view returns YES, the touchStart event will be sent directly to it.</p>
+
+<p>You could then use invokeLater to wait that split-second. But then what? You don't actually
+know what the target view should be. What you need is to start at the original target, and
+do the whole working up to it calling captureTouch and work down from it calling touchStart
+thing—but this time, starting from your own view, rather than the root. </p>
+
+<p>Thankfully, you can do this in one line of code:</p>
+
+<pre><code class='syntax js'><span class="variable">touch</span>.<span class="variable">captureTouch</span>(<span class="this">this</span>, <span class="class">YES</span>); <span class="comment">// the YES means stack, which I'm guessing you'd want to do</span>
+<span class="comment">// so that the new view can easily pass control back to this...</span>
+<span class="comment">// ... but you may know better than me.</span>
+</code></pre>
+
+<p>What happens next depends on whether or not you told it to stack your view:</p>
+
+<ul>
+<li>If stacked, you will receive a touchCancelled when the touch actually ends, unless the
+view which captures the touch hands control back to your view. If it does, you will <em>not</em>
+receive another <code class='syntax js'><span class="variable">touchStart</span></code>, but you <em>will</em> start receiving <code class='syntax js'><span class="variable">touchesDragged</span></code> and
+will receive a <code class='syntax js'><span class="variable">touchEnd</span></code> when the touch ends.</li>
+<li>If not stacked, your view will receive <code class='syntax js'><span class="variable">touchCancelled</span></code>.</li>
+</ul>
+
+<h2>What Does It Look Like?</h2>
+
+<p><a href='capturing.js' class='demo'>capturing.js</a></p>
</div><div class="footer"></div></body></html>
@@ -0,0 +1,75 @@
+/**
+ This is our test view. It will capture a touch, and, after one second,
+ pass it through to the child view. Depending on the shouldStack property,
+ it will stack while passing.
+
+ In this example, the top view stacks, the bottom one does not.
+*/
+var Tester = SC.View.extend({
+ backgroundColor: "white",
+
+ shouldStack: NO,
+ captureTouch: function() {
+ return YES;
+ },
+
+ touchStart: function(touch) {
+ this._hasTouch = touch;
+ this.get("layer").style.backgroundColor = "red";
+
+ // in one second, we'll pass the touch along.
+ this.invokeLater("beginContentTouches", 1000, touch);
+ },
+
+ beginContentTouches: function(touch) {
+ // if our touch hasn't changed in the meantime
+ if (touch === this._hasTouch) {
+ // we'll pass the touch along.
+ touch.captureTouch(this, this.get("shouldStack"));
+ }
+ },
+
+ touchEnd: function(touch) {
+ this._hasTouch = NO;
+ this.get("layer").style.backgroundColor = "white";
+ },
+
+ touchCancelled: function(touch) {
+ this._hasTouch = NO;
+ this.get("layer").style.backgroundColor = "white";
+ },
+
+ childViews: "inner".w(),
+ inner: SC.View.design({
+ layout: { left: 50, top: 50, right: 50, bottom: 50 },
+ backgroundColor: "gray",
+ touchStart: function() {
+ this.get("layer").style.backgroundColor = "blue";
+ },
+
+ touchEnd: function() {
+ this.get("layer").style.backgroundColor = "gray";
+ }
+
+ })
+
+});
+
+var MyExampleView = SC.View.extend({
+ backgroundColor: "#aaa",
+ childViews: "stacks doesNot".w(),
+ stacks: Tester.extend({
+ layout: { top: 10, left: 10, width: 200, height: 200 },
+ shouldStack: YES
+ }),
+
+ doesNot: Tester.extend({
+ layout: { top: 230, left: 10, width: 200, height: 200 },
+ shouldStack: NO
+ })
+});
+
+// bootstrap code :)
+exports.getDemoView = function() {
+ return MyExampleView;
+};
Oops, something went wrong. Retry.

0 comments on commit 2ad4481

Please sign in to comment.