Jump to content

click event "slow" on android


Recommended Posts

We have made a class of button derived from TW3Button. We find that the onclick events don't work quickly on android or in responsive mode on chrome.

 

I have attached the project. http://numberworksnwords.com/cloud/temp/button/TNWToggleButtonTest.zip

Or you can open in browser http://numberworksnwords.com/cloud/temp/button/index.html

On desktop or iOS a simple touch will toggle the button - a shadow will appear.

On android browsers or when chrome is set to "responsive: you need to "click" and hold for a second or more before the button toggles.

2017-11-22_10-34-28.gif

 

 

 

 

Link to post
Share on other sites

I have stripped the problem right down and my conclusion is that on android and responsive the click event is firing twice setting the button back to its original setting.

 

I have included ms since previous click code and the image below slows that a second event fires 2ms later.

 

unit Form1;

interface

uses 
  System.Types,
  System.Types.Convert,
  System.Objects,
  System.Time,
  SmartCL.System,
  SmartCL.Time,
  SmartCL.Graphics,
  SmartCL.Components,
  SmartCL.FileUtils,
  SmartCL.Forms,
  SmartCL.Fonts,
  SmartCL.Theme,
  SmartCL.Borders, system.time,
  SmartCL.Application, SmartCL.Controls.Button;

type
  TMyButton = class(tw3button)
  public
    checked : boolean;
    Clicked : integer;
    procedure CheckBoxClick(Sender: TObject);
    procedure InitializeObject; override;
   end;

type
  TForm1 = class(TW3Form)
  private
    {$I 'Form1:intf'}
  protected
    procedure InitializeForm; override;
    procedure InitializeObject; override;
    procedure Resize; override;
  end;

implementation

{ TForm1 }

procedure TMyButton.InitializeObject;
begin
  inherited;
  Checked := False;
  Self.OnClick := CheckBoxClick;
  SetBounds(100,200,120,40);
  clicked := GetMilliseconds;
end;


procedure TForm1.InitializeForm;
begin
  inherited;
  // this is a good place to initialize components
  var MyButton := TMyButton.create(self);
end;

procedure TMyButton.CheckBoxClick(Sender: TObject);
begin
  writeln(GetMilliseconds-TMyButton(Sender).Clicked);
  if GetMilliseconds-TMyButton(Sender).Clicked <1000 then
    begin
      writeln('too quick');
      exit;
    end;

  if TMyButton(Sender).Checked then begin           // On
    caption := 'not checked';
    Checked := False;
    clicked := GetMilliseconds;
  end
  else begin
    caption := 'checked';
    Checked := True;
    clicked := GetMilliseconds;
  end;
end;

procedure TForm1.InitializeObject;
begin
  inherited;
  {$I 'Form1:impl'}
end;
 
procedure TForm1.Resize;
begin
  inherited;
end;
 
initialization
  Forms.RegisterForm({$I %FILE%}, TForm1);
end.

tooquick.jpg

Link to post
Share on other sites
  • Administrators

I can't get any extra clicks with my Android phone. Can you test this? It outputs the click times to a label.
 

unit Form1;

interface

uses
  System.Types,
  System.Types.Convert,
  System.Objects,
  System.Time,
  SmartCL.System,
  SmartCL.Time,
  SmartCL.Graphics,
  SmartCL.Components,
  SmartCL.FileUtils,
  SmartCL.Forms,
  SmartCL.Fonts,
  SmartCL.Theme,
  SmartCL.Borders, system.time,
  SmartCL.Application, SmartCL.Debug,
  SmartCL.Controls.Button,
  SmartCL.EventManager,
  SmartCL.Controls.Label;

type
  TMyButton = class(tw3button)
  public
    checked : boolean;
    Clicked : integer;
    procedure CheckBoxClick(Sender: TObject);
    procedure InitializeObject; override;
   end;

type
  TForm1 = class(TW3Form)
  private
    {$I 'Form1:intf'}
  protected
    procedure InitializeForm; override;
    procedure InitializeObject; override;
    procedure Resize; override;
  end;

implementation

{ TForm1 }

procedure TMyButton.InitializeObject;
begin
  inherited;
  Checked := False;
  Self.OnClick := CheckBoxClick;
  SetBounds(100,300,120,40);
  clicked := GetMilliseconds;
end;


procedure TForm1.InitializeForm;
begin
  inherited;
  // this is a good place to initialize components
  var MyButton := TMyButton.create(self);
  var DebugLabel := TW3Label.create(self);
  DebugLabel.SetBounds(0,0,Width,290);
  DebugLabel.WordWrap:=true;
  Application.OnDebugPrint:=procedure(Sender: TObject; msg: Variant)
    begin
      DebugLabel.Caption:=DebugLabel.Caption+' '+msg;
    end;
end;

procedure TMyButton.CheckBoxClick(Sender: TObject);
begin
  Application.DebugPrint('Click: '+IntToStr(GetMilliseconds-TMyButton(Sender).Clicked));

  if TMyButton(Sender).Checked then begin           // On
    caption := 'not checked';
    Checked := False;
    clicked := GetMilliseconds;
  end
  else begin
    caption := 'checked';
    Checked := True;
    clicked := GetMilliseconds;
  end;
end;

procedure TForm1.InitializeObject;
begin
  inherited;
  {$I 'Form1:impl'}
end;

procedure TForm1.Resize;
begin
  inherited;
end;

initialization
  Forms.RegisterForm({$I %FILE%}, TForm1);
end.

 

Link to post
Share on other sites
  • Administrators

Yes, the previous version did trigger OnClick twice. That happened as the new button code did not use the mouse/touch events any more. And if those events were not set, the EventManager did not call preventDefault for the event. If the default event happens, mobile devices automatically created "fake" mouse events. So the OnClick happened from both touch and the mouse events. This was hard to prevent, but I think we have a pretty good solution at the moment:

  • If no touch events are set on a control, we will not call preventDefault. That lets the control do its default action. For example, set focus.
  • If your control is based on a div, img or a button, we will call preventDefault if touch events are listened to.
  • If your control is an edit or a memo, we will never call preventDefault.
  • If we don't call preventDefault, fake mouse events are generated, but we just don't react to them inside EventManager.

There is also a new property: TW3CustomControl.TouchPreventDefault, which can be used to control behaviour. It's True as default for controls that are based on a div, img or button. It controls, if preventDefault is called for the control when touch events are set on it. You can probably leave it as default always, but it's good to know that you can also change that if needed.

Why call preventDefault at all? If we don't do that, the user can drag the form and controls in any direction. Also, there are all kinds of popup menus that may be shown. But if we call preventDefault always, we block all kinds of useful functionality, like scrolling inside a memo or the popup menus for copy/paste. So there's a certain kind of balance that is needed.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...