Archive for December, 2010

Moving Views in Android – Part 1

I am building an Android app where I want to have a lot of views on the screen and allow the user to move them around by touching and dragging them. I’m not there yet, but I have made some progress. So far, I have learned enough about Android touch events to get a view to move when it is touched. I’ve also learned how to hide and show views.

I have been working with ImageView objects. The app looks like Figure 1 when it starts. After a few touches (clicks in the emulator), the image views’ positions have been displaced relative to their original position. That is shown in Figure 2.

Screenshot from HideAndMoveImages in HideAndMove after a few clicks

Figures 1 – 2

How It Works

In the Android developer website, I had found an article about touch events and moving objects: Making Sense of Multitouch. It showed how to build a simple custom view that tracks touch events and moves an icon within the view. The key bit of code was in its override of the onDraw method. The method translate the position of the canvas by an x-y amount before it draws the icon that is being moved about the screen.

public void onDraw (Canvas canvas) {
   super.onDraw (canvas);
   canvas.save ();
   canvas.translate (mPosX, mPosY); 
   mIcon.draw (canvas);
   canvas.restore ();
 }

I wanted to work with ImageView objects so I did a similar thing in a custom subclass of ImageView. MyImageView has an onDraw method that looks like the following:

public void onDraw(Canvas canvas) {
  canvas.translate(mPosX, mPosY);
  super.onDraw(canvas);
}

An ImageView object already knows how to draw itself so all I had to do was translate the canvas position and call the superclass method. The instance variables mPosX and mPosY are used to keep track of the x and y displacements of the view from its original position.

I set up the HideAndMove activity so it handles any touch events on the ImageViews. It was actually a pretty simple handler. All it did was change the position of the view a little in the x and y position. It did this using the changePos method in MyImageView.

public boolean onTouch (View v, MotionEvent ev) {
  MyImageView iv = (MyImageView) v;
  float dx = 10f;
  float dy = -20f;
  iv.changePos (dx, dy);
  return false;
 }

In MyImageView there is a changePos method that takes the delta x and y values and changes the position of the view. Its code is shown below. It sets the mPosX and mPosY values and calls the invalidate method for the view. That last call is what makes the view redraw itself, and as we have already seen above, the onDraw method translates the canvas by the mPosX and mPosY values before drawing its image.

public void changePos (float dx, float dy){
  mPosX += dx;
  mPosY += dy;
  this.invalidate ();
}

That’s all I have so far for doing drag and drop on views.

Hiding images turns out to be very easy. Check the onClick handler defined in the HideAndMove activity. It has a line that changes the visibility of the first image view. I had expected this to be more difficult because I had done a few web searches and found lots of cases where Android developers were having trouble hiding and showing views in their apps.

public void onClick(View v) {
  if (mV1 != null)
    mV1.setVisibility (View.INVISIBLE); // View.GONE hides and removes view from the layout.
}

I feel like I’ve made good progress. As I’ve said in my earlier posts in this blog, I don’t know if I’ve found the absolute best way to do things, and with this particular topic, I have so much more to learn about views. If anyone has suggestions or tips, please post a comment.

For Part 2 of this project, I am going to work on the following: (1) adding a background image on which the images move; (2) getting the images to follow the touch point as it moves; (3) and having the images not be clipped by the rectangle in which they are placed.

Source Code

Source code for this example is available in my Google Docs. Download the HideAndMove zip file.

If you find that the app does not build in Eclipse, be sure to do a clean build by using the “Clean” item on the Project menu.

My Introduction To Android Activities

One good way to get started with Android is to find others also trying to learn. Here in the Triangle area of North Carolina, there is a Meetup group for Android developers. It is called Tridroid. It’s been a great source of Android tips and a good way to meet other developers.

There was a very good Tridroid meeting earlier this month. Luke Meyer walked us through a tutorial about the Android activity lifecycle. I picked up many really useful tips about getting starting in the Android development world. It’s the sort of thing you don’t get except by watching someone else type and think through whatever comes up on the screen.

I now have a basic understanding of Activity objects. That includes:
- how activities and views connect;
- what the activity lifecycle is;
- what states an activity can be in;
- how one activity can start another.

I took what we worked on in the group and fleshed it out a bit. I ended up with something that looks like Figure 1 and Figure 2.

Figures 1-2:

There’s a text box and two buttons. The first button starts a new activity that runs and takes the full screen. The second button starts a new activity that displays as a dialog box. The second activity is shown in Figure 2

Looking at the manifest file, you will see that there are three different activity definitions. Two are ordinary: Main and Sub1. DialogActivity is different. Note the theme attribute value “Theme.Dialog”. That says that it should start as a dialog activity.

<activity android:name=".Main" android:label="@string/app_name">            
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />            
 </intent-filter>        
</activity>        
<activity android:name=".Sub1" android:label="Sub1 Activity"></activity>        
<activity android:name=".DialogActivity" android:label="Read This"
              android:theme="@android:style/Theme.Dialog">        
</activity>

As shown in Figure 2, the DialogActivity overlays the previous activity.

The next figure shows what the Main onCreate method looks like. After setting its content view, it locates the two buttons with findViewById and defines actions for the button clicks.  The two actions start activities in exactly the same way.  You see that it does not take much to start an activity, just a call to startActivity with the Activity class you want to run. As mentioned above, it is the theme attribute that makes the second one run as a dialog.

Figure 3: onCreate method of Main (click for larger image)

If you are new to Android, you will want to spend a bit of time understanding the call “setContentView (R.layout.main)”. There is quite a bit of Android magic there. Basically what it is saying is set the main view for this activity to a view defined by the main.xml file in the resources layout folder (/res/layout). You can define view objects in java code or in xml files. My sense so far is that most people find it more convenient to define the views in xml files. If you look in the resources folder of this app, you see three layout files. The main.xml file lays out the view with an EditText and two Button views.

Note the last line in the onCreate method. It is a call to a trace function. That is the thing that makes the activity lifecycle come alive. In each of the activity’s On methods (onCreate, onStart, onResume, etc.) there is a call to a trace method. The method makes an entry in a debugging log and also throws something up on the screen so you can see the transition.

Figure 4: Toast message

Those little messages help a lot. You can see what happens when you start another activity. You can see what happens when you stop an app. And for a little surprise, see what happens when you change the orientation of the device — the activity gets completely shut down and restarted. Knowing that should save a lot of time later in your real app. (By the way, to try that in the emulator, use CTRL-F12 and CTRL-F11 keys.)

The trace methods look like this:

public void toast (String msg) {  Toast.makeText (getApplicationContext(), msg, Toast.LENGTH_SHORT).show (); }
private void trace (String msg)
{
 Log.d("Demo", msg);
 toast (msg);
}

The Log.d call puts things into the Logcat part of the DDMS window. The toast call displays a short-lived message on the device screen. Both are those help a lot in debugging. If like me, you still use System.out.println, you should know that these messages end up in the Logcat area too.

Figure 5: Logcat within DDMS (click to see larger image)

Source Code

Source code is available in Google Docs. It is a zip of an Eclipse project. It was tested with version 2.2 of Android in the Android Emulator. My Eclipse version is 3.5.2.

If you find that the app does not build in Eclipse, be sure to do a clean build by using the “Clean” item on the Project menu.

References and Acknowledgements

If you have not already done so, read the Android Fundamentals article.

Thanks to Luke Meyer for a great code-and-tell session. Check out his blog at http://sosiouxme.wordpress.com/.



Follow

Get every new post delivered to your Inbox.

Join 73 other followers