How to make a canvas scroll

Put your problem here if it does not fit any of the other categories.

How to make a canvas scroll

Postby mpathare » Fri May 15, 2009 12:31 am

I am writing a solitaire app. I use a canvas to draw everything on the screen. Sometimes a pile of cards will get big and extend below the bottom of the screen. I would like to make the canvas scrollable so the user can access those cards.

Main Activity.
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. package com.maulinpathare.solitaire;
  3.  
  4.  
  5.  
  6. import android.app.Activity;
  7.  
  8. import android.content.Context;
  9.  
  10. import android.os.Bundle;
  11.  
  12. import android.view.Menu;
  13.  
  14. import android.view.MenuItem;
  15.  
  16.                
  17.  
  18. public class Solitaire extends Activity{
  19.  
  20.     /** Called when the activity is first created. */
  21.  
  22.         private Context mContext;
  23.  
  24.         private GameView mG;
  25.  
  26.        
  27.  
  28.     @Override
  29.  
  30.     public void onCreate(Bundle savedInstanceState) {
  31.  
  32.         super.onCreate(savedInstanceState);
  33.  
  34.         mContext = this;
  35.  
  36.         setContentView(R.layout.main);
  37.  
  38.     }
  39.  
  40.    
  41.  
  42.     @Override
  43.  
  44.     public boolean onCreateOptionsMenu(Menu menu) {
  45.  
  46.         boolean result = super.onCreateOptionsMenu(menu);
  47.  
  48.         menu.add(0, 1, 0, R.string.newGame);
  49.  
  50.         menu.add(0, 2, 0, R.string.exitGame);
  51.  
  52.         return result;
  53.  
  54.     }
  55.  
  56.    
  57.  
  58.     @Override
  59.  
  60.     public boolean onOptionsItemSelected(MenuItem item) {
  61.  
  62.         switch (item.getItemId()) {
  63.  
  64.         case 1:
  65.  
  66.                 mG = new GameView(this);
  67.  
  68.                 setContentView(mG);
  69.  
  70.             return true;
  71.  
  72.         case 2:
  73.  
  74.             finish();
  75.  
  76.             return true;
  77.  
  78.         }
  79.  
  80.         return false;
  81.  
  82.     }
  83.  
  84.    
  85.  
  86. }//end class
  87.  
  88.  
Parsed in 0.035 seconds, using GeSHi 1.0.8.4


GameView Class
This is where everything happens
I have removed most of the game logic...
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. package com.maulinpathare.solitaire;
  3.  
  4.  
  5.  
  6. import java.util.Stack;
  7.  
  8. import android.content.Context;
  9.  
  10. import android.graphics.Canvas;
  11.  
  12. import android.graphics.Color;
  13.  
  14. import android.graphics.Paint;
  15.  
  16. import android.graphics.Rect;
  17.  
  18. import android.view.MotionEvent;
  19.  
  20. import android.view.View;
  21.  
  22. import android.view.View.OnTouchListener;
  23.  
  24. import android.widget.ScrollView;
  25.  
  26.  
  27.  
  28. public class GameView extends ScrollView implements OnTouchListener{
  29.  
  30.         private Deck mD;
  31.  
  32.         private boolean mInit, mDone;
  33.  
  34.         private Stack<Card> mPile1, mPile2, mPile3, mPile4, mPile5, mPile6, mPile7,
  35.  
  36.                                                 mOpenPile, mEndPile1, mEndPile2, mEndPile3, mEndPile4, mTemp;
  37.  
  38.         private Canvas mCanvas;
  39.  
  40.         private int mPile;
  41.  
  42.         private boolean mPickUp, mVictory;
  43.  
  44.         private Card mCard;
  45.  
  46.         private final int mSpacing = 22;
  47.  
  48.         private Paint rectPaint, wonPaint1, wonPaint2;
  49.  
  50.        
  51.  
  52.         public GameView(Context context) {
  53.  
  54.         super(context);
  55.  
  56.                                 //initialize everything needed for the game
  57.  
  58.     }
  59.  
  60.        
  61.  
  62.     @Override
  63.  
  64.     protected void onDraw(Canvas canvas) {
  65.  
  66.         mCanvas = canvas;
  67.  
  68.         if(mInit){
  69.  
  70.                 initialize();
  71.  
  72.                 mInit = false;
  73.  
  74.         }
  75.  
  76.         //draw stuff...
  77.  
  78.  
  79.  
  80.     }//end onDraw
  81.  
  82.    
  83.  
  84.     public boolean onTouch(View v, MotionEvent event){
  85.  
  86.         int eventAction = event.getAction();
  87.  
  88.         int x = Math.round(event.getX());
  89.  
  90.         int y = Math.round(event.getY());
  91.  
  92.        
  93.  
  94.         switch(eventAction){
  95.  
  96.         case MotionEvent.ACTION_DOWN:
  97.  
  98.                                 //check if touch has happened on one of the card piles
  99.  
  100.                 break; //end case action_touch
  101.  
  102.                
  103.  
  104.         case MotionEvent.ACTION_MOVE:
  105.  
  106.                                 //if card touched move it
  107.  
  108.                 break; //end case action_move
  109.  
  110.                
  111.  
  112.         case MotionEvent.ACTION_UP:
  113.  
  114.                                 //check if legal move has been made
  115.  
  116.                 break; //end case action_up
  117.  
  118.                
  119.  
  120.         }//end switch(event)
  121.  
  122.  
  123.  
  124.         invalidate();
  125.  
  126.         return true;
  127.  
  128.     }//end onTouch
  129.  
  130. }
  131.  
  132.  
  133.  
  134.  
Parsed in 0.038 seconds, using GeSHi 1.0.8.4


Where and how should I implement screen scrolling? I would like the user to be able to slide their finger across the screen in the direction they want to scroll.
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Top

Postby mpathare » Mon May 18, 2009 5:29 pm

bump.
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Postby mangaluve » Mon May 18, 2009 6:53 pm

Well the ScrollView needs a Child which it can scroll. If you want to do it like this, one way would be to implement a simple custom View where you do all the drawing, and put that View inside a ScrollView. You could probably just move all the code to that View, but don't forget to override the onMeasure-method. This is called by the parent (the ScrollView) to determine the size of your View. Something like this would work:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  2.  
  3.         setMeasuredDimension(320, 500);
  4.  
  5. }
Parsed in 0.034 seconds, using GeSHi 1.0.8.4

if you know that your View always will have the size 320x500. This is okay since in your case, the View will always be inside of a scrollview, so you can set the size to pretty much anything.

Edit: I saw now that you don't always need to scroll. Then, of course, you have to change the onMeasure method to set the current dimensions. Also, when the dimensions of your view changes, you should probably call requestLayout().
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby mpathare » Mon May 18, 2009 7:44 pm

If I have a child view inside the ScrollView which view will get to handle the users touch? I have implemented the onTouch method in my view to process the moving of cards around the screen etc...

What will I need to do to have the ScrollView handle the scrolling gesture and the child view handle game moves?

Also, what other way can this be handled in? Is there a way I can make a canvas inside a view scrollable?

Thanks for your help.
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Postby mangaluve » Mon May 18, 2009 8:31 pm

Well the ScrollView will dispatch the touch-event to the View inside of it.. you don't have to worry about that, just override the onTouch method for your custom view as you're used to. See, all touchevents are passed to the ScrollView. The ScrollView then dispatches them to the child (which may in turn dispatch it to it's child if it has any). Before the ScrollView passes the touchevents on to it's children, it will look at them and determine whether or not it should scroll. So it really takes care of everything: when you make a scroll movement, it will scroll, and when you make something else, it will pass it on to the child.

I don't really know if there are any other ways, I mean you could handle scrolling by yourself inside the view (so if the user presses the screen and moves his finger, you scroll), but there's no point in inventing the wheel again I guess. Perhaps you don't have to draw the cards or whatever you're drawing by yourself, perhaps you can use ImageViews and stuff. For instance, I guess you could use an AbsoluteLayout and use ImageViews. Haven't played around with it though, I think the way I suggested will work... Try it, and if you're not satisfied, we'll figure something out :)

So, just keep track of the size of your View at all time. Use the current size in onMeasure, to make sure the ScrollView knows your size. When you change the size, call requestLayout, that will force the ScrollView to ask your View about it's dimensions again.
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby mpathare » Tue May 19, 2009 2:14 am

Thanks Mangaluve!
That worked great. I added my GameView to a ScrollView container. The scroll view scrolls like expected, but the touch events dont get routed to the child view correctly...well, not all of them anyway. Is there a way that I can have the child view eat all the touch calls instead of the scroll view? and then if the gesture wasn't a legal game move, let the scroll view handle the event?
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Top

Postby mangaluve » Wed May 20, 2009 8:28 am

Hm I think the ScrollView "hijacks" the motionevent before it is passed to the child. You could modify the scrollview I guess, but that'd take some work. Why aren't you satisfied with the way it behaves, since it should be similar to the general scroll behaviour in android?

It wouldn't be very difficult to write your own "scrollview" either, one that just is working for your game.. I've never really done anything with scrollviews so I dont really know :)
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby mpathare » Wed May 20, 2009 2:27 pm

Well the scrolling works fine. But like you said, the ScrollView seems to handle touch events that should be handled by my GameView. I am able to select cards and move them a small distance on the screen, but then it seems like the events get routed to the ScrollView and I cant interact with the card anymore.

Maybe there is some way to only have the parent ScrollView handle some events and then send the rest to the child.
mpathare
Developer
Developer
 
Posts: 26
Joined: Sat Apr 11, 2009 10:43 pm

Top

Return to Other Coding-Problems

Who is online

Users browsing this forum: Google [Bot] and 11 guests