key event problem

Put problem concerning Views, Layouts and other XML-Resources (like AndroidManifest) here.

key event problem

Postby mpathare » Sun May 24, 2009 5:42 pm

I have a parent ScrollView with a child view. When the user presses the back button, I want the child view to handle the event. I have tried a couple of things but none of them seem to work. pressing the back button kill sthe activity.

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class GameScrollView extends ScrollView{
  3.  
  4.        
  5.  
  6.         public GameScrollView(Context context) {
  7.  
  8.                 super(context);
  9.  
  10.         }
  11.  
  12.         @Override
  13.  
  14.         public boolean onInterceptTouchEvent (MotionEvent ev){
  15.  
  16.                 return false;
  17.  
  18.                
  19.  
  20.         }
  21.  
  22.         @Override
  23.  
  24.         public boolean onKeyDown (int keyCode, KeyEvent event){
  25.  
  26.                 return false;
  27.  
  28.                
  29.  
  30.         }
  31.  
  32. }
  33.  
  34.  
Parsed in 0.031 seconds, using GeSHi 1.0.8.4


in the child view I have the following code
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class GameView extends View implements OnTouchListener, onKeyListener{
  3.  
  4.  
  5.  
  6.         public boolean onKey(View v, int keyCode, KeyEvent event){
  7.  
  8.                 if(keyCode == KeyEvent.KEYCODE_BACK){
  9.  
  10.                     //do stuff
  11.  
  12.                 }
  13.  
  14.                 invalidate();
  15.  
  16.                 return true;           
  17.  
  18.         }
  19.  
  20. }
  21.  
  22.  
Parsed in 0.031 seconds, using GeSHi 1.0.8.4

In the ScrollView I have also tried overriding the dispatchKeyEvent method to return false, but that did not work either. What am I doing wrong here?

Thanks!
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Top

Postby mangaluve » Sun May 24, 2009 7:27 pm

You don't have to override the methods in your ScrollView. I've never worked with key-events like this, so Im just spitballing, but you could try to do something like

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. setFocusable(true);
  2.  
  3. setFocusableInTouchMode(true);
Parsed in 0.034 seconds, using GeSHi 1.0.8.4

on your own View (for instance in the constructor). The problem otherwise is (I think) that your views don't show that they can be focused, so the Activity wont even bother to pass the keypress down to your ScrollView.
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby mpathare » Sun May 24, 2009 8:20 pm

Hey,
I do get key events passed to my scrollView. This was something I needed help with last week and I think you helped me with it!

See, I return false from the onInterceptTouchEvent method in my ScrollView because I wanted all gestures to be handled by the child view. I am able to scroll by using the direction keys. This makes me think that key press events are being passed to the scrollView. I just want a particular key press to be sent to the child view (the back key)

Let me try setting the focus property and see if that works.
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Postby mangaluve » Sun May 24, 2009 8:45 pm

Sorry, the ScrollView is automatically focusable, but it won't forward the key events to the child (i.e. your View) unless it's focusable aswell... at least I think so :)

By overriding for instance the intercept-method and just let it return false, you'll not be able to scroll with a motion event, or am I wrong?
Last edited by mangaluve on Sun May 24, 2009 9:05 pm, edited 1 time in total.
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby mpathare » Sun May 24, 2009 9:03 pm

My child view is focusable. I have set its focusable property in the constructor.

this is what I have in the ScrollView....
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2.         @Override
  3.  
  4.         public boolean onKeyDown(int keyCode, KeyEvent event){
  5.  
  6.                 if(keyCode == KeyEvent.KEYCODE_BACK){
  7.  
  8.                         return false;
  9.  
  10.                 }
  11.  
  12.                 else{
  13.  
  14.                         return true;
  15.  
  16.                 }
  17.  
  18.         }
  19.  
  20.  
Parsed in 0.040 seconds, using GeSHi 1.0.8.4


This doesnt work. The thing I dont get is that this piece of code also breaks the scrolling (if I remove the above code I can scroll using the up/down direction keys)

pressing the back key still kills the activity.
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Postby mangaluve » Sun May 24, 2009 9:11 pm

You should return true when you press back, and false otherwise, so just swap the return statements.

When you return true, it means that your View has "consumed" the key press, so it wont be used anymore. However, if you return false, the View above it will instead get the keyPress. When a View gets a key event, it will always try to pass it to the children. If all the childrens onKey-methods returns false, however, it will process the event by itself. So for your code, when you press back and return false, you'll tell the Views above, and ultimately the Activity itself, to handle the back-press. And default behaviour for an Activity is to close itself when the users hits the back key.
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Top

Postby mpathare » Sun May 24, 2009 9:49 pm

I am still a little confused. I thought that returning true from a method in a view means that the view consumed the event Why would a view then pass this event to its children? I thought that if you wanted to pass the touch/key event to your children then you should return false so the view will ignore the event and pass it on.

This is what I have done now

parent scroll view
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class GameScrollView extends ScrollView{
  3.  
  4.        
  5.  
  6.         public GameScrollView(Context context) {
  7.  
  8.                 super(context);
  9.  
  10.         }
  11.  
  12.        
  13.  
  14.         @Override
  15.  
  16.         public boolean onInterceptTouchEvent (MotionEvent ev){
  17.  
  18.                 return false;
  19.  
  20.                
  21.  
  22.         }
  23.  
  24.        
  25.  
  26.         @Override
  27.  
  28.         public boolean onKeyDown(int keyCode, KeyEvent event){
  29.  
  30.                 if(keyCode == KeyEvent.KEYCODE_BACK){
  31.  
  32.                         return true;
  33.  
  34.                 }
  35.  
  36.                 else{
  37.  
  38.                         return false;
  39.  
  40.                 }
  41.  
  42.         }
  43.  
  44. }
  45.  
  46.  
Parsed in 0.041 seconds, using GeSHi 1.0.8.4


child view
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2.         public boolean onKey(View v, int keyCode, KeyEvent event){
  3.  
  4.                 if(event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK){
  5.  
  6.                 //do stuff
  7.  
  8.                 invalidate();
  9.  
  10.                 return true;
  11.  
  12.                 }
  13.  
  14.                 else{
  15.  
  16.                 return false;
  17.  
  18.                 }
  19.  
  20.         }
  21.  
  22.  
Parsed in 0.041 seconds, using GeSHi 1.0.8.4


When the back button is pressed I want the "do stuff" code to be executed in the child view. What happens now, is that the activity gets killed (whis is the default for the back button).

Activity code in case you want to look at it
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class myAct extends Activity{
  3.  
  4.     /** Called when the activity is first created. */
  5.  
  6.         private Context mContext;
  7.  
  8.         private GameView mGv;
  9.  
  10.         private GameScrollView mGsv;
  11.  
  12.        
  13.  
  14.     @Override
  15.  
  16.     public void onCreate(Bundle savedInstanceState) {
  17.  
  18.         super.onCreate(savedInstanceState);
  19.  
  20.         mContext = this;
  21.  
  22.         setContentView(R.layout.main);
  23.  
  24.     }
  25.  
  26.    
  27.  
  28.     @Override
  29.  
  30.     public boolean onCreateOptionsMenu(Menu menu) {
  31.  
  32.         boolean result = super.onCreateOptionsMenu(menu);
  33.  
  34.         menu.add(0, 1, 0, R.string.newGame);
  35.  
  36.         menu.add(0, 2, 0, R.string.exitGame);
  37.  
  38.         return result;
  39.  
  40.     }
  41.  
  42.    
  43.  
  44.     @Override
  45.  
  46.     public boolean onOptionsItemSelected(MenuItem item) {
  47.  
  48.         switch (item.getItemId()) {
  49.  
  50.         case 1:
  51.  
  52.                 mGv = new GameView(this);
  53.  
  54.                 mGsv = new GameScrollView(this);
  55.  
  56.                 mGsv.addView(mGv);
  57.  
  58.                 setContentView(mGsv);
  59.  
  60.             return true;
  61.  
  62.         case 2:
  63.  
  64.             finish();
  65.  
  66.             return true;
  67.  
  68.         }
  69.  
  70.         return false;
  71.  
  72.     }
  73.  
  74.    
  75.  
  76. }//end class
  77.  
  78.  
Parsed in 0.105 seconds, using GeSHi 1.0.8.4
Last edited by mpathare on Sun May 24, 2009 10:14 pm, edited 1 time in total.
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Postby mangaluve » Sun May 24, 2009 9:56 pm

First of all, where are you setting the OnKeyListener (since your View implements it).

What happens if you remove all the keycode from your scroll view?

To answer your question regarding returning true/false:
The onKeyDown method in the parent will be executed After the onKeyDown method has been invoked on the child! Actually, the onKeyDown isn't used to pass the key event down the View tree, the dispatchKeyEvent method is!

What happens is essentially that a View's dispatchKeyEvent will be called. That method will the call dispatchKeyEvent on the children. If all the childrens return false (or there were no children), the onKey-method will run.

So every view has a dispatchKeyEvent that looks something like:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public boolean dispatchKeyEvent(...) {
  2.  
  3.     if(!child.dispatchKeyEvent(...))
  4.  
  5.           return onKey(...);
  6.  
  7.     return true;
  8.  
  9. }
Parsed in 0.069 seconds, using GeSHi 1.0.8.4


So it will first execute dispatchKeyEvent on all children. If the children, however, all return false, then the onKey method will be used.

For Views that dont't have any children, all the dispatchKeyEvent method will do is to call onKey or whatever it's called. Of course the real implementations of dispatchKey and so on are more sophisticated, but the stub I wrote above shows the essential flow.
Last edited by mangaluve on Sun May 24, 2009 10:06 pm, edited 1 time in total.
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby mpathare » Sun May 24, 2009 10:05 pm

I implement the listener in my child view like so.

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class GameView extends View implements OnTouchListener, OnKeyListener{
  3.  
  4.   public GameView{
  5.  
  6.                 this.setOnTouchListener(this);
  7.  
  8.                 this.setOnKeyListener(this);
  9.  
  10.   }
  11.  
  12.  
  13.  
  14. }
  15.  
  16.  
Parsed in 0.050 seconds, using GeSHi 1.0.8.4


swapping the return values in the child view and removing all the key code from the ScrollView did not help :(
pressing the back button still kills the activity.
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Postby mangaluve » Sun May 24, 2009 10:13 pm

Hm so you have no code whatsoever in the scroll-class, and your onKey method looks something like this:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public boolean onKey(View v, int keyCode, KeyEvent event) {
  2.  
  3.                 if(event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) {
  4.  
  5.                         Log.w("MyView", "Weee do something clever here...");
  6.  
  7.                         return true;
  8.  
  9.                 }
  10.  
  11.                 return false;
  12.  
  13.         }
Parsed in 0.037 seconds, using GeSHi 1.0.8.4

and you're not doing anything else like overriding any onKey-methods or anything like that anywhere? And it still kills the Activity? And you're using

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. setFocusable(true);
  2.  
  3. setFocusableInTouchMode(true);
Parsed in 0.036 seconds, using GeSHi 1.0.8.4

in the constructor (where you have the setOnKeyListener now)?
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby mpathare » Sun May 24, 2009 10:17 pm

mostly yes. The only code I have in the Scroll class is

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2.         @Override
  3.  
  4.         public boolean onInterceptTouchEvent (MotionEvent ev){
  5.  
  6.                 return false;
  7.  
  8.                
  9.  
  10.         }
  11.  
  12.  
Parsed in 0.036 seconds, using GeSHi 1.0.8.4

I have this code so that all the touch events are sent to the child view

but other than that nothing...And I am not overriding onKey methods anywhere else.
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Postby mangaluve » Sun May 24, 2009 10:22 pm

Ah I see, you don't wanna scroll with your fingers?.. (because of the intercept-method).

That's strange. I just made a small sample which works for me, you can look at it and compare it to your code. Its a simple View inside of a ScrollView, the custom View only draws a 500x500 red square.
main.xml:
Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
  1. <?xml version="1.0" encoding="utf-8"?>
  2.  
  3.  
  4.  
  5. <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
  6.  
  7.         android:layout_width="fill_parent"
  8.  
  9.         android:layout_height="fill_parent" android:scrollbars="vertical">
  10.  
  11.         <com.scrolling.MyView
  12.  
  13.                 android:orientation="vertical" android:layout_width="fill_parent"
  14.  
  15.                 android:layout_height="fill_parent">
  16.  
  17.         </com.scrolling.MyView>
  18.  
  19. </ScrollView>
Parsed in 0.002 seconds, using GeSHi 1.0.8.4


TestActivity.java:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public class ScrollingActivity extends Activity {
  2.  
  3.     /** Called when the activity is first created. */
  4.  
  5.     @Override
  6.  
  7.     public void onCreate(Bundle savedInstanceState) {
  8.  
  9.         super.onCreate(savedInstanceState);
  10.  
  11.         setContentView(R.layout.main);
  12.  
  13.     }
  14.  
  15. }
Parsed in 0.037 seconds, using GeSHi 1.0.8.4


MyView.java:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public class MyView extends View implements OnKeyListener {
  2.  
  3.         public MyView(Context context, AttributeSet attrs) {
  4.  
  5.                 super(context, attrs);
  6.  
  7.                 setFocusable(true);
  8.  
  9.                 setFocusableInTouchMode(true);
  10.  
  11.                 setOnKeyListener(this);
  12.  
  13.         }
  14.  
  15.        
  16.  
  17.         @Override
  18.  
  19.         public void onDraw(Canvas canvas) {
  20.  
  21.                 Paint paint = new Paint();
  22.  
  23.                 paint.setColor(0xFFFF0000);
  24.  
  25.                
  26.  
  27.                 canvas.drawRect(0, 0, 500, 500, paint);
  28.  
  29.         }
  30.  
  31.        
  32.  
  33.         @Override
  34.  
  35.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  36.  
  37.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  38.  
  39.         setMeasuredDimension(500, 500);
  40.  
  41.     }
  42.  
  43.        
  44.  
  45.         @Override
  46.  
  47.         public boolean onKey(View v, int keyCode, KeyEvent event) {
  48.  
  49.                 if(event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) {
  50.  
  51.                         Log.w("MyView", "Weee do something clever here...");
  52.  
  53.                         return true;
  54.  
  55.                 }
  56.  
  57.                 return false;
  58.  
  59.         }
  60.  
  61. }
Parsed in 0.040 seconds, using GeSHi 1.0.8.4


You can scroll with the keys, and if you press back, the text "Weee do something clever here..." will be printed and the Activity does not die on you...
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby mpathare » Sun May 24, 2009 11:01 pm

Yea, I didnt want to scroll with touch because it seemed like too much work to differentiate between scroll gestures and gestures meant for the child view and handle them separately...

When I run your code as is, it works....with these changes it doesn't...

Activity
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class Test extends Activity {
  3.  
  4.     /** Called when the activity is first created. */
  5.  
  6.         private MyView mGv;
  7.  
  8.         private GameScrollView mGsv;
  9.  
  10.     @Override
  11.  
  12.     public void onCreate(Bundle savedInstanceState) {
  13.  
  14.         super.onCreate(savedInstanceState);
  15.  
  16.        
  17.  
  18.         mGv = new MyView(this);
  19.  
  20.         mGsv = new GameScrollView(this);
  21.  
  22.         mGsv.addView(mGv);
  23.  
  24.         setContentView(mGsv);
  25.  
  26.     }
  27.  
  28. }
  29.  
  30.  
  31.  
  32. child view
  33.  
  34.  
Parsed in 0.038 seconds, using GeSHi 1.0.8.4


Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class MyView extends View implements OnKeyListener{
  3.  
  4.  
  5.  
  6.         //called by parent view to get the measurement of a child view
  7.  
  8.         @Override
  9.  
  10.         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  11.  
  12.                 setMeasuredDimension(480, 400);
  13.  
  14.         }
  15.  
  16.  
  17.  
  18.         public MyView(Context context) {
  19.  
  20.                 super(context);
  21.  
  22.                 this.setOnKeyListener(this);
  23.  
  24.         }
  25.  
  26.  
  27.  
  28.         @Override
  29.  
  30.         protected void onDraw(Canvas canvas) {
  31.  
  32.         Paint paint = new Paint();
  33.  
  34.         paint.setColor(0xFFFF0000);
  35.  
  36.        
  37.  
  38.         canvas.drawRect(0, 0, 500, 500, paint);         }//end onDraw
  39.  
  40.  
  41.  
  42.         @Override
  43.  
  44.         public boolean onKey(View v, int keyCode, KeyEvent event){
  45.  
  46.                 if(event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK){
  47.  
  48.                         Log.w("gameview", "inside onkey");
  49.  
  50.                         return true;
  51.  
  52.                 }
  53.  
  54.                 return false;
  55.  
  56.         }
  57.  
  58. }
  59.  
  60.  
Parsed in 0.040 seconds, using GeSHi 1.0.8.4


parent scrollview
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class GameScrollView extends ScrollView{
  3.  
  4.        
  5.  
  6.         public GameScrollView(Context context) {
  7.  
  8.                 super(context);
  9.  
  10.         }
  11.  
  12.        
  13.  
  14.         @Override
  15.  
  16.         public boolean onInterceptTouchEvent (MotionEvent ev){
  17.  
  18.                 return false;
  19.  
  20.                
  21.  
  22.         }
  23.  
  24. }
  25.  
  26.  
Parsed in 0.037 seconds, using GeSHi 1.0.8.4


For some reason when I add the child view to the parent view in the activity it doesnt work. When I use the XML like you did, its fine.....I dont understand :shock:

No wait....I didn't set the focusable property to the child view...Now it works. Well now I only have to figure out how to get it to work in my main project :D

I'll let you know how it goes....Stay tuned!
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Postby mpathare » Sun May 24, 2009 11:26 pm

I think the problem is with the way I have my activity set up, but I cant figure out what it is

My activity looks like this

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class Test extends Activity {
  3.  
  4. /** Called when the activity is first created. */
  5.  
  6. private Context mContext;
  7.  
  8. private MyView mGv;
  9.  
  10. private GameScrollView mGsv;
  11.  
  12.  
  13.  
  14. @Override
  15.  
  16. public void onCreate(Bundle savedInstanceState) {
  17.  
  18.     super.onCreate(savedInstanceState);
  19.  
  20.     mContext = this;
  21.  
  22.     setContentView(R.layout.main);
  23.  
  24. }
  25.  
  26.  
  27.  
  28. @Override
  29.  
  30. public boolean onCreateOptionsMenu(Menu menu) {
  31.  
  32.     boolean result = super.onCreateOptionsMenu(menu);
  33.  
  34.     menu.add(0, 1, 0, "new");
  35.  
  36.     menu.add(0, 2, 0, "exit");
  37.  
  38.     return result;
  39.  
  40. }
  41.  
  42.  
  43.  
  44. @Override
  45.  
  46. public boolean onOptionsItemSelected(MenuItem item) {
  47.  
  48.     switch (item.getItemId()) {
  49.  
  50.     case 1:
  51.  
  52.         mGv = new MyView(this);
  53.  
  54.         mGsv = new GameScrollView(this);
  55.  
  56.         mGsv.addView(mGv);
  57.  
  58.         setContentView(mGsv);
  59.  
  60.         return true;
  61.  
  62.     case 2:
  63.  
  64.         finish();
  65.  
  66.         return true;
  67.  
  68.     }
  69.  
  70.     return false;
  71.  
  72. }
  73.  
  74.  
  75.  
  76. }
  77.  
  78.  
Parsed in 0.040 seconds, using GeSHi 1.0.8.4


When I run your code with the activity set up like this it fails...My main.xml just displays the name of the app...
pressing the back button now kills the activity....Any ideas? :?:
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Postby mangaluve » Mon May 25, 2009 7:55 am

Hm.. I don't have access to an Android emulator right now, but you mean that by using all my code, and your Activity, where the only difference is the two overriden methods for the menu, screws everything up?
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Top
Next

Return to View, Layout & Resource Problems

Who is online

Users browsing this forum: No registered users and 5 guests