天道酬勤,学无止境

反应长按事件(react long press event)

问题

有没有办法在react-web 应用程序中添加长按事件?

我有地址列表。 长按任何地址时,我想触发事件以删除该地址,然后是确认框。

回答1

我创建了一个带有钩子的代码沙盒来处理长按和点击。 基本上,在鼠标按下、触摸开始事件时,会使用setTimeout创建一个计时器。 当提供的时间过去时,它会触发长按。 在鼠标抬起、鼠标离开、触摸结束等时,计时器被清除。

useLongPress.js

import { useCallback, useRef, useState } from "react";

const useLongPress = (
    onLongPress,
    onClick,
    { shouldPreventDefault = true, delay = 300 } = {}
    ) => {
    const [longPressTriggered, setLongPressTriggered] = useState(false);
    const timeout = useRef();
    const target = useRef();

    const start = useCallback(
        event => {
            if (shouldPreventDefault && event.target) {
                    event.target.addEventListener("touchend", preventDefault, {
                    passive: false
                });
                target.current = event.target;
            }
            timeout.current = setTimeout(() => {
                onLongPress(event);
                setLongPressTriggered(true);
            }, delay);
        },
        [onLongPress, delay, shouldPreventDefault]
    );

    const clear = useCallback(
        (event, shouldTriggerClick = true) => {
            timeout.current && clearTimeout(timeout.current);
            shouldTriggerClick && !longPressTriggered && onClick();
            setLongPressTriggered(false);
            if (shouldPreventDefault && target.current) {
                target.current.removeEventListener("touchend", preventDefault);
            }
        },
        [shouldPreventDefault, onClick, longPressTriggered]
    );

    return {
        onMouseDown: e => start(e),
        onTouchStart: e => start(e),
        onMouseUp: e => clear(e),
        onMouseLeave: e => clear(e, false),
        onTouchEnd: e => clear(e)
    };
};

const isTouchEvent = event => {
return "touches" in event;
};

const preventDefault = event => {
if (!isTouchEvent(event)) return;

if (event.touches.length < 2 && event.preventDefault) {
    event.preventDefault();
}
};

export default useLongPress;

要使用钩子, App.js

import useLongPress from "./useLongPress";

export default function App() {

    const onLongPress = () => {
        console.log('longpress is triggered');
    };

    const onClick = () => {
        console.log('click is triggered')
    }

    const defaultOptions = {
        shouldPreventDefault: true,
        delay: 500,
    };
    const longPressEvent = useLongPress(onLongPress, onClick, defaultOptions);

    return (
        <div className="App">
            <button {...longPressEvent}>use  Loooong  Press</button>
        </div>
    );
}

类组件的旧答案:

您可以使用 MouseDown、MouseUp、TouchStart、TouchEnd 事件来控制可以充当长按事件的计时器。 查看下面的代码

class App extends Component {
  constructor() {
    super()
    this.handleButtonPress = this.handleButtonPress.bind(this)
    this.handleButtonRelease = this.handleButtonRelease.bind(this)
  }
  handleButtonPress () {
    this.buttonPressTimer = setTimeout(() => alert('long press activated'), 1500);
  }
  
  handleButtonRelease () {
    clearTimeout(this.buttonPressTimer);
  }

  render() {
    return (
      <div 
          onTouchStart={this.handleButtonPress} 
          onTouchEnd={this.handleButtonRelease} 
          onMouseDown={this.handleButtonPress} 
          onMouseUp={this.handleButtonRelease} 
          onMouseLeave={this.handleButtonRelease}>
        Button
      </div>
    );
  }
}
回答2

使用 react 16.8 中的钩子,您可以使用函数和钩子重写类。

import { useState, useEffect } from 'react';

export default function useLongPress(callback = () => {}, ms = 300) {
  const [startLongPress, setStartLongPress] = useState(false);

  useEffect(() => {
    let timerId;
    if (startLongPress) {
      timerId = setTimeout(callback, ms);
    } else {
      clearTimeout(timerId);
    }

    return () => {
      clearTimeout(timerId);
    };
  }, [callback, ms, startLongPress]);

  return {
    onMouseDown: () => setStartLongPress(true),
    onMouseUp: () => setStartLongPress(false),
    onMouseLeave: () => setStartLongPress(false),
    onTouchStart: () => setStartLongPress(true),
    onTouchEnd: () => setStartLongPress(false),
  };
}
import useLongPress from './useLongPress';

function MyComponent (props) {
  const backspaceLongPress = useLongPress(props.longPressBackspaceCallback, 500);

  return (
    <Page>
      <Button {...backspaceLongPress}>
        Click me
      </Button>
    </Page>
  );
};

回答3

不错的钩子! 但我想做一个小的改进。 使用useCallback包装事件处理程序。 这确保这些不会在每次渲染时更改。

import { useState, useEffect, useCallback } from 'react';

export default function useLongPress(callback = () => {}, ms = 300) {
  const [startLongPress, setStartLongPress] = useState(false);

  useEffect(() => {
    let timerId;
    if (startLongPress) {
      timerId = setTimeout(callback, ms);
    } else {
      clearTimeout(timerId);
    }

    return () => {
      clearTimeout(timerId);
    };
  }, [callback, ms, startLongPress]);

  const start = useCallback(() => {
    setStartLongPress(true);
  }, []);
  const stop = useCallback(() => {
    setStartLongPress(false);
  }, []);

  return {
    onMouseDown: start,
    onMouseUp: stop,
    onMouseLeave: stop,
    onTouchStart: start,
    onTouchEnd: stop,
  };
}
回答4

基于@Sublime me 上面关于避免多次重新渲染的评论,我的版本不使用任何触发渲染的内容:

export function useLongPress({
  onClick = () => {},
  onLongPress = () => {},
  ms = 300,
} = {}) {
  const timerRef = useRef(false);
  const eventRef = useRef({});

  const callback = useCallback(() => {
    onLongPress(eventRef.current);
    eventRef.current = {};
    timerRef.current = false;
  }, [onLongPress]);

  const start = useCallback(
    (ev) => {
      ev.persist();
      eventRef.current = ev;
      timerRef.current = setTimeout(callback, ms);
    },
    [callback, ms]
  );

  const stop = useCallback(
    (ev) => {
      ev.persist();
      eventRef.current = ev;
      if (timerRef.current) {
        clearTimeout(timerRef.current);
        onClick(eventRef.current);
        timerRef.current = false;
        eventRef.current = {};
      }
    },
    [onClick]
  );

  return useMemo(
    () => ({
      onMouseDown: start,
      onMouseUp: stop,
      onMouseLeave: stop,
      onTouchStart: start,
      onTouchEnd: stop,
    }),
    [start, stop]
  );
}

它还提供onLongPressonClick并传递接收到的事件对象。

用法与前面描述的一样,除了现在在对象中传递参数之外,所有参数都是可选的:

  const longPressProps = useLongPress({
    onClick: (ev) => console.log('on click', ev.button, ev.shiftKey),
    onLongPress: (ev) => console.log('on long press', ev.button, ev.shiftKey),
  });

// and later:
  return (<button {...longPressProps}>click me</button>);
回答5

这是一个提供 onClick 和 onHold 事件的组件 - 根据需要进行调整...

CodeSandbox:https://codesandbox.io/s/hold-press-event-r8q9w

用法:

import React from 'react'
import Holdable from './holdable'

function App() {

  function onClick(evt) {
    alert('click ' + evt.currentTarget.id)
  }

  function onHold(evt) {
    alert('hold ' + evt.currentTarget.id)
  }

  const ids = 'Label1,Label2,Label3'.split(',')

  return (
    <div className="App">
      {ids.map(id => (
        <Holdable
          onClick={onClick}
          onHold={onHold}
          id={id}
          key={id}
        >
          {id}
        </Holdable>
      ))}
    </div>
  )
}

可持有的.jsx:

import React from 'react'

const holdTime = 500 // ms
const holdDistance = 3**2 // pixels squared

export default function Holdable({id, onClick, onHold, children}) {

  const [timer, setTimer] = React.useState(null)
  const [pos, setPos] = React.useState([0,0])

  function onPointerDown(evt) {
    setPos([evt.clientX, evt.clientY]) // save position for later
    const event = { ...evt } // convert synthetic event to real object
    const timeoutId = window.setTimeout(timesup.bind(null, event), holdTime)
    setTimer(timeoutId)
  }

  function onPointerUp(evt) {
    if (timer) {
      window.clearTimeout(timer)
      setTimer(null)
      onClick(evt)
    }
  }

  function onPointerMove(evt) {
    // cancel hold operation if moved too much
    if (timer) {
      const d = (evt.clientX - pos[0])**2 + (evt.clientY - pos[1])**2
      if (d > holdDistance) {
        setTimer(null)  
        window.clearTimeout(timer)
      }
    }
  }

  function timesup(evt) {
    setTimer(null)
    onHold(evt)
  }

  return (
    <div
      onPointerDown={onPointerDown}
      onPointerUp={onPointerUp}
      onPointerMove={onPointerMove}
      id={id}
    >
      {children}
    </div>
  )
}

注意:这不适用于 Safari - 指针事件虽然在 v13 中出现 - https://caniuse.com/#feat=pointer

回答6

这是最流行的答案的打字稿版本,以防它对任何人有用:

(它也固定与访问一问题event在被委托的事件属性内timeOut通过利用e.persist()和克隆的情况下)

使用LongPress.ts

import { useCallback, useRef, useState } from "react";
  
function preventDefault(e: Event) {
  if ( !isTouchEvent(e) ) return;
  
  if (e.touches.length < 2 && e.preventDefault) {
    e.preventDefault();
  }
};

export function isTouchEvent(e: Event): e is TouchEvent {
  return e && "touches" in e;
};

interface PressHandlers<T> {
  onLongPress: (e: React.MouseEvent<T> | React.TouchEvent<T>) => void,
  onClick?: (e: React.MouseEvent<T> | React.TouchEvent<T>) => void,
}

interface Options {
  delay?: number,
  shouldPreventDefault?: boolean
}

export default function useLongPress<T>(
  { onLongPress, onClick }: PressHandlers<T>,
  { delay = 300, shouldPreventDefault = true }
  : Options
  = {}
) {
  const [longPressTriggered, setLongPressTriggered] = useState(false);
  const timeout = useRef<NodeJS.Timeout>();
  const target = useRef<EventTarget>();

  const start = useCallback(
    (e: React.MouseEvent<T> | React.TouchEvent<T>) => {
      e.persist();
      const clonedEvent = {...e};
      
      if (shouldPreventDefault && e.target) {
        e.target.addEventListener(
          "touchend",
          preventDefault,
          { passive: false }
        );
        target.current = e.target;
      }

      timeout.current = setTimeout(() => {
        onLongPress(clonedEvent);
        setLongPressTriggered(true);
      }, delay);
    },
    [onLongPress, delay, shouldPreventDefault]
  );

  const clear = useCallback((
      e: React.MouseEvent<T> | React.TouchEvent<T>,
      shouldTriggerClick = true
    ) => {
      timeout.current && clearTimeout(timeout.current);
      shouldTriggerClick && !longPressTriggered && onClick?.(e);

      setLongPressTriggered(false);

      if (shouldPreventDefault && target.current) {
        target.current.removeEventListener("touchend", preventDefault);
      }
    },
    [shouldPreventDefault, onClick, longPressTriggered]
  );

  return {
    onMouseDown: (e: React.MouseEvent<T>) => start(e),
    onTouchStart: (e: React.TouchEvent<T>) => start(e),
    onMouseUp: (e: React.MouseEvent<T>) => clear(e),
    onMouseLeave: (e: React.MouseEvent<T>) => clear(e, false),
    onTouchEnd: (e: React.TouchEvent<T>) => clear(e)
  };
};
回答7

Brian 的解决方案允许您将参数传递给我认为使用 Hook 无法实现的孩子。 不过,如果我可以为最常见的情况建议一个更简洁的解决方案,即您希望将 onHold 行为添加到单个组件,并且您还希望能够更改 onHold 超时。

带有芯片组件的 Material-UI 示例:

 'use strict'; const { Chip } = MaterialUI function ChipHoldable({ onClick = () => {}, onHold = () => {}, hold = 500, ...props }) { const [timer, setTimer] = React.useState(null); function onPointerDown(evt) { const event = { ...evt }; // convert synthetic event to real object const timeoutId = window.setTimeout(timesup.bind(null, event), hold); setTimer(timeoutId); } function onPointerUp(evt) { if (timer) { window.clearTimeout(timer); setTimer(null); onClick(evt); } } const onContextMenu = e => e.preventDefault(); const preventDefault = e => e.preventDefault(); // so that ripple effect would be triggered function timesup(evt) { setTimer(null); onHold(evt); } return React.createElement(Chip, { onPointerUp, onPointerDown, onContextMenu, onClick: preventDefault, ...props }); } const App = () => <div> {[1,2,3,4].map(i => < ChipHoldable style={{margin:"10px"}}label = {`chip${i}`} onClick = { () => console.log(`chip ${i} clicked`) } onHold = { () => console.log(`chip ${i} long pressed`) } />)} </div> ReactDOM.render( <App/>, document.querySelector('#root'));
 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> </head> <body> <div id="root"></div> <script src="https://unpkg.com/react@16/umd/react.production.min.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" /> <script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script> </body> </html>
回答8

Ionic React LongPress 示例我将它与 Ionic React 一起使用,效果很好。

import React, {useState}  from 'react';
import { Route, Redirect } from 'react-router';

interface MainTabsProps { }
const MainTabs: React.FC<MainTabsProps> = () => {

// timeout id  
var initial: any;

// setstate
const [start, setStart] = useState(false);

const handleButtonPress = () => {
  initial = setTimeout(() => {
    setStart(true); // start long button          
    console.log('long press button');
    }, 1500);
}

const handleButtonRelease = () => {
  setStart(false); // stop long press   
  clearTimeout(initial); // clear timeout  
  if(start===false) { // is click
    console.log('click button');
  }  
}

  return (
    <IonPage>
      <IonHeader>
        <IonTitle>Ionic React LongPress</IonTitle>
      </IonHeader>    
      <IonContent className="ion-padding">
        <IonButton expand="block"  
          onMouseDown={handleButtonPress} 
          onMouseUp={handleButtonRelease} >LongPress</IonButton>    
      </IonContent>
    </IonPage>
  );
};

export default MainTabs;
回答9

只是想指出钩子在这里不是一个很好的解决方案,因为你不能在回调中使用它们。

例如,如果您想为多个元素添加长按:

items.map(item => <button {...useLongPress(() => handle(item))}>{item}</button>)

让你:

... React Hooks 必须在 React 函数组件或自定义 React Hook 函数中调用

但是,您可以使用 vanilla JS:

export default function longPressEvents(callback, ms = 500) {
  let timeout = null

  const start = () => timeout = setTimeout(callback, ms)
  const stop = () => timeout && window.clearTimeout(timeout)

  return callback ? {
    onTouchStart: start,
    onTouchMove: stop,
    onTouchEnd: stop,
  } : {}
}

然后:

items.map(item => <button { ...longPressEvents(() => handle(item)) }>{item}</button>)

演示:https://codesandbox.io/s/long-press-hook-like-oru24?file=/src/App.js

请注意longPressEvents将运行每个渲染。 可能没什么大不了的,但要记住一些事情。

回答10

这是我自己能做出的最简单和最好的解决方案。

  • 这样你就不需要传递点击事件
  • 单击事件仍然有效
  • 钩子返回一个函数而不是事件本身,然后您可以在循环中或有条件地使用它并将不同的回调传递给每个元素。

使用LongPress.js

export default function useLongPress() {
  return function (callback) {
    let timeout;
    let preventClick = false;

    function start() {
      timeout = setTimeout(() => {
        preventClick = true;
        callback();
      }, 300);
    }

    function clear() {
      timeout && clearTimeout(timeout);
      preventClick = false;
    }

    function clickCaptureHandler(e) {
      if (preventClick) {
        e.stopPropagation();
        preventClick = false;
      }
    }

    return {
      onMouseDown: start,
      onTouchStart: start,
      onMouseUp: clear,
      onMouseLeave: clear,
      onTouchMove: clear,
      onTouchEnd: clear,
      onClickCapture: clickCaptureHandler
    };
  }
}

用法:

import useLongPress from './useLongPress';

export default function MyComponent(){
  const onLongPress = useLongPress();
  const buttons = ['button one', 'button two', 'button three'];

  return (
    buttons.map(text => 
      <button
        onClick={() => console.log('click still working')}
        {...onLongPress(() => console.log('long press worked for ' + text))}
      >
      {text}
      </button>
    )
  )
}
回答11

David 解决方案的改编版:当您想要重复触发事件时使用 React 钩子。 它使用setInterval代替。

export function useHoldPress(callback = () => {}, ms = 300) {
  const [startHoldPress, setStartHoldPress] = useState(false);

  useEffect(() => {
    let timerId;
    if (startHoldPress) {
      timerId = setInterval(callback, ms);
    } else {
      clearTimeout(timerId);
    }

    return () => {
      clearTimeout(timerId);
    };
  }, [startHoldPress]);

  return {
    onMouseDown: () => setStartHoldPress(true),
    onMouseUp: () => setStartHoldPress(false),
    onMouseLeave: () => setStartHoldPress(false),
    onTouchStart: () => setStartHoldPress(true),
    onTouchEnd: () => setStartHoldPress(false)
  };
}

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 如何彻底去除手机浏览器长按震动?(How to completely remove mobile browser long-press vibration?)
    问题 我正在尝试完全消除在移动浏览器中长按某个元素时发生的振动。 具体来说,我有一个图像,我正在向其中添加我自己的长按功能,但是默认情况下发生的微妙的短振动会产生干扰,我需要禁用它。 我通过如下覆盖它成功地阻止了通常的上下文菜单的出现: window.oncontextmenu = function (event) { event.preventDefault(); event.stopPropagation(); return false; }; 我还添加了 CSS 来停止高亮显示和文本选择等 - 但我无法弄清楚是什么导致了几百毫秒后的默认振动。 在移动浏览器中、oncontextmenu 中或周围是否有另一个生命周期事件在长按时弹出? 完整的 plunker 示例,从移动浏览器(我在 Android 上使用 chrome)长按图像以了解我的意思:https://plnkr.co/edit/y1KVPltTzEhQeMWGMa1F?p=preview 回答1 在过去一天左右的时间里,我一直在使用我自己的 React 应用程序解决同样的问题,但我已经完成了与您相同的步骤,但没有成功。 目前我有一个 Android 应用程序正在使用 webView 打开 React Web 应用程序,我发现的是: 我相当确定你(我们)想要做的事情不能仅仅通过 ReactJS 来完成,我使用的解决方案
  • onKeyDown和onKeyLongPress(onKeyDown and onKeyLongPress)
    问题 我希望我的应用程序对正常和长按的音量按钮的按键事件做出不同的反应。 我已经看到了,但是如果按住音量按钮,则在得到KeyLongPressed事件之前会收到很多KeyDown事件。 我想要一个事件或另一个事件,而不是两个都发生,这样我可以短按一下“音量”,长按一次跳过一个曲目。 你能帮我吗? 这是我的代码: @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { Log.d("Test", "Long press!"); return true; } return super.onKeyLongPress(keyCode, event); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { event.startTracking(); Log.d("Test", "Short"); return true; } return super.onKeyDown(keyCode, event); } 任何帮助表示赞赏! -虹膜
  • 通过触摸事件模拟长按(Simulate Long press by Touch events)
    问题 我们如何通过触摸事件模拟长按? 或者我们如何计算触摸屏幕的时间,全部处于 ACTION_DOWN 状态? 回答1 我终于实现了触摸屏长按,谢谢所有: textView.setOnTouchListener(new View.OnTouchListener() { private static final int MIN_CLICK_DURATION = 1000; private long startClickTime; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: longClickActive = false; break; case MotionEvent.ACTION_DOWN: if (longClickActive == false) { longClickActive = true; startClickTime = Calendar.getInstance().getTimeInMillis(); } break; case MotionEvent.ACTION_MOVE: if (longClickActive == true) { long clickDuration
  • 按钮上的长按事件[重复](Long press event on button [duplicate])
    问题 这个问题在这里已经有了答案: 8 年前关闭。 可能的重复: 如何使用 uiview 和 uibutton 检测对 Uitableview 单元格的点击? UIButton 长按事件 我正在通过表格自定义单元格加载按钮。如何确定用户是单击还是长按按钮事件?。 回答1 我只是谷歌一下,我从堆栈溢出中得到了最好的答案 - (void)viewDidLoad { UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; [self.button addGestureRecognizer:longPress]; [longPress release]; [super viewDidLoad]; } 和事件:- - (void)longPress:(UILongPressGestureRecognizer*)gesture { if ( gesture.state == UIGestureRecognizerStateEnded ) { NSLog(@"Long Press"); } } 回答2 您可以首先创建 UILongPressGestureRecognizer
  • 如何使用Polymer1.0实现长按事件?(How to implement long-press event using Polymer1.0?)
    问题 似乎长按事件不是聚合物规格的一部分。 你将如何实施? 我考虑过使用行为并使用带有一些debounce技巧的down和up事件来管理这样一个新事件,但这意味着我必须制作一个自定义元素来使用此行为,并且不能例如直接在我想要的任何元素上使用它像 : <div on-long-press="_cheese">...</div> 这不方便。 你有其他解决方案吗? 回答1 您不必为此创建自定义元素。 这就是聚合物行为的用途。 它们为不同的聚合物元素提供了一种共享共同行为的方式。 至于用于实现长按的实际 javascript,您可以从这个问题中获得想法。 回答2 为此,您可以使用 Vaadin 手势。 https://github.com/vaadin/vaadin-context-menu/blob/master/vaadin-long-touch.html <paper-button on-vaadin-long-touch="function"></paper-button>
  • 反应不响应按键事件(React not responding to key down event)
    问题 我正在尝试实现一些非常基本的按键检测,但根本无法正常工作。 我有一个应该在onKeyDown事件上接收的裸组件,但控制台中没有任何内容被注销: class App extends React.Component { constructor(props) { super(props); } handleKeyDown(event) { console.log('handling a key press'); } render() { return ( <ChildComponent onKeyDown={this.handleKeyDown} /> ); } } React.render(<App />, document.getElementById('app')); 回答1 问题是ChildComponent不是组件而是组件工厂。 它将被渲染由该工厂创建的元素的结果替换。 将ChildComponent插入 div 并将任何事件侦听器附加到 div,而不是ChildComponent 。 如果需要内联显示,请将<div>替换为<span> 。 let {Component} = React; class ChildComponent extends Component { render() { return ( <child-component>press down a
  • Ionic 2 - 为“长按”事件指令设置回调(Ionic 2 - setting callback for “long press” event directive)
    问题 我正在尝试在元素上添加自定义 longPress 事件指令,因为 (press)="callback_function()" 将导致 ion-list 无法再滚动。 无论是否有错误,我发现我需要添加一个自定义手势指令来添加对新属性的支持,在这种情况下,我将其称为 longPress。 效果很好,除了我不知道如何添加回调函数:-) 我已经按照教程(http://roblouie.com/article/198/using-gestures-in-the-ionic-2-beta/) “press-directive”在src/components/press-directive/press-directive.js 中创建,如下所示: import { Directive, ElementRef, OnInit, OnDestroy } from '@angular/core'; import { Gesture } from "ionic-angular/gestures/gesture"; /** * Generated class for the PressDirective directive. * * See https://angular.io/docs/ts/latest/api/core/index/DirectiveMetadata-class.html *
  • 检测触摸按压与长按按压与运动?(Detect touch press vs long press vs movement?)
    问题 我目前正在研究Android编程,但是在检测不同的触摸事件时遇到了一个小问题,即正常的触摸按下(在屏幕上按下并立即释放),长按(触摸屏幕并用手指按住它) )和移动(在屏幕上拖动)。 我想做的是在屏幕上放一个(圆的)图像,然后可以拖动它。 然后,当我按一下(短按/普通按)时,Toast会提供一些有关它的基本信息。 长按它时,会出现一个带有列表的AlertDialog,以选择其他图像(圆形,矩形或三角形)。 我使用自己的OnTouchListener制作了一个自定义View,以检测事件并在onDraw中绘制图像。 OnTouchListener.onTouch类似于以下内容: // has a touch press started? private boolean touchStarted = false; // co-ordinates of image private int x, y; public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { touchStarted = true; } else if (action == MotionEvent.ACTION_MOVE) { //
  • 长按添加新视图后如何保留触摸事件(How to preserve touch event after new view is added by long press)
    问题 当我在检测到用户的长按后添加新视图时,会收到 touchesCancelled 事件。 但是,我想将长按事件保留到新添加的视图中。 我想要实现的是用户触摸并按住屏幕,然后添加新视图,用户可以在新添加的视图中移动触摸而无需再次触摸和触摸。 但是,当添加新视图时,我会收到触摸取消事件,因此即使用户的触摸正在移动,添加的视图也无法接收任何触摸事件。 我正在使用 UILongPressGestureRecognizer 来检测用户的长按。 下面是日志消息。 MyView touchesBegan x:524 y:854 MyView handleLongPress(检测到长按) 添加了新视图 MyView touchesCancelled x:526 y:854 什么也没发生…… 我期待的是... MyView touchesBegan x:524 y:854 MyView handleLongPress(检测到长按) 添加了新视图 MyView touchesCancelled x:526 y:854 新视图触摸开始 NewView touchMoved NewView touchMoved NewView touchMoved NewView touchMoved ... 有什么解决办法吗? 提前致谢。 回答1 这是一个棘手的问题 - 我对解决方案的想法有点老套,但我认为它会奏效
  • 长按(按住)jqueryhammer.js 2 和事件委托(Long press (hold) with jquery hammer.js 2 and event delegation)
    问题 我最近升级到了hammer.js 2,我注意到的第一件事是“hold”已被“press”取代。 我的旧代码在事件委托方面工作得很好,但切换到按下似乎只有当我把它放在特定元素上时才起作用。 注意:我通过jquery插件使用hammer.js 锤子.js 1 $(element).hammer().on("hold",callback); 工作正常 $(rootElement).hammer().on("hold",".elementSelector",callback); 工作正常 锤子.js 2 这 $(element).hammer().on("press",callback); 工作正常,而这 $(rootElement).hammer().on("press",".elementSelector",callback); 才不是。 回调永远不会被触发。 回答1 在新版本中,锤子事件已被简化以提高速度。 要重新启用事件委托,只需添加 domEvents:true 作为选项: $(rootElement).hammer({domEvents:true}).on("press",".elementSelector",callback);
  • Android中长按和长按的事件(Events for Long click down and long click up in Android)
    问题 我想要两个单独的事件,分别用于长按向下和长按向上。 如何在Android中执行此操作? 我尝试过如下 public class FfwRewButton extends ImageButton { public interface ButtonListener { void OnLongClickDown(View v); void OnLongClickUp(View v); } private ButtonListener mListener; private boolean mLongClicked = false; public FfwRewButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setFocusable(true); setLongClickable(true); } public FfwRewButton(Context context) { this(context, null); } public FfwRewButton(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.imageButtonStyle); }
  • 长按JavaScript吗?(Long Press in JavaScript?)
    问题 是否可以在JavaScript(或jQuery)中实现“长按”? 如何? (来源:androinica.com) 的HTML <a href="" title="">Long press</a> 的JavaScript $("a").mouseup(function(){ // Clear timeout return false; }).mousedown(function(){ // Set timeout return false; }); 回答1 没有“ jQuery”魔术,只有JavaScript计时器。 var pressTimer; $("a").mouseup(function(){ clearTimeout(pressTimer); // Clear timeout return false; }).mousedown(function(){ // Set timeout pressTimer = window.setTimeout(function() { ... Your Code ...},1000); return false; }); 回答2 根据Maycow Moura的回答,我写了这封信。 它还可以确保用户没有单击右键,这将触发长按并在移动设备上工作。 演示 var node = document.getElementsByTagName("p
  • 使用 jQuery 在 Android 上确定长按(长按,点按保持)(Determining Long Tap (Long Press, Tap Hold) on Android with jQuery)
    问题 我已经能够使用 jQuery 和 HTML 页面在 Android 上成功地处理 touchstart、touchmove 和 touchend 事件。 现在我想看看确定一个长按事件的技巧是什么,一个人点击并保持 3 秒。 我似乎还无法弄清楚这一点。 我只想在没有 Sencha Touch、JQTouch、jQMobile 等的情况下使用 jQuery。 我喜欢 jQTouch 的概念,尽管它并没有为我提供很多东西,而且我的一些代码与它有冲突。 使用 Sencha Touch,我不喜欢从 jQuery 转移到 Ext.js 和一些新的 Javascript 抽象方法,尤其是当 jQuery 如此强大时。 所以,我想单独用 jQuery 来解决这个问题。 我已经能够使用 jQuery 自己做很多 jQTouch 和 Sencha Touch 的事情。 并且 jQMobile 仍然是测试版,还不够针对 Android。 回答1 计时器未使用,但只有在用户长按后松开手指后才会触发。 var startTime, endTime; var gbMove = false; window.addEventListener('touchstart',function(event) { startTime = new Date().getTime(); gbMove = false; }
  • Android中的onLongPress事件持续了多长时间?(How long is the event onLongPress in the Android?)
    问题 Android支持onLongPress事件。 我的问题是“按”触发事件有多长时间(以毫秒为单位)? 回答1 标准的长按时间是getLongPressTimeout()返回的时间,当前为500毫秒,但可能会更改(在1.0中为1000毫秒,但在以后的版本中有所更改;也许将来会由用户自定义)。 浏览器使用了自己的长按时间,因为它具有一些更复杂的交互。 我相信应该是1000,尽管将来可能还会改变。 它没有将不同的超时时间加在一起。 回答2 您可以在android.view.ViewConfiguration使用getLongPressTimeout方法以编程方式确定此值。 有关详细信息,请参阅文档。 回答3 通常,就像提到的Roman Nurik一样,您可以使用ViewConfiguration.getLongPressTimeout()以编程方式获取长按值。 默认值为500毫秒。 /** * Defines the default duration in milliseconds before a press turns into * a long press */ private static final int DEFAULT_LONG_PRESS_TIMEOUT = 500; 但是,长按时间可以通过将其设置为可访问性来全局定制。 值是短(400 ms),中(1000 ms
  • Android:如何在触摸事件中手动实现长按?(Android : How to implement longpress manually in touch event?)
    问题 简短版本:我想要一种在 onTouchEvent 上启动基于时间的计数器的方法,并测试在响应之前是否已经过去了一定的时间,作为手动 LongTouch 检测。 说明:我有一个自定义的 imageView,它可以在两指滑动时滑入/滑出屏幕。 我想向它添加拖动事件,但这些需要比长按更快。 我可以通过使用一个计数器来延迟拖动事件,该计数器每个 onTouchEvent 更新一次并且只触发拖动,例如 10 个计数,但计数器仅在触摸事件上更新并且手指必须移动。 我如何创建一个基于时间的计数器,一个每秒递增 60 次的活动级别字段等等? 回答1 我不确定你的问题,但似乎你试图在你的 onTouchListener 中实现一个 catch long click 事件,除非你需要在 ACTION_UP 事件发生之前执行某种逻辑? 如果是这样,那与我遇到的问题完全相同。 我也尝试过使用 System.nanoTime() 但我发现了一个不那么棘手的方法。 您可以使用计时器,您只需要在第一个 ACTION_DOWN 事件上安排它,并在发生任何不利情况时取消它(例如 ACTION_UP,这意味着它不是长按而是单击,或者 ACTION_MOVE 的位移超过一定的门槛)。 类似于以下内容: layout.seyOnTouchListener(new OnTouchListener(){ private
  • 设置长按监听器的持续时间(Set Duration of Long Key press Listener)
    问题 我们可以设置长按键监听器的持续时间吗? 我想要的是,如果用户持续触摸屏幕 3 秒,那么我的长按键监听器应该触发并打开我的弹出窗口进行设置。 提前致谢。 回答1 覆盖 onTouch 侦听器,然后在按下按钮期间处理按下、释放的事件并设置计时器(事件 ==“按下”) private Timer timer; public LongClickTimer(int seconds) { timer = new Timer(); timer.schedule(new LongClickTask(), seconds *1000); } class LongClickTask extends TimerTask { public void run() { // do what you want timer.cancel(); } } button.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.v(TAG, "EVENT" + event.toString()); if(event.getAction == 2) {// pressed new LongClickTimer(5); // schedule for 5
  • 使用Android检测长按(Detecting a long press with Android)
    问题 我目前正在使用 onTouchEvent(MotionEvent event){ } 检测用户何时按下我的glSurfaceView,是否有方法检测何时长按。 我猜如果我在开发文档中找不到太多的东西,那将是围绕方法的某种解决方法。 例如注册ACTION_DOWN并查看ACTION_UP之前需要多长时间。 如何使用opengl-es在android上检测长按? 回答1 尝试这个: final GestureDetector gestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() { public void onLongPress(MotionEvent e) { Log.e("", "Longpress detected"); } }); public boolean onTouchEvent(MotionEvent event) { return gestureDetector.onTouchEvent(event); }; 回答2 GestureDetector是最好的解决方案。 这是一个有趣的选择。 在onTouchEvent中,每个ACTION_DOWN计划中都会有一个Runnable在1秒内运行。 在每个ACTION_UP或ACTION_MOVE上
  • 如何对Go中的按键事件做出反应?(How to react to keypress events in Go?)
    问题 我在Go中有一个REPL应用程序,该应用程序应该对键盘按下事件(每个按下的键的动作有所不同)做出反应,但是ReadString希望在读取os.Stdin之前先按下返回键: import ( "bufio" "os" ) for { reader := bufio.NewReader(os.Stdin) key, _ := reader.ReadString('\n') deferKey(key) } 我如何对Go中的按键事件做出反应? 回答1 游戏引擎通常实现这种功能。 它们通常也与平台无关(通常至少是Windows,Linux,Mac OS X)。 例如尝试Azul3D的键盘库。 逻辑就像我的头上一样 watcher := keyboard.NewWatcher() // Query for the map containing information about all keys status := watcher.States() left := status[keyboard.ArrowLeft] if left == keyboard.Down { // The arrow to left is being held down // Do something! } 要获得当前当前按下的键的列表,只需遍历地图并列出value为Down的键即可。 回答2
  • 防止图像上的强制触摸事件,但仍允许在 iOS Safari 中长按事件(Prevent force touch event on image but still allow long press event in iOS Safari)
    问题 我们需要在我们的图片库中防止 Apple 对图片的强制触摸事件,但仍然允许长按触发“保存图片”标注。 我们为 iOS 用户提供了长按图像然后选择“保存图像”的说明,但是如果用户不小心按得太用力并触发 Force Touch 事件,他们会感到非常困惑 - 特别是当它“弹出”并加载图像时在新页面中。 最初我想到了监听touchforcechange事件,然后当力达到一定程度时调用preventDefault 。 像这样的东西: imgEl.addEventListener( 'touchforcechange', 'onTouchForceChange', false ) function onTouchForceChange( e ){ if( e.changedTouches[0].force > 0.5 ){ e.preventDefault() } } 然而,这似乎也阻止了长按事件。 似乎也没有一个特定的力级别可以让事件切换到力触。 添加 css 属性-webkit-touch-callout: none; 到图像确实会阻止 Force Touch 事件,但同样,它也会阻止长按时的标注。 任何想法都非常感谢! 回答1 (使用 jQuery,但可能没有它就可以完成) 这似乎对我有用,在 iPhone 7 和 iOS 10.3.3 上测试过: window
  • Android 长按滚动(Android long press with scroll)
    问题 我想通过滚动“连接”长按,因此用户不必释放屏幕并开始滚动。 我实现了手势检测器... final GestureDetector gestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() { public void onLongPress(MotionEvent e) { // action 1 } public boolean onScroll(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { // action 2 } } public boolean onTouchEvent(MotionEvent event) { return gestureDetector.onTouchEvent(event); } 但是现在在动作 1 和动作 2 之间,用户必须释放屏幕......如何在不释放屏幕的情况下连接这些动作? 回答1 我不认为GestureDetector会做你想做的事,更有可能你必须自己做。 我不知道您当前的设置,下面是一个OnToucListener绑定到ScrollView ,它将考虑这两个事件: public class ScrollTouchTest