I use the following codes to detect which UI element is the player pointing. It works well in Unity Editor, on one of my Android phone, but failed on a second Android phone.
public static T RaycastOnFirstPointed<T>(EventSystem eventSystem, GraphicRaycaster raycaster)
{
if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
{
if (Input.touches == null || Input.touches.Length == 0) return default;
}
var m_PointerEventData = new PointerEventData(eventSystem);
m_PointerEventData.position = Input.mousePosition;
var results = new List<RaycastResult>();
raycaster.Raycast(m_PointerEventData, results); // On the 2nd phone the results.length is 0
foreach (RaycastResult result in results)
{
var component = result.gameObject.GetComponent<T>();
if (component != null)
{
return component;
}
}
return default;
}
This method is called within a IEndDragHandler.OnEndDrag method. I tried to debug it on the 2nd Android phone, and saw the results.length is 0 after Raycast was executed.(it should be > 0 since I ended my drag on several overlapped UI elements, and it is > 0 on the 1st phone, not sure why the 2nd phone is different)
I don't have any clue where should I go from here to find the problem. Please show me some directions, thank you!
More info:
Phone 1: MI 8 Lite, OS: MIUI 10.3
Phone 2: MI 9, OS: MIUI 10.2.35
============Update===========
Reason found:
When IEndDragHandler.OnEndDrag is triggered, the Input.mousePosition has different value on the two devices. 1st Phone has the touch position from the last frame, while the 2nd phone seems clears that value, and it has a very large wrong value. I'm working on how to solve this in a proper way. Any suggestions are welcomed.
Problem solved. As I updated in the question, this problem is caused by wrong Input.mousePosition value on different devices. So I updated the RaycastOnFirstPointed method as follows:
public static T RaycastOnFirstPointed<T>(EventSystem eventSystem, GraphicRaycaster raycaster, PointerEventData eventData = null)
{
if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
{
if (Input.touches == null || Input.touches.Length == 0) return default;
}
var m_PointerEventData = new PointerEventData(eventSystem);
if (eventData == null)
{
m_PointerEventData.position = Input.mousePosition;
}
else
{
m_PointerEventData.position = eventData.position;
}
var results = new List<RaycastResult>();
raycaster.Raycast(m_PointerEventData, results);
foreach (RaycastResult result in results)
{
var component = result.gameObject.GetComponent<T>();
if (component != null)
{
return component;
}
}
return default;
}
When call this method within OnEndDrag, pass in the PointerEventData that unity provides and use its position.
I'm trying to control RGB LED's with an ESP8266 module. But if i try to control multiple ESP8266 modules at once, the for loop only works for the last array element.
I've tried Toast.makeText(applicationContext, i.toString(), Toast.LENGTH_SHORT).show()
and the loop only counts 2 also if i remove the if statement.
The toast itself works fine on the AVD but not on my Galaxy S8.
The loading of all ips doesn't work on my phone and on the AVD.
Every time i try to control multiple devices only the last one lights up.
Here's my RGBActivity maybe I'm missing something.
iv_rgb.setOnTouchListener {
_,
event - >
if (event.action == MotionEvent.ACTION_DOWN || event.action == MotionEvent.ACTION_MOVE) {
bitmap = iv_rgb.drawingCache
val pixel = bitmap.getPixel(event.x.toInt(), event.y.toInt())
var r = (Color.red(pixel) * brightness) / 100
var g = (Color.green(pixel) * brightness) / 100
var b = (Color.blue(pixel) * brightness) / 100
val hex = "#" + Integer.toHexString(pixel)
for (i in Devices.deviceIP.indices) {
if (Devices.switch[i]) {
wv_rgb.loadUrl("http://${Devices.deviceIP[i]}/?r${r.toString()}g${g.toString()}b${b.toString()}&")
Toast.makeText(applicationContext, Devices.deviceIP[i], Toast.LENGTH_SHORT).show()
}
}
}
true
}
If `wv_rgb' is a WebView than for a loadUrl you have to wait for event onPageFinished() (or onPageLoaded() forgot name).
inside the loop you can try using onPageStarted() passing view url anf favicon and than call onPageFinished()(as stated by #blackapps) passing view and url. or try using conventional for loop(not sure, but worth a shot).
also you can look into this link https://android--code.blogspot.com/2016/03/android-detect-when-webview-finish.html
Please help me in finding a solution that will be very useful for many other people after me.
I have a simple/standard carousel made in Bootstrapie. The problem starts when I want with the swipe right or left go to next or previous tab in the carousel at the browser in Android.
I know that is the mass of plug-ins that provide such functionality Bootstrapping carousel. I used the simplest way using component "touch" from jQuery Mobile. When I use desktop browser (chrome, ff, opera) and using the mouse to swipe left/right it all works nicely (changing cards).
However, when I use the android browser I haven't such a possibility. My diagnosed why this happens (unfortunately, this is so independent of plugin enabled swipe and I lost a lot of time trying to find a running plugin - tested hammer.js bootstrap-touch-carousel.js, slick.js, jquery.touchSwipe.js, etc.). The reason is use by me a configurable scrollbar'a from plugin - manos.malihu. My diagnosis is to find part of code in the above plugin: jquery.Custom Scrollbar.js whose responsible for swipe (and blocking swipe from e.g. jQuery Mobile). Below I paste code responsible for the swipe in manos.malihu plugin:
/*
TOUCH SWIPE EVENTS
scrolls content via touch swipe
Emulates the native touch-swipe scrolling with momentum found in iOS, Android and WP devices
*/
_contentDraggable=function(){
var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
namespace=pluginPfx+"_"+d.idx,
mCustomScrollBox=$("#mCSB_"+d.idx),
mCSB_container=$("#mCSB_"+d.idx+"_container"),
mCSB_dragger=[$("#mCSB_"+d.idx+"_dragger_vertical"),$("#mCSB_"+d.idx+"_dragger_horizontal")],
draggable,dragY,dragX,touchStartY,touchStartX,touchMoveY=[],touchMoveX=[],startTime,runningTime,endTime,distance,speed,amount,
durA=0,durB,overwrite=o.axis==="yx" ? "none" : "all",touchIntent=[],touchDrag,docDrag,
iframe=mCSB_container.find("iframe"),
events=[
"touchstart."+namespace+" pointerdown."+namespace+" MSPointerDown."+namespace, //start
"touchmove."+namespace+" pointermove."+namespace+" MSPointerMove."+namespace, //move
"touchend."+namespace+" pointerup."+namespace+" MSPointerUp."+namespace //end
],
touchAction=document.body.style.touchAction!==undefined;
mCSB_container.bind(events[0],function(e){
_onTouchstart(e);
}).bind(events[1],function(e){
_onTouchmove(e);
});
mCustomScrollBox.bind(events[0],function(e){
_onTouchstart2(e);
}).bind(events[2],function(e){
_onTouchend(e);
});
if(iframe.length){
iframe.each(function(){
$(this).load(function(){
/* bind events on accessible iframes */
if(_canAccessIFrame(this)){
$(this.contentDocument || this.contentWindow.document).bind(events[0],function(e){
_onTouchstart(e);
_onTouchstart2(e);
}).bind(events[1],function(e){
_onTouchmove(e);
}).bind(events[2],function(e){
_onTouchend(e);
});
}
});
});
}
function _onTouchstart(e){
if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){touchable=0; return;}
touchable=1; touchDrag=0; docDrag=0; draggable=1;
$this.removeClass("mCS_touch_action");
var offset=mCSB_container.offset();
dragY=_coordinates(e)[0]-offset.top;
dragX=_coordinates(e)[1]-offset.left;
touchIntent=[_coordinates(e)[0],_coordinates(e)[1]];
}
function _onTouchmove(e){
if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){return;}
if(!o.documentTouchScroll){e.preventDefault();}
e.stopImmediatePropagation();
if(docDrag && !touchDrag){return;}
if(draggable){
runningTime=_getTime();
var offset=mCustomScrollBox.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left,
easing="mcsLinearOut";
touchMoveY.push(y);
touchMoveX.push(x);
touchIntent[2]=Math.abs(_coordinates(e)[0]-touchIntent[0]); touchIntent[3]=Math.abs(_coordinates(e)[1]-touchIntent[1]);
if(d.overflowed[0]){
var limit=mCSB_dragger[0].parent().height()-mCSB_dragger[0].height(),
prevent=((dragY-y)>0 && (y-dragY)>-(limit*d.scrollRatio.y) && (touchIntent[3]*2<touchIntent[2] || o.axis==="yx"));
}
if(d.overflowed[1]){
var limitX=mCSB_dragger[1].parent().width()-mCSB_dragger[1].width(),
preventX=((dragX-x)>0 && (x-dragX)>-(limitX*d.scrollRatio.x) && (touchIntent[2]*2<touchIntent[3] || o.axis==="yx"));
}
if(prevent || preventX){ /* prevent native document scrolling */
if(!touchAction){e.preventDefault();}
touchDrag=1;
}else{
docDrag=1;
$this.addClass("mCS_touch_action");
}
if(touchAction){e.preventDefault();}
amount=o.axis==="yx" ? [(dragY-y),(dragX-x)] : o.axis==="x" ? [null,(dragX-x)] : [(dragY-y),null];
mCSB_container[0].idleTimer=250;
if(d.overflowed[0]){_drag(amount[0],durA,easing,"y","all",true);}
if(d.overflowed[1]){_drag(amount[1],durA,easing,"x",overwrite,true);}
}
}
function _onTouchstart2(e){
if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){touchable=0; return;}
touchable=1;
e.stopImmediatePropagation();
_stop($this);
startTime=_getTime();
var offset=mCustomScrollBox.offset();
touchStartY=_coordinates(e)[0]-offset.top;
touchStartX=_coordinates(e)[1]-offset.left;
touchMoveY=[]; touchMoveX=[];
}
function _onTouchend(e){
if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){return;}
draggable=0;
e.stopImmediatePropagation();
touchDrag=0; docDrag=0;
endTime=_getTime();
var offset=mCustomScrollBox.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left;
if((endTime-runningTime)>30){return;}
speed=1000/(endTime-startTime);
var easing="mcsEaseOut",slow=speed<2.5,
diff=slow ? [touchMoveY[touchMoveY.length-2],touchMoveX[touchMoveX.length-2]] : [0,0];
distance=slow ? [(y-diff[0]),(x-diff[1])] : [y-touchStartY,x-touchStartX];
var absDistance=[Math.abs(distance[0]),Math.abs(distance[1])];
speed=slow ? [Math.abs(distance[0]/4),Math.abs(distance[1]/4)] : [speed,speed];
var a=[
Math.abs(mCSB_container[0].offsetTop)-(distance[0]*_m((absDistance[0]/speed[0]),speed[0])),
Math.abs(mCSB_container[0].offsetLeft)-(distance[1]*_m((absDistance[1]/speed[1]),speed[1]))
];
amount=o.axis==="yx" ? [a[0],a[1]] : o.axis==="x" ? [null,a[1]] : [a[0],null];
durB=[(absDistance[0]*4)+o.scrollInertia,(absDistance[1]*4)+o.scrollInertia];
var md=parseInt(o.contentTouchScroll) || 0; /* absolute minimum distance required */
amount[0]=absDistance[0]>md ? amount[0] : 0;
amount[1]=absDistance[1]>md ? amount[1] : 0;
if(d.overflowed[0]){_drag(amount[0],durB[0],easing,"y",overwrite,false);}
if(d.overflowed[1]){_drag(amount[1],durB[1],easing,"x",overwrite,false);}
}
function _m(ds,s){
var r=[s*1.5,s*2,s/1.5,s/2];
if(ds>90){
return s>4 ? r[0] : r[3];
}else if(ds>60){
return s>3 ? r[3] : r[2];
}else if(ds>30){
return s>8 ? r[1] : s>6 ? r[0] : s>4 ? s : r[2];
}else{
return s>8 ? s : r[3];
}
}
function _drag(amount,dur,easing,dir,overwrite,drag){
if(!amount){return;}
_scrollTo($this,amount.toString(),{dur:dur,scrollEasing:easing,dir:dir,overwrite:overwrite,drag:drag});
}
},
I see that in desktop browser is used to swipe from jQuery mobile. Changing cards from carousel works with swipe by mouse (press left mouse button and drag to left or right).
Code with swipe using jQuery mobile:
$('.carousel').swiperight(function() {
$(this).carousel('prev');
});
$('.carousel').swipeleft(function() {
$(this).carousel('next');
});
After many attempts I cann't make changes in "jquery.mCustomScrollbar.js" such to get the same functionality in android browser with touch of a finger. My a function call from "jquery.mCustomScrollbar.js":
jQuery('.carousel-item').mCustomScrollbar({ axis:"y", theme: "rounded-dots", scrollButtons: { enable: true }, scrollInertia: 100});
For you it will be easier than for me to add/change code snippet in jquery.mCustomScrollbar.js to get similar functionality for both browsers (desktop, android).
P.S.
I warn you, when I use:
contentTouchScroll: false
In fact, I have similar functionality on both browsers, but this not the way because I block possibility to scroll up/down with touch(swipe) your finger up/down.
Issue reported on github creator plugin
[but I guess that support from creators rather isn't possible at this moment]
I would be very grateful for your help. I lost too much time trying to solve the problem yourself
Regards Zic
This should only remove e.stopImmediatePropagation() from above part of plugin (_OnTouch/Start/Move/End)
everyone! I have trouble with combination in one scene multi touch and one touch with. So let me describe my problem step by step.
I use cocos2dx( for android ), So I have scene, on this scene I add layer Pan Zoom Layer for scroll and zoom. next, I add new layer(Game Layer) on PanZoomLayer. I need catch click on Game Layer(on this layer located my game things) I try to do so, using pattern observer,I have done PanZoom Layer by "Subject" my Game Layer - "Observer", and in PanZoomLayer Have created enum EVENTS, and struct touchEvent
enum EVENTS{
EVENT_ONCE_CLICK,
EVENT_MOVE,
ANOTHER,
};
struct touchEvent {
EVENTS eventName;
};
and created in class PanZoomLayer field m_events :
std::stack<EVENTS> m_events;
and on onTouchesBegan add such code
if (_touches.size() == 1) {
m_events.push(EVENTS::EVENT_ONCE_CLICK);
}
else {
m_events.push(EVENTS::ANOTHER);
}
in onTouchesMoved add such code in branch if _touches.size() == 1:
Vec2 curTouchPosition = Director::getInstance()->convertToGL(touch->getLocationInView());
Vec2 prevTouchPosition = Director::getInstance()->convertToGL(touch->getPreviousLocationInView());
Vec2 deltaPosition = curTouchPosition - prevTouchPosition;
float pos = curTouchPosition.distance(prevTouchPosition);
if (fabs(pos) < 0.5f) {
m_events.push(EVENTS::EVENT_ONCE_CLICK);
}
else {
m_events.push(EVENTS::ANOTHER);
}
an onTouchesEnded, add such code :
if (m_events.empty())
return;
EVENTS ev = m_events.top();
while (!m_events.empty()) {
m_events.pop();
}
if (ev == EVENTS::EVENT_ONCE_CLICK) {
// MessageBox("once click", "title");
Touch *touch = (Touch *)_touches.at(0);
Vec2 position = touch->getLocation();
notifyClick(position);
}
where notifyClick :
std::shared_ptr<CSceneSession> sessionShared = m_session.lock();
if (sessionShared)
sessionShared->clickOnScene(point);
So I enter in game cycle : game scene -> transition on menu scene -> game scene...... in start it great work, but after some time ( on difference devices - different time) game begin strange behavior : buggy,
Could you help me please? Thanks for any idea and suggestions.
I Solved my problem in the following way: I remove scheduleUpdateForTarget in method onEnter and remove unscheduleAllForTarget in method onExit and remove method update.
Thank you for your attention!
Ok, I have three conditions here. It's seems pretty simple, but I can't get it working how I want, bear with me as I try to explain it.
If(conditionA){
Play Sound 1}
If(conditionB) {
changedrawable ///(irrelevant)
}
If(conditionA && conditionB){
Play sound 2
}
////Unfortunately, since condition A is true, it plays sound 1 too, and I only want it to play sound 2
FWIW These conditions are just coordinates on the touchscreen, and I have them set up as boolean's
Boolean conditionA;
conditionA = y > 0 && y < (0.2 * tY) && x > 0 && x < (0.1667 * tX) || y2 > 0
&& y2 < (0.2 * tY) && x2 > 0 && x2 < (0.1667 * tX);
ConditionA and ConditionB are referring to different points on the touchscreen. The main question: how on earth can I get it so when conditionA and conditionB are BOTH true, ONLY Play Sound 2 (instead of both sounds)? I have been pulling my hair out the last day trying to figure this out. Please let me know if there is a solution or if you need further details. Thanks!
This may not be perfectly optimal, but it's easy to read:
if (conditionA && conditionB) {
play sound 2
} else if (conditionA) {
// Implies that conditionB == false
play sound 1
} else if (conditionB) {
change drawable
}
Shouldn't it be
if(conditionA && conditionB) {
play sound 2
} else if(conditionA) {
play sound 1
}
if(conditionB) {
change drawable
}
You only want the else if for playing the sound. Not for changing the drawable.
How about:
if (conditionA && conditionB) {
// play sound2
} else if (conditionA) {
// play sound1
} else if (conditionB) {
// change drawable
}
If both conditions aren't satisfied, it'll run the code for the condition that is. If they are both satisfied, it'll only run //play sound2.
Just put the third option as the first, and then use else ifs in case not both conditions are fulfilled.
edit/ what he says :)
This may not be the most elegant solution, but it should work:
if (conditionA && conditionB) {
play sound 2
}
else {
if (conditionA){
play sound 1
}
if (conditionB) {
change drawable
}
}