iOS/Android browser: showing a zoomed preview of button on touchmove

筅森魡賤 提交于 2020-01-06 07:20:46

问题


I'm trying to create behavior similar to iPhone keyboard (see included image). As in, when user starts and moves touch, she sees a zoomed version of the element that is touched, and selection would happen when on touch up. I'm using Zepto.

I can get the touch coordinates correctly, but have trouble finding the object that's under the finger. I'm using below code to check which element is returned as target of the event.

$("#myList li").live('touchmove', function(event) {
  console.log(event.touches[0].target.innerHTML);
});

This returns always the event that was on starttouch.

On Apple documentation the touch should have event.touches event.changedTouches event.targetTouches

I've tried checking the first element on each of the objects, but they all seem to contain just the starttouch-element as target. Is there something I'm missing here?

I get the coordinates for the touch correctly from

var positionTop = event.touches[0].pageY;
var positionLeft = event.touches[0].pageX;

If all else fails, I started to think maybe there's a way to find the DOM-element under the touch with the coordinates.

Any ideas are appreciated.


回答1:


The object that is under the touch event is given by event.target. Also, you should bind to touchstart and touchend events. See this example I made:

http://ampersand.no.de/iOSkeyboard.html

Source code:

<html>

<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<style>
body{
    font-family:arial;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -o-user-select: none;
    user-select: none;
}
.entry{
    border:1px solid green;
    color:darkGreen;
    margin:25px;
    font-size:25px;
    font-family:verdana, arial,"sans serif";
    padding:10px;
    width:500px;
    word-wrap:break-word;
}
.wrapper{
    height:200px;
    position:relative;
    margin:25px;
}
.keyboard{
    position:absolute;
    bottom:0;
}

.key{
    border:1px solid darkGray;
    display:inline-block;
    text-align:center;
    cursor:pointer;
    margin-top:1px;
    border-radius: 4px;
    font-family:arial,"sans serif";
    width:30px;
    height:30px;
    line-height:30px;
}

.shift{
    width:60px;
    margin-left:35px;
}
.spacebar{
    width:126px;
}
.backspace{
    width:60px;
}

.keypress{
    border:1px solid blue;
}

#floatKey{
    border-bottom-left-radius:10px;
    border-bottom-right-radius:10px;
    border-bottom:0px;
    border-color:blue;
    font-weight:bold;
    font-size:24px;
    cursor:pointer;
    width:40px;
    height:40px;
    line-height:40px;
    background-color:white;
    -moz-box-shadow: -5px 0px 5px #ccc;
    -webkit-box-shadow: -5px 0px 5px #ccc;
    box-shadow: -5px 0px 5px #ccc;
}

.touchStart{
    border-color:blue;
    border-top:0px;
    border-top-left-radius:0px;
    border-top-right-radius:0px;
    -moz-box-shadow: -5px 5px 5px #ccc;
    -webkit-box-shadow: -5px 5px 5px #ccc;
    box-shadow: -5px 5px 5px #ccc;
}

</style>
</head>

<body>
<h3>iOS-style keyboard examples</h3>
<div class="entry">|</div>

<div class="wrapper">
    <div>With mouse events:</div>
    <div class="keyboard" id="mousekb">
        <div class="row">
            <span>1</span>
            <span>2</span>
            <span>3</span>
            <span>4</span>
            <span>5</span>
            <span>6</span>
            <span>7</span>
            <span>8</span>
            <span>9</span>
            <span>0</span>
        </div>
        <div class="row">
            <span>q</span>
            <span>w</span>
            <span>e</span>
            <span>r</span>
            <span>t</span>
            <span>y</span>
            <span>u</span>
            <span>i</span>
            <span>o</span>
            <span>p</span>
        </div>
        <div class="row" style="margin-left:18px">
            <span>a</span>
            <span>s</span>
            <span>d</span>
            <span>f</span>
            <span>g</span>
            <span>h</span>
            <span>j</span>
            <span>k</span>
            <span>l</span>
        </div>
        <div class="row">
            <span>z</span>
            <span>x</span>
            <span>c</span>
            <span>v</span>
            <span>b</span>
            <span>n</span>
            <span>m</span>
            <span>,</span>
            <span>.</span>
        </div>
        <div class="row">
            <span class="shift">shift</span>
            <span class="spacebar">&nbsp;</span>
            <span class="backspace">&lArr;</span>
        </div>
    </div>
</div>

<div class="entry">|</div>
<div class="wrapper">
    <div>With touch events (zoom in for better view):</div>
    <div class="keyboard" id="touchkb">
        <div class="row">
            <span>1</span>
            <span>2</span>
            <span>3</span>
            <span>4</span>
            <span>5</span>
            <span>6</span>
            <span>7</span>
            <span>8</span>
            <span>9</span>
            <span>0</span>
        </div>
        <div class="row">
            <span>q</span>
            <span>w</span>
            <span>e</span>
            <span>r</span>
            <span>t</span>
            <span>y</span>
            <span>u</span>
            <span>i</span>
            <span>o</span>
            <span>p</span>
        </div>
        <div class="row" style="margin-left:18px">
            <span>a</span>
            <span>s</span>
            <span>d</span>
            <span>f</span>
            <span>g</span>
            <span>h</span>
            <span>j</span>
            <span>k</span>
            <span>l</span>
        </div>
        <div class="row">
            <span>z</span>
            <span>x</span>
            <span>c</span>
            <span>v</span>
            <span>b</span>
            <span>n</span>
            <span>m</span>
            <span>,</span>
            <span>.</span>
        </div>
        <div class="row">
            <span class="shift">shift</span>
            <span class="spacebar">&nbsp;</span>
            <span class="backspace">&lArr;</span>
        </div>
    </div>
</div>

<div id="floatKey" class="key" style="display:none"></div>

<script>
SHIFT=false;
$('.keyboard span').addClass('key');


function touchStart(ev){
    ev.preventDefault();
    var o=$(ev.target).offset();
    $('#floatKey').html($(ev.target).html())
        .show()
        .offset({top:(o.top-$('#floatKey').outerHeight()), left:(o.left-5)});
    $(ev.target).addClass('touchStart');
}

function touchEnd(ev){
    ev.preventDefault();
    $('#floatKey').hide();
    $(ev.target).removeClass('touchStart');
}

function keyrelease(ev){
    ev.preventDefault();
    outlineKey(ev.target);
    $(ev.target).removeClass('keydown');
    $('#floatKey').removeClass('keydown');
    var text=$('.entry').eq(0).text();
    $('.entry').text(text.substr(0,text.length-1)+$(ev.target).text()+'|');
}

function shiftKey(ev){
    ev.preventDefault();
    if(SHIFT){
        $('.keyboard span').not('.shift').each(function(idx,el){
            $(el).text($(el).text().toLowerCase());
        })
        $(ev.target).removeClass('keypress');
        SHIFT=false;
    }else{
        $('.keyboard span').not('.shift').each(function(idx,el){
            $(el).text($(el).text().toUpperCase());
        })
        $(ev.target).addClass('keypress');
        SHIFT=true;
    }

}

function outlineKey(el){
    $(el).addClass('keypress');
    setTimeout(function(){
        $(el).removeClass('keypress')
    },500);
}
function backspace(ev){
    ev.preventDefault();
    outlineKey(ev.target);
    var text=$('.entry').eq(0).text();
    $('.entry').text(text.substr(0,text.length-2)+'|');
}

//mouse keyboard
$('#mousekb span').not('.spacebar,.shift,.backspace').bind('mouseenter',touchStart);
$('#mousekb span').not('.spacebar,.shift,.backspace').bind('mouseout',touchEnd)
$('#mousekb span').not('.shift,.backspace').bind('mouseup',keyrelease)
$('#mousekb .shift').bind('mouseup',shiftKey);
$('#mousekb .backspace').bind('mouseup',backspace);

//touch keyboard:
$('#touchkb span').not('.spacebar,.shift,.backspace').bind('touchstart',touchStart);
$('#touchkb span').not('.spacebar,.shift,.backspace').bind('touchend',touchEnd);
$('#touchkb span').not('.shift,.backspace').bind('touchend',keyrelease)
$('#touchkb .shift').bind('touchend',shiftKey);
$('#touchkb .backspace').bind('touchend',backspace);

</script>
</body> 

UPDATE Ok, I found it, and 'it' is called document.getElementFromPoint(). There is some documentation on Mozilla's site (https://developer.mozilla.org/En/DOM/Document.elementFromPoint). It'll get the element given the top and left coordinates. This can be easily used to track which key the finger is currently over. I've updated my code example to use this awesome function. Here are some updated functions that get the current touch element and update the 'hover key':

//functions for touchmove implementation:
function getElAtTouchPosition(ev){
    var touch = ev.originalEvent.touches[0] || ev.originalEvent.changedTouches[0] || ev.touches[0];
    var top = touch.pageY;
    var left = touch.pageX;
    var el=document.elementFromPoint(left,top);
    if(el.className=='key'){
        return el;
    }else{
        return null;
    }
}

function move(ev){
    ev.stopImmediatePropagation();
    var el=getElAtTouchPosition(ev);
    if(el.className=='key' && el!=currentHoverKey){
        updateFloatKey(el);
        currentHoverKey=el;
    }
}
function updateFloatKey(el){
    var o=$(el).offset();
    $(currentHoverKey).removeClass('touchStart');
    $('#floatKey').html($(el).html())
        .show()
        .offset({top:(o.top-$('#floatKey').outerHeight()), left:(o.left-5)});
    $(el).addClass('touchStart');
}

function touchStart2(ev){
    ev.preventDefault();
    updateFloatKey(ev.target);
    currentHoverKey=ev.target;
}

function touchStop2(ev){
    $(currentHoverKey).removeClass('touchStart');
    $('#floatKey').hide();
}

Check out the example to see how all of this is used. I have tested this on iPad 2 (iOS 4.3), and it works. It still needs some tweaking to improve smoothness and account for cases when the touchmove ends up on a non-key element. I'd be interested to see how this works on Android. I haven't completed the text entry code for the third keyboard, but you can combine some of my previous code to make it work. Good luck.

Note: It is extremely important to block touchmove event propagation/bubbling up the DOM tree. If it does propagate, then it will turn into a scroll, and during scrolling on iOS devices DOM manipulation is disabled, so you won't be able to update the 'hover key'. You need to account for all edge cases when the touchmove event fires over a non-key element.



来源:https://stackoverflow.com/questions/6045817/ios-android-browser-showing-a-zoomed-preview-of-button-on-touchmove

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!