How to detect the single tap in DispatchTouchEvent method in forms android - xamarin.forms

Am using DispatchTouchEvent and need to detect a single tap, for that considered the down point and up point, when both are same, detected the single tap.
But this works fine in some android devices, but in some device, there in a pixel difference in down and up point. How to overcome this?
public override bool DispatchTouchEvent(MotionEvent e)
{
if (e.Action == MotionEventActions.Down)
{
touchDownPoint = new Xamarin.Forms.Point(e.GetX(), e.GetY());
}
else if (e.Action == MotionEventActions.Up)
{
var position = new Xamarin.Forms.Point(e.GetX(), e.GetY());
if (touchDownPoint == position) // this condition not gets satisfied in some devices
{
// single tap detected.
}
}
else if (e.Action == MotionEventActions.Move)
{
}
return base.DispatchTouchEvent(e);
}

Related

Xamarin.Forms UI Test - Tap Button multiple (5) times

I'm working on writing an UI-Test for my Xamarin.Forms Application.
Therefore I need to tap a button 5-times. This invokes a dialog and I need the result of the user's input to this dialog.In code I realised this by implementing an GestureRecognizer:
private bool HandleMultipleTouch()
{
if (iLastTap == null || (DateTime.Now - iLastTap.Value).Milliseconds < iToleranceInMs)
{
if (NumberOfTaps == 4)
{
NumberOfTaps = 0;
iLastTap = null;
return true;
}
else
{
NumberOfTaps++;
iLastTap = DateTime.Now;
return false;
}
}
else
{
NumberOfTaps = 0;
iLastTap = null;
return false;
}
}
Do you know any method how to use Xamarin.UITest to get the button taped 5 times in a short time?
I tried used double tap twice and one single tap, but this is not working because of the time needed to execute the taps.
I had a similar issue, where I had to tap a morse code using Xamarin.UITest and concluded that it's impossible to ensure consistent timing between taps. My solution was therefore to abandon the morse code and only check in the app whether the button was hit 5 times.

SelectionMode.MULTIPLE with TAB to navigate to next cell

I'm currently using TAB to navigate to next cell. selectNext() or selectRightCell() works fine when I'm using SelectionMode.SINGLE.
However, when using SelectionMode.MULTIPLE, its selecting multiple cells as I TAB.
I'm using a TableView. I need SelectionMode.MULTIPLE for the copy & paste function.
Is there a way to make it work in SelectionMode.MULTIPLE?
fixedTable.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()){
case TAB:
if (event.isShiftDown()) {
fixedTable.getSelectionModel().selectPrevious();
} else {
fixedTable.getSelectionModel().selectNext();
}
event.consume();
break;
case ENTER:
return;
case C:
if(event.isControlDown()){
copySelectionToClipboard(fixedTable) ;
}
event.consume();
break;
case V:
if(event.isControlDown()){
pasteFromClipboard(fixedTable);
}
event.consume();
break;
default:
if (fixedTable.getEditingCell() == null) {
if (event.getCode().isLetterKey() || event.getCode().isDigitKey()) {
TablePosition focusedCellPosition = fixedTable.getFocusModel().getFocusedCell();
fixedTable.edit(focusedCellPosition.getRow(), focusedCellPosition.getTableColumn());
}
}
break;
}
}
});
You will need to handle the selection on your own. The reason is because the methods selectPrevious() and selectNext() tries to select the previous ( or the next ) without removing the current selected row ( when you set the selection mode to be SelectionMode.MULTIPLE) , also you can't use them and just remove the previous selecting by just calling clearSelection() because this will set the selected index to -1 and then the methods selectPrevious() and selectNext() will select the last or the first row only.
Here is how you could implement the selection on your own :
// the rest of your switch statement
...
case TAB:
// Find the current selected row
int currentSelection = table.getSelectionModel().getSelectedIndex();
// remove the previous selection
table.getSelectionModel().clearSelection();
if (event.isShiftDown()) {
currentSelection--;
} else {
currentSelection++;
}
// find the size of our table
int size = table.getItems().size() - 1;
// we was on the first element and we try to go back
if(currentSelection < 0){
// either do nothing or select the last entry
table.getSelectionModel().select(size);
}else if(currentSelection > size) {
// we are at the last index, do nothing or go to 0
table.getSelectionModel().select(0);
}else {
// we are between (0,size)
table.getSelectionModel().select(currentSelection);
}
event.consume();
break;
...

Firebase firestore document changes

I just want to ask how can I properly use the document changes in my app? Btw there are 3 types of that which is ADDED, MODIFIED and lastly REMOVED. TYPE.ADDED works perfectly fine, but in modified and removed it doesn't work well in modified it. I am using a recyclerview for that and here's my code. Am I wrong utilizing it? Also, I am using a instance oldindex and newindex to know the index which is affected by the action performed.
for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
if(doc.getType() == DocumentChange.Type.ADDED) {
PostsClass post = doc.getDocument().toObject(PostsClass.class).withId(doc.getDocument().getId());
postList.add(post);
Log.d(TAG, post.toString());
postsAdapter.notifyDataSetChanged();
}
else if (doc.getType() == DocumentChange.Type.MODIFIED) {
adoptList.clear();
AdoptClass adopt = doc.getDocument().toObject(AdoptClass.class).withId(doc.getDocument().getId());
adoptList.add(adopt);
adoptListAdapter.notifyItemChanged(oldIndex);
}
else if (doc.getType() == DocumentChange.Type.REMOVED) {
adoptList.remove(oldIndex);
adoptListAdapter.notifyItemRemoved(oldIndex);
}
}
below code worked for me in 3 conditions ADDED,MODIFIED,REMOVED (Android Firestore)
for (DocumentChange documentChange : queryDocumentSnapshots.getDocumentChanges()) {
if (documentChange.getType() == DocumentChange.Type.ADDED) {
String doc_id = documentChange.getDocument().getId();
PostModel postModel = documentChange.getDocument().toObject(PostModel.class).withDocId(doc_id);
postModelList.add(postModel);
} else if (documentChange.getType() == DocumentChange.Type.MODIFIED) {
// modifying
String docID = documentChange.getDocument().getId();
PostModel changedModel = documentChange.getDocument().toObject(PostModel.class).withDocId(docID);
if (documentChange.getOldIndex() == documentChange.getNewIndex()) {
// Item changed but remained in same position
postModelList.set(documentChange.getOldIndex(),changedModel);
postListAdapter.notifyItemChanged(documentChange.getOldIndex());
}else {
// Item changed and changed position
postModelList.remove(documentChange.getOldIndex());
postModelList.add(documentChange.getNewIndex(),changedModel);
postListAdapter.notifyItemMoved(documentChange.getOldIndex(),documentChange.getNewIndex());
}
postListAdapter.notifyDataSetChanged();
} else if (documentChange.getType() == DocumentChange.Type.REMOVED) {
// remove
postModelList.remove(documentChange.getOldIndex());
postListAdapter.notifyItemRemoved(documentChange.getOldIndex());
}
}

Flex navigateToURL from iframe POST

Let me explain my current issue right now:
I have a webapp located at domain A. Let's call it A-App. I open an iframe from A-App that points to a Flex app on domain B. We'll call it B-FlexApp. B-FlexApp wants to post some data to another app located on the same domain, we'll call it B-App. The problem is that in IE the communication breaks somewhere between B-FlexApp and B-App while B-FlexApp is opened in the iframe. This only happens in IE.
However when opening B-FlexApp in a new window, posting the data to B-App works just fine. How to overcome this? Dropping the iframe is not possible.
ThereĀ“s a issue with AS3 navigateToURL and IE. You can try calling javascript to navigate: I have a little utility class to handle this:
//class URLUtil
package com
{
import flash.external.*;
import flash.net.*;
public class URLUtil extends Object
{
protected static const WINDOW_OPEN_FUNCTION:String="window.open";
public function URLUtil()
{
super();
return;
}
public static function openWindow(arg1:String = "", arg2:String="_blank", arg3:String=""):void
{
var browserName:String = getBrowserName();
switch (browserName)
{
case "Firefox":
{
flash.external.ExternalInterface.call(WINDOW_OPEN_FUNCTION, arg1, arg2, arg3);
break;
}
case "IE":
{
flash.external.ExternalInterface.call("function setWMWindow() {window.open(\'" + arg1 + "\');}");
break;
}
case "Safari":
case "Opera":
{
flash.net.navigateToURL(new URLRequest(arg1), arg2);
break;
}
default:
{
flash.net.navigateToURL(new URLRequest(arg1), arg2);
break;
}
}
return;
}
private static function getBrowserName():String
{
var str:String="";
var browserName:String = ExternalInterface.call("function getBrowser(){return navigator.userAgent;}");
if (!(browserName == null) && browserName.indexOf("Firefox") >= 0)
{
str = "Firefox";
}
else
{
if (!(browserName == null) && browserName.indexOf("Safari") >= 0)
{
str = "Safari";
}
else
{
if (!(browserName == null) && browserName.indexOf("MSIE") >= 0)
{
str = "IE";
}
else
{
if (!(browserName == null) && browserName.indexOf("Opera") >= 0)
{
str = "Opera";
}
else
{
str = "Undefined";
}
}
}
}
trace("Browser: \t" + str);
return str;
}
}
}
and you call it like:
btn.addEventListener(MouseEvent.CLICK, onBTNClick);
function onBTNClick(evt:MouseEvent):void
{
URLUtil.openWindow(YOUR_URL_STRING);
}
Hope it helps!
It is better to let the browser actually does the "navigate to URL" function instead of Flex.
For example, in the page that contains the Flex app, the page would contain a Javascript function call handleNavigationRequest(pageName, target). In the Flex application, you may utilize ExternalInterface, and call the handleNavigationRequest.
By using this paradigm, the Flex application would not have to figure the details as to how the external implementations such as frame setup, etc, and you end up having a cleaner and less-coupled design.
I've found out that i can use swfObject to embed the flash object thus the iframe implementation is completely useless. Embedding the flash component in the overlay, instead of opening it in an iframe, makes IE behave properly.
I had the same problem and I solved it simply passing the second argument (browser window) to the function:
navigateToUrl(url,"_blank"); , in my case I use "_blank".
It works with IE8 and IE9.
Davide

How to cancel 'seeking' state of Flex3 VideoDisplay class

I have a VideoDisplay instance playing some video. When I click on the video slider (also my component) the property videoDisplay.playheadTime is set and the videoDisplay.state goes from 'playing' into a 'seeking' state for a brief moment (the videoDisplay seeks for a new position and then plays the video again). Intended bevaiour.
But if I'm (or any random user) fast enough, I can set the playheadTime again while the player is still in 'seeking' state. When repeated several times every click is enqueued and the videoDisplay jump on every place of the video I have clicked(this is happening in an interval about 10-15 second after my last click). When I use live dragging the videoDisplay, overwhelmed by seekings, goes into 'error' state.
My question is - is there any way to cancel seeking state of the VideoDisplay class? For example player is in 'seeking' state, I set playheadTime, and the player forgets about last seeking and try to find the new place of the video.
I will downvote pointless answers like 'Use the Flex4 VideoPlayer class'!
One possible way is wrap the video display in a component and manage the seek a little better yourself. So if someone calls seek, make sure that the video is not currently seeking, if so, then wait till the current operation is complete before proceeding to the new one. If the user tries to seek again, discard all currently pending operations and make the latest one the next operation. Working on this exact problem right now.... Here's the code:
public function Seek(nSeconds:Number, bPlayAfter:Boolean):void
{
trace("Player Seek: "+ nSeconds);
var objSeekComand:VideoPlayerSeekCommand = new VideoPlayerSeekCommand(ucPlayer, nSeconds, bPlayAfter);
ProcessCommand(objSeekComand);
}
protected function ProcessCommand(objCommand:ICommand):void
{
if(_objCurrentCommand != null)
{
_objCurrentCommand.Abort();
}
_objCurrentCommand = objCommand
objCommand.SignalCommandComplete.add(OnCommandComplete);
objCommand.Execute();
}
Here's the Command
public class VideoPlayerSeekCommand extends CommandBase
{
private var _ucVideoDisplay:VideoDisplay;
private var _nSeekPoint:Number;
private var _bPlayAfterSeek:Boolean;
private var _bIsExecuting:Boolean;
public function VideoPlayerSeekCommand(ucVideoDisplay:VideoDisplay, nSeekPointInSeconds:Number, bPlayAfterSeek:Boolean, fAutoAttachSignalHandler:Function = null)
{
_ucVideoDisplay = ucVideoDisplay;
_nSeekPoint = nSeekPointInSeconds;
_bPlayAfterSeek = bPlayAfterSeek;
super(fAutoAttachSignalHandler);
}
override public function Execute():void
{
//First check if we are playing, and puase if needed
_bIsExecuting = true;
if(_ucVideoDisplay.playing == true)
{
_ucVideoDisplay.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, OnPlayerStateChangedFromPlay, false, 0, true);
_ucVideoDisplay.pause();
}
else
{
DoSeek();
}
}
protected function OnPlayerStateChangedFromPlay(event:MediaPlayerStateChangeEvent):void
{
_ucVideoDisplay.removeEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, OnPlayerStateChangedFromPlay);
if(_bIsExecuting == true)
{
if(_ucVideoDisplay.playing == false)
{
DoSeek();
}
else
{
throw new Error("VideoPlayerSeekAndPlayCommand - OnPlayerStateChangedFromPlay error");
}
}
}
private function DoSeek():void
{
if(_bIsExecuting == true)
{
_ucVideoDisplay.seek(_nSeekPoint);
CheckSeekComplete();
}
}
private function CheckSeekComplete():void
{
if(_bIsExecuting == true)
{
if (Math.abs( _ucVideoDisplay.currentTime - _nSeekPoint) < 2)
{
if(_bPlayAfterSeek == true)
{
_ucVideoDisplay.play();
}
DispatchAndDestroy();
}
else
{
CoreUtils.CallLater(CheckSeekComplete, .07);
}
}
}
override public function Abort():void
{
_bIsExecuting = false;
SignalCommandComplete.removeAll();
}
}
Im Using AS3 Signals here instead of events, and the CoreUtils.Call later you can use setInterval, or a Timer. But the idea is to not call seek until the video is paused, and to keep track of when the seek is complete.

Resources