I'm somehow getting unexpected results while trying to implement multitouch in my app. I'm never getting data for more than one pointer.
Multitouch on my phone surely works, because I can pinch-zoom in browser and detect pinch gesture with GestureDetector, but the following sample prints action=0 pointers=1 regardless of how many fingers I use to touch the screen.
Is there something in configuration/AndroidManifest or Activity creation that I need to
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.ll1).setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG","onTouch action="+event.getAction()+" pointers="+event.getPointerCount());
return false;
}
});
}
layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ll1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
</LinearLayout>
The problem was that I was returning false in onTouch, therefore new touch events have not been generated.
In my case, I realized that getPointerCount() was not changing because it was being called inside the MotionEvent.ACTION_DOWN action which meant it'd always be one.
The solution was to move it, either to MotionEvent.ACTION_MOVE if the pointer count is needed on move, either outside of the actions, to the onTouch implementation if the pointer count is needed once on touch. I hope this helps someone who may not have understood this as in my case.
Related
I have been successful with adding onClick listeners directly
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="#{action::onItemClicked}" />
and onRefreshListener listeners as well
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:onRefreshListener="#{action::onRefresh}">
but I cannot understand why I am not able to do the following
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:onTouchListener="#{action::onItemTouched}" />
It shows the following error:
Listener class android.view.View.OnTouchListener with method onTouch did not match signature of any method action::onItemTouched
And another error if I use android: instead of app: or onTouch instead of onTouchListener.
Yet the method signature of onItemTouched is as defined in the View.java source file:
public void onItemTouched(View v, MotionEvent event) {
// no dice
}
As far as I can see, TextView is a View and as such it should have worked: https://android.googlesource.com/platform/frameworks/base/+/a175a5b/core/java/android/view/View.java#14494
So what am I doing wrong, why won't this work? Should it be a different attribute name?
And please no #BindingAdapter or similar suggestions, I already know how to do it that way. My objective is to keep the model clutter free and attach the methods directly on the views as I did for clicks and swipe refresh.
Got it working, the only problem was the method was void, but the onTouch signature requires a boolean return. In the end this is how it should be:
Layout file sample
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onTouch="#{action::onItemTouched}" />
or
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onTouchListener="#{action::onItemTouched}" />
Action class method
public boolean onItemTouched(View v, MotionEvent event) {
// now it works, do your magic
return true; // or return false, depending on what you want to do
}
Only worry now is Android Studio complains that android:onTouch is an unknown attribute, I hope it won't turn non-public for some odd reason in the future. For that reason I will be using the following method in the layout just to get rid of the warning message
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:onTouch="#{action::onItemTouched}" />
// app:onTouchListener works as well
I've been seeing an issue in an app I'm working on relating to views being visible when they shouldn't be and I was wondering if anyone had seen similar.
I have a fragment viewed from a viewPager, that fragment has a base layout, in that base layout I include a banner style area with some info in it and a button, the layout is defaulted to GONE in the XML, like this.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:animateLayoutChanges="true" >
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/usage_swipe_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:animateLayoutChanges="true"
android:layout_height="match_parent">
<ScrollView
android:id="#+id/usage_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:background="#color/background_colour">
<include layout="#layout/layout_in_question"
android:id="#+id/layout_in_question_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"/>
.... Normal Stuff in layout
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
This view is only set to VISIBLE in very select circumstances. However some users are seeing it outside of those circumstances based on a response from a server call, its a very low percentage of users who are seeing it when they shouldn't ( in the region of 0.001% ), the server team insist its not them so I'm trying to ascertain if there are any known android issue or "hacks" that allow this sort of thing. The App supports API 15 and up and we're currently using support libs 25.3.0.
Has anyone seen behavior like this before? are there developer options on some devices that "show all views" or Modded OS's that allow it?
Edit: While I cant share full code snippets due to NDA, I have 2 locations the view can be enabled, both call the same method.
private View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState)
{
setupBanner();
}
/**
* OTTO event based on server response
*/
#Subscribe
public void receiveEvent(BannerEvent event)
{
setupBanner();
}
public void setupBanner() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (shouldShowBanner()) {
findViewById(R.id.layout_in_question_id).setVisibility(View.VISIBLE);
}
}
});
}
shouldShowBanner returns a boolean which is either true/false depending on what the server responded with.
I am using an ImageView as a NEXT button in my Android app which is responsible for loading the next page of results into the current activity. However, despite that I bind a click listener to it, I cannot seem to capture click events on this ImageView. Here is the XML:
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="50"
android:gravity="left"
android:orientation="horizontal">
<ImageView
android:id="#+id/listBackIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/back_icon"/>
<TextView
android:id="#+id/listBackLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Prev"
android:textSize="16dip"/>
</LinearLayout>
And here is the relevant Java code:
ImageView forwardIconView = (ImageView)findViewById(R.id.listBackIcon);
// not sure if necessary; doesn't fix it anyway
forwardIconView.setClickable(true);
forwardIconView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
++pageNumber;
try {
params.put("page", pageNumber);
} catch (JSONException e) {
// do something
}
ConnectionTask task = new ConnectionTask();
task.execute(new String[0]);
}
});
I spent about an hour researching this on Stack Overflow. I found a few places which claimed that ImageView could directly be made clickable, but most things recommended workarounds using other types of widgets.
Does anything about my layout/code stand out as being a culprit for this behavior?
Update:
I also tried binding a click listener to the TextView at the same level as the ImageView and this too failed to capture clicks. So now I am suspecting that the views are being masked by something. Perhaps something is capturing the clicks instead of the views.
I would set it up like this:
private ImageView nextButton;
nextButton = (ImageView)view.findViewById(R.id.back_button);
Util.loadImage(getActivity(),R.drawable.some_image,nextButton); //Here i would load the image, but i see you do it in XML.
nextButton.setOnClickListener(nextButtonListener);
nextButton.setEnabled(true);
View.OnClickListener nextButtonListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.v(TAG, "ImageView has been clicked. do something.");
}
};
This works for me.
Why not use android:drawableLeft attribute for the textview instead of using imageView​ and textview both in a linearlayout .
<ImageView
android:id="#+id/listBackIcon"
...
android:clickable="true"
Or you can try overriding onTouchListener with ACTION_DOWN event filter, not onClickListener. Also check for parrents with android:clickable="false", they could block childs for click events.
What seemed to work for me was the accepted answer from this SO question, which suggests adding the following the every child element of the LinearLayout which I pasted in my question:
android:duplicateParentState="true"
I don't know exactly what was happening, but it appears the click events were not making it down to the TextView and ImageView. Strangely, the click events were reaching a Button, when I added one for debugging purposes. If someone has more insight into what actually happened, leave a comment and this answer can be updated.
I've been working on an app where a ball (bitmap) appears on the canvas at the point where the user taps on the screen. The background is an xml layout setContentView(R.layout.newsession). The canvas is a black painted canvas. When i set my java parent class setContentView(customView), the program works fine but when I add the custom surface view to my XML layout and setContentView(R.layout.newsession), the screen just shows the canvas, and the OnTouch event doesn't work. Am I doing something wrong? I've been working on this for almost a week now and I really need help. I will post my code below for the XML layout and custom surfaceView. Thanks in advance!
XML layout (newsession)
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/newSessionPage"
>
<ImageView
android:layout_width="231dp"
android:id="#+id/ivStrikeGrid"
android:layout_gravity="center"
android:layout_height="270dp"
android:layout_marginTop="18dp"
android:src="#drawable/strike_grid"
android:layout_marginBottom="10dp"
/>
<appsys.studios.CustomSurfaceViewOne
android:id="#+id/customSurfaceViewOne1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></appsys.studios.CustomSurfaceViewOne
>
</FrameLayout>
Custom SurfaceView
package appsys.studios;
public class CustomSurfaceViewOne extends SurfaceView implements Runnable{
public CustomSurfaceViewOne(Context context, AttributeSet attr) {
super(context, attr);
ourHolder = getHolder();
}
// Other stuff
}
It works fine like this:
newSeshView = new CustomSurfaceViewOne(this, null);
setContentView(newSeshView);
But nothing happens when I try to use it from the XML layout, like this:
newSeshView = new CustomSurfaceViewOne(this, null);
setContentView(R.layout.newsession);
Thanks again! :)
I think you might be missing invallidate() call of the view on its touch reading delegates.
I am not sure exactly what is happening in your code. But if i would be creating my own view and adding it in my own layout as you did.
And want it to change itself on reading touch events then i would be doing something like
in the myown view class it self
#override
// i dont remem exact signature of this method. google it or see docs
// motive is to read touch event of view and doing appropriate changes
// and redrawing the view again
public void onTouchEvent(MotionEvent me)
{
doCalculation(); // change points where to draw the ball next time. Read me
invalidate(); // tell the view re draw it self
}
Hope it helps :)
I ran into the same issue, and found your question while looking for the answer. I solved it, but I'm not sure it is the proper way.
3 files, your main activity, your surfaceview, and your XML file.
Your XML file looks ok, you have the surfaceview in it
<appsys.studios.CustomSurfaceViewOne
android:id="#+id/customSurfaceViewOne1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></appsys.studios.CustomSurfaceViewOne
>
In your activity, add implements OnTouchListener, use setContentView(R.layout.newsession); and after that, still in your onCreate() add this line CustomViewOne cvo = (CustomViewOne)findViewById(R.id.customSurfaceViewOne1) and set the listener to it by cvo.setOnTouchListener(this);
then add your onTouch
#Override
public boolean onTouch(View v, MotionEvent event) {
customSurfaceViewOne1.myOnTouch(event);
return false;
}
where myOnTouch() is a method in your customSurfaceViewOne1 class where you will do all your ontTouch events. Notice I passed in the MotionEvent event.
Again, I'm not sure if this is the proper way to do it, it's just how I got it to work. The reason I did it was just so I could have an admob ad above my surfaceview lol.
I am fighting with focus management of WebView: WebView messes with focus management of classic components. Here is a simple application with just an EditBox and a WebView in it which loads Google!
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:and="http://schemas.android.com/apk/res/android"
xmlns:webtag="http://schemas.android.com/apk/res/com.webtag"
and:orientation="vertical" and:layout_width="fill_parent" and:layout_height="fill_parent">
<LinearLayout and:id="#+id/HorizontalScrollView02"
and:layout_width="fill_parent" and:layout_height="wrap_content">
<EditText and:id="#+id/EditText01"
and:layout_width="wrap_content" and:layout_height="wrap_content"
and:text="#+id/EditText01"/>
</LinearLayout>
<WebView and:id="#+id/uiContent"
and:layout_weight="1"
and:layout_width="fill_parent"
and:layout_height="fill_parent"/>
</LinearLayout>
And here is the Java code:
public class WebtagActivity extends Activity
{
// UI components.
private WebView mContent;
private EditText mUrl;
#Override
public void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContent = (WebView) findViewById(R.id.uiContent);
mContent.getSettings().setJavaScriptEnabled(true);
mContent.loadUrl("http://www.google.fr/");
}
}
Based on this very simple example, it's impossible to get focus on the WebView (i.e. the google search terms input box)! However when adding "mContent.requestFocus();" during initialization, things get better. I can switch from my EditText to my WebView if I click on WebView first only... But behaviour gets soon very "erratic", with WebView sometimes not getting focus when touching it, sometimes getting it but staying with a focus rectangle around WebView fields (orange or green depending on your phone) after another touch to go back on EditText component (in which I can write text)!
Anyway, a solution I found is to add a touchListener and request focus when clicking on a WebView:
mContent.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
if (!v.hasFocus()) {
v.requestFocus();
}
break;
}
return false;
}
});
This solves almost all problems (switching from classic components to WebView and writing text) except one: WebView keeps the focusRectangle (green or orange) around fields whether it has focus or not. In the below screenshot, my EditText has the focus and receive text but WebView still looks like it has focus. I tried clearFocus but that doesn't do anything:
See the result
Any idea how to solve this?
Thanks a lot for your help!
make sure that parent layout that extends "ViewGroup" doesn't have property
android:descendantFocusability = "blocksDescendants" which prevent child layout from getting focused
This helped my problem for focus:
Webview.requestFocus(View.FOCUS_DOWN|View.FOCUS_UP);
and this for sensitive touch:
Webview.getSettings().setLightTouchEnabled(true);
Just add android:focusable="true" to your WebView layout:
<WebView android:id="#+id/uiContent"
android:layout_weight="1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:focusable="true"/>