Saturday, 29 December 2012

Android - horizontal flow layout

If you use a LinearLayout which has horizontal orientation and limited width, you'll notice that the child views you add to this LinearLayout are placed one after another left-to-right up to and beyond the width of the LinearLayout. The child views will not wrap to a new line and there is no native layout to do this. So! I've wrote one, as below. It's an adaptation of a view I found on Nishant Nair's Blog here:
https://nishantvnair.wordpress.com/2010/09/28/flowlayout-in-android

UPDATE: For the latest version of the HorizontalFlowLayout class, see this repository:
https://bitbucket.org/adilson05uk/android-utils
 
 
/**
 * Custom view which extends {@link RelativeLayout}
 * and which places its children horizontally,
 * flowing over to a new line whenever it runs out of width.
 */
public class HorizontalFlowLayout extends RelativeLayout {

  /**
   * Constructor to use when creating View from code.
   */
  public HorizontalFlowLayout(Context context) {
    super(context);
  }

  /**
   * Constructor that is called when inflating View from XML.
   */
  public HorizontalFlowLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  /**
   * Perform inflation from XML and apply a class-specific base style.
   */
  public HorizontalFlowLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // need to call super.onMeasure(...) otherwise get some funny behaviour
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    final int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    // increment the x position as we progress through a line
    int xpos = getPaddingLeft();
    // increment the y position as we progress through the lines
    int ypos = getPaddingTop();
    // the height of the current line
    int line_height = 0;

    // go through children
    // to work out the height required for this view

    // call to measure size of children not needed I think?!
    // getting child's measured height/width seems to work okay without it
    //measureChildren(widthMeasureSpec, heightMeasureSpec);

    View child;
    MarginLayoutParams childMarginLayoutParams;
    int childWidth, childHeight, childMarginLeft, childMarginRight, childMarginTop, childMarginBottom;

    for (int i = 0; i < getChildCount(); i++) {
      child = getChildAt(i);

      if (child.getVisibility() != GONE) {
        childWidth = child.getMeasuredWidth();
        childHeight = child.getMeasuredHeight();

        if (child.getLayoutParams() != null
            && child.getLayoutParams() instanceof MarginLayoutParams) {
          childMarginLayoutParams = (MarginLayoutParams)child.getLayoutParams();

          childMarginLeft = childMarginLayoutParams.leftMargin;
          childMarginRight = childMarginLayoutParams.rightMargin;
          childMarginTop = childMarginLayoutParams.topMargin;
          childMarginBottom = childMarginLayoutParams.bottomMargin;
        }
        else {
          childMarginLeft = 0;
          childMarginRight = 0;
          childMarginTop = 0;
          childMarginBottom = 0;
        }

        if (xpos + childMarginLeft + childWidth + childMarginRight + getPaddingRight() > width) {
          // this child will need to go on a new line

          xpos = getPaddingLeft();
          ypos += line_height;

          line_height = childMarginTop + childHeight + childMarginBottom;
        }
        else {
          // enough space for this child on the current line
          line_height = Math.max(
              line_height,
              childMarginTop + childHeight + childMarginBottom);
        }

        xpos += childMarginLeft + childWidth + childMarginRight;
      }
    }

    ypos += line_height + getPaddingBottom();

    if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
      // set height as measured since there's no height restrictions
      height = ypos;
    }
    else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST
        && ypos < height) {
      // set height as measured since it's less than the maximum allowed
      height = ypos;
    }

    setMeasuredDimension(width, height);
  }

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    // increment the x position as we progress through a line
    int xpos = getPaddingLeft();
    // increment the y position as we progress through the lines
    int ypos = getPaddingTop();
    // the height of the current line
    int line_height = 0;

    View child;
    MarginLayoutParams childMarginLayoutParams;
    int childWidth, childHeight, childMarginLeft, childMarginRight, childMarginTop, childMarginBottom;

    for (int i = 0; i < getChildCount(); i++) {
      child = getChildAt(i);

      if (child.getVisibility() != GONE) {
        childWidth = child.getMeasuredWidth();
        childHeight = child.getMeasuredHeight();

        if (child.getLayoutParams() != null
            && child.getLayoutParams() instanceof MarginLayoutParams) {
          childMarginLayoutParams = (MarginLayoutParams)child.getLayoutParams();

          childMarginLeft = childMarginLayoutParams.leftMargin;
          childMarginRight = childMarginLayoutParams.rightMargin;
          childMarginTop = childMarginLayoutParams.topMargin;
          childMarginBottom = childMarginLayoutParams.bottomMargin;
        }
        else {
          childMarginLeft = 0;
          childMarginRight = 0;
          childMarginTop = 0;
          childMarginBottom = 0;
        }

        if (xpos + childMarginLeft + childWidth + childMarginRight + getPaddingRight() > r - l) {
          // this child will need to go on a new line

          xpos = getPaddingLeft();
          ypos += line_height;

          line_height = childHeight + childMarginTop + childMarginBottom;
        }
        else {
          // enough space for this child on the current line
          line_height = Math.max(
              line_height,
              childMarginTop + childHeight + childMarginBottom);
        }

        child.layout(
            xpos + childMarginLeft,
            ypos + childMarginTop,
            xpos + childMarginLeft + childWidth,
            ypos + childMarginTop + childHeight);

        xpos += childMarginLeft + childWidth + childMarginRight;
      }
    }
  }
}
 

Friday, 28 December 2012

Android: DialogFragment and screen rotation

If you're setting up your dialogs using the DialogFragment class, you've probably noticed that a dialog which is shown becomes hidden when the screen orientation is changed. Not great! Spending a fair bit of time looking into this - browsing online and Stack Overflow in particular - you'll find lots of discussion and suggestions but it becomes pretty clear very soon that nobody really quite knows what to do about it!! Below are a couple of things I tried:

(1) Included an empty (i.e. no arguments), public constructor in my DialogFragment class which simply calls the default, empty super constructor.

(2) Tried different combinations of setRetainInstance(true) and setRetainInstance(false) with getDialog().setDismissMessage(null) and getDialog().setOnDismissListener(null) in my DialogFragment.onCreate(Bundle savedInstanceState) and DialogFragment.onDestroyView() methods respectively.

In the end I gave up and am now allowing my dialogs to be dismissed on screen rotation by calling setRetainInstance(true) when my dialog is created (i.e. in my DialogFragment.onCreate(Bundle savedInstanceState) method). This causes the dialog to be dismissed proper on screen orientation change instead of simply showing as invisible whilst blocking the screen. Not ideal and it would have been great to have dialogs persist beyond screen rotations but better not to spend any more time on this shooting in the dark!

Friday, 7 December 2012

Talk summary: So you have an app idea?, by Dave Addey

Here's a summary of a good talk I listened to last week by Dave Addey entitled "So you have an app idea?". It's the first talk I've heard in a long time which was worthy of note-taking. You'll find in the list below some points the speaker mentions for determining the potential of an app idea.
  1. Universal appeal: Is it niche, i.e. relevant only to a particular interest group and therefore not going to make much money?
  2. International appeal: Is it as relevant in China as it is in the UK?
  3. Lasting appeal: Will it still be relevant a year(+) from now for users to install and use?
  4. Ongoing use: Is it a use once or twice and throw away app or will it be used over a lengthy, potentially indefinite time-frame?
  5. Personal interest: Does it scratch my own itch? Do I want or need this myself?
  6. The hook: Is it something that has not been done before? Does it give people a reason to write about it, to be excited about it, and to show it off to their friends?
  7. Dead time principle: Can it be dived into and out of for short spells, i.e. whenever the user has a moment free to use it?
A video recording of the talk used to be up on Be Square here but it looks like that's been taken down since. Good news though: I managed to find an audio recording of the talk on Sound Cloud here.

Android: show a View as pressed without using a Selector resource

It's possible to show a View as pressed or unpressed (when in the pressed or default state respectively) by having two versions of the View's background image, putting the two images in a selector drawable, and then assigning the selector to be the background of your View. However, sometimes you might not have two versions of the image or you might not want to bloat the size of your apk by having two(+) versions of each image. In such a situation, here's an alternative way of showing a View as pressed (or not), i.e. show a black-ish, transparent overlay over the View.

The first step is to define a black, transparent colour in your res/values/colors.xml file as follows:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <color name="black_transparent">#70000000</color>
</resources>

The second step is to create a res/drawable/selector_foreground_black_transparent.xml file defined as follows:

<?xml version="1.0" encoding="utf-8"?>
<selector
  xmlns:android="http://schemas.android.com/apk/res/android" >
  <item
    android:state_pressed="true"
    android:drawable="@color/black_transparent" />
  <item
    android:drawable="@android:color/transparent" />
</selector>

The third and final step is two wrap your View - the one you want to be displayed as pressed or not - in a FrameLayout something as follows:

<FrameLayout
  android:id="@+id/layout_my_view"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:foreground="@drawable/selector_foreground_black_transparent"
  android:foregroundGravity="fill" >
  <View
    android:id="@+id/my_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/my_view_bg" />
</FrameLayout>

That's it. The only other thing to keep in mind is to put a click listener on your FrameLayout instead of putting it on your View.

Tuesday, 27 November 2012

Android: How to set the height and width of a DialogFragment

If you've played around with creating dialogs using the DialogFragment class, you've probably noticed that the layout_width and layout_height parameters that you assign in your DialogFragment's xml layout file are ignored (disrespected!) and the operating system assigns height and width to your DialogFragment however it so wishes!

Because of this problem and because it is highly recommended to create dialogs with the DialogFragment class, what I do now is specify the layout_width and layout_height parameters in my DialogFragment's xml layout file as match_parent. And then, more importantly, I specify the dialog's height and width in my DialogFragment.onStart() method as follows:
 
@Override
public void onStart() {
  super.onStart();

  // safety check
  if (getDialog() == null) {
    return;
  }

  int dialogWidth = ... // specify a value here
  int dialogHeight = ... // specify a value here

  getDialog().getWindow().setLayout(dialogWidth, dialogHeight);

  // ... other stuff you want to do in your onStart() method
}
 

Android: DialogFragment enter and exit animations

Adding enter and exit animations to your DialogFragment's dialog is a three-step process:
  1. define the enter and exit animations;
  2. add your animations to a style;
  3. set the style as your dialog's "window animations".
That's the gist of it. In greater detail, and assuming you want fade in and fade out animations, this is what you need to do.

First, define the animations. Add a fade_in_dialog.xml file to your res/anim folder which has the following xml code...

<?xml version="1.0" encoding="utf-8"?>
<alpha
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:interpolator="@android:anim/accelerate_interpolator"
  android:fromAlpha="0.0"
  android:toAlpha="1.0"
  android:duration="400" />

And a fade_out_dialog.xml file to your res/anim folder which has the following xml code...

<?xml version="1.0" encoding="utf-8"?>
<alpha
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:interpolator="@android:anim/decelerate_interpolator"
  android:fromAlpha="1.0"
  android:toAlpha="0.0"
  android:duration="400" />

Second, add a style to your res/styles.xml file defined as follows:

<style
  name="dialog_animation_fade" >
  <item name="android:windowEnterAnimation">@anim/fade_in_dialog</item>
  <item name="android:windowExitAnimation">@anim/fade_out_dialog</item>
</style>

Third (and final!), add the following code to your DialogFragment.onStart() method:

@Override
public void onStart() {
  super.onStart();

  // safety check
  if (getDialog() == null) {
    return;
  }

  // set the animations to use on showing and hiding the dialog
  getDialog().getWindow().setWindowAnimations(
      R.style.dialog_animation_fade);
  // alternative way of doing it
  //getDialog().getWindow().getAttributes().
  //    windowAnimations = R.style.dialog_animation_fade;

  // ... other stuff you want to do in your onStart() method
}

Done! Your dialogs should now fade in and fade out when shown and dismissed respectively.

Monday, 19 November 2012

Android Debug Bridge: detect Google Nexus 7 tablet

Spent an awful, awful, awful amount of time this morning trying to hook up a Google Nexus 7 tablet to Android Debug Bridge on my computer.

These are the steps I took which you'd think would suffice:
  • Go to Settings in the tablet,
  • Make Developer Options visible by clicking About Tablet seven times,
  • Enable USB Debugging in Developer Options,
  • Select the app to debug in the Select Debug App option of Developer Options,
  • Install the driver onto my computer as per the instructions here: Using Hardware Devices. I tried the driver in the [Android SDK]\extras\google folder of my computer as well as the one available for download from ASUS.
However, on plugging my tablet into the USB port of my computer and entering the command adb devices in the command prompt, the device was still not listed, i.e. not detected by Android Debug Bridge.

After much wild guessing and frantic searching on Stack Overflow, I finally found the solution, as follows:
  • Go to Settings,
  • then Storage,
  • then USB Computer Connection,
  • then select Camera (PTP) instead of Media Device (MTP).
That should do it!

Monday, 22 October 2012

Android - how to add padding or a border to a Bitmap

Here's a neat (I'd like to think) method (which you can tinker with) for adding padding or a border to a Bitmap:
 
 
/** Creates and returns a new bitmap which is the same as the provided bitmap
 * but with horizontal or vertical padding (if necessary)
 * either side of the original bitmap
 * so that the resulting bitmap is a square.
 * @param bitmap is the bitmap to pad.
 * @return the padded bitmap.*/
public static Bitmap padBitmap(Bitmap bitmap)
{
  int paddingX;
  int paddingY;

  if (bitmap.getWidth() == bitmap.getHeight())
  {
    paddingX = 0;
    paddingY = 0;
  }
  else if (bitmap.getWidth() > bitmap.getHeight())
  {
    paddingX = 0;
    paddingY = bitmap.getWidth() - bitmap.getHeight();
  }
  else
  {
    paddingX = bitmap.getHeight() - bitmap.getWidth();
    paddingY = 0;
  }

  Bitmap paddedBitmap = Bitmap.createBitmap(
      bitmap.getWidth() + paddingX,
      bitmap.getHeight() + paddingY,
      Bitmap.Config.ARGB_8888);

  Canvas canvas = new Canvas(paddedBitmap);
  canvas.drawARGB(0xFF, 0xFF, 0xFF, 0xFF); // this represents white color
  canvas.drawBitmap(
      bitmap,
      paddingX / 2,
      paddingY / 2,
      new Paint(Paint.FILTER_BITMAP_FLAG));

  return paddedBitmap;
}
 

Sunday, 21 October 2012

Advice on preparing images for an Android app

Here's some things to keep in mind when preparing (or advising or delegating to someone to prepare) graphics/images for an Android app:
  • Images file names must consist of lower case letters, numbers and the underscore character only, i.e. [ a-z | 0-9 | _ | . ]. Upper case characters not allowed. Also, all images are to be contained in a single drawable folder so better to give images meaningful names to minimise renaming etc later, e.g. myactivity_header_black.png or button_blue_pressed.png.
  • For all images which are to act as buttons, have two states: a normal state and a pressed state. Likewise, for all images which are to act as text input boxes, have two states: a normal state and a focused/selected state.
  • Device screen sizes come in all sorts. The easiest thing I find is to design for a 960*640 screen and to bear in mind when designing that some devices will be slightly taller, slighter wider etc. Also, chop screen designs down to their smallest image components so that click handlers etc can be placed on the images themselves rather than on certain co-ordinates of the screen (remember: the position of items will vary from screen to screen).
  • Related to the previous point: bear in mind that images which are to span the entire height or width of the screen (backgrounds, headers, footers etc) will get stretched and shrunk slightly depending on the screen size of the handset.
  • Avoid putting text in your images (buttons etc) except where necessary (e.g. where a special font or look of the text is required). Add text in code instead. As well as allowing images to be re-used (and thus reducing the size of the app), this also makes localisation easier.
  • Avoid padding graphics with whitespace (this can be done in code) except where necessary for shadows etc.

Writing code in Blogger

Here's a technique taken from Mijalko's Blog for writing computer code in Blogger, i.e. surround your code with pre and code tags as follows:

<pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;">
<code>
This is code.
</code>
</pre>


The output will look like this:

This is code.

Done! :)

Saturday, 20 October 2012

Android - how to scale a bitmap and retain the original's quality

If you've tried the Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) method you'll have experienced the bad (blocky) quality of the Bitmap that it produces. Here's an alternative method I found (didn't compose myself) for scaling Bitmaps and retaining the quality of the original:

/**
 * Scales the provided bitmap to have the height and width provided.
 * (Alternative method for scaling bitmaps
 * since Bitmap.createScaledBitmap(...) produces bad (blocky) quality bitmaps.)
 * 
 * @param bitmap is the bitmap to scale.
 * @param newWidth is the desired width of the scaled bitmap.
 * @param newHeight is the desired height of the scaled bitmap.
 * @return the scaled bitmap.
 */
 public static Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight) {
  Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Config.ARGB_8888);

  float scaleX = newWidth / (float) bitmap.getWidth();
  float scaleY = newHeight / (float) bitmap.getHeight();
  float pivotX = 0;
  float pivotY = 0;

  Matrix scaleMatrix = new Matrix();
  scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY);

  Canvas canvas = new Canvas(scaledBitmap);
  canvas.setMatrix(scaleMatrix);
  canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG));

  return scaledBitmap;
}

Friday, 27 July 2012

Android - how to create a sliding View

Creating a View which slides back and forth between an original position and a displacement position is easy post- Ice Cream Sandwich (by means of the new ObjectAnimator class and setTranslationX(float translationX) etc methods). Doing this pre- Ice Cream Sandwich is not so easy. Below is a class I created which you can use as a basis for creating a View which toggles (slides) between an original position and a displacement position. The way it works is to extend FrameLayout (could be a different View depending on your need), to start the translate right/left animations when the toggleSlide() method is called, and to listen for the end of the animations in order to relocate itself right/left as appropriate, as follows:

public class SlidingFrameLayout extends FrameLayout
{
  private final int durationMilliseconds = 1000;
  private final int displacementPixels = 200;

  private boolean isInOriginalPosition = true;
  private boolean isSliding = false;

  public SlidingFrameLayout(Context context)
  {
    super(context);
  }

  public SlidingFrameLayout(Context context, AttributeSet attrs, int defStyle)
  {
    super(context, attrs);
  }

  public SlidingFrameLayout(Context context, AttributeSet attrs, int defStyle)
  {
    super(context, attrs, defStyle);
  }

  @Override
  protected void onAnimationEnd()
  {
    super.onAnimationEnd();

    if (isInOriginalPosition)
      offsetLeftAndRight(displacementPixels);
    else
      offsetLeftAndRight(-displacementPixels);

    isSliding = false;
    isInOriginalPosition = !isInOriginalPosition;
  }

  @Override
  protected void onLayout(
      boolean changed,
      int left,
      int top,
      int right,
      int bottom)
  {
    super.onLayout(changed, left, top, right, bottom);

    // need this since otherwise this View jumps back to its original position
    // ignoring its displacement
    // when (re-)doing layout, e.g. when a fragment transaction is committed
    if (changed && !isInOriginalPosition)
      offsetLeftAndRight(displacementPixels);
  }

  public void toggleSlide()
  {
    // check whether frame layout is already sliding
    if (isSliding)
      return; // ignore request to slide

    if (isInOriginalPosition)
      startAnimation(new SlideRightAnimation());
    else
      startAnimation(new SlideLeftAnimation());

    isSliding = true;
  }

  private class SlideRightAnimation extends TranslateAnimation
  {
    public SlideRightAnimation()
    {
      super(
        Animation.ABSOLUTE, 0,
        Animation.ABSOLUTE, displacementPixels,
        Animation.ABSOLUTE, 0,
        Animation.ABSOLUTE, 0);

      setDuration(durationMilliseconds);
      setFillAfter(false);
    }
  }

  private class SlideLeftAnimation extends TranslateAnimation
  {
    public SlideLeftAnimation()
    {
      super(
        Animation.ABSOLUTE, 0,
        Animation.ABSOLUTE, -displacementPixels,
        Animation.ABSOLUTE, 0,
        Animation.ABSOLUTE, 0);

      setDuration(durationMilliseconds);
      setFillAfter(false);
    }
  }
}

Tuesday, 24 July 2012

Android: Posting a Facebook question with options

Posting a question which has no associated options is easy to figure out from the Facebook documentation. Posting a question which does have associated options I struggled to find a single example for and figured out by pure luck, a shot in the dark! Solution below:

Bundle params = new Bundle();
params.putString("questions", "This is a question.");
params.putString("options", "[\"Option 1\", \"Option 2\"]");

new AsyncFacebookRunner(myFacebookObject)
    .request("me/questions", params, "POST" myRequestListener);

Tuesday, 17 July 2012

How to Bulk-Crop whitespace from images

Found a good tool today - XnView by Pierre e Gougelet - for bulk-, auto- cropping of whitespace from a set of images. To do this with XnView is as simple as the following steps:

  • Select the files to be cropped;
  • Go to Tools > Batch Processing;
  • On the first tab of the Batch Processing window (the General tab) set the destination directory (if you don't want to have your files overwritten) and the output format.
  • On the second tab (the Transformations tab) select the Auto Crop feature from the list of available Transformations and click Add to add it to the list of the active transformations. On the Parameters panel at the bottom, choose your desired background colour.
  • Press the Go button and check your destination folder see that everything went okay.
Steps above adapted from John Thomas' answer found in the following thread:

Thursday, 31 May 2012

Android: creating a Drawable or a Bitmap from a web url

Here are a couple of methods for creating a Drawable or a Bitmap from a web url:

/** Returns a Drawable object containing the image located at 'imageWebAddress' if successful, and null otherwise.
 * (Pre: 'imageWebAddress' is non-null and non-empty;
 * method should not be called from the main/ui thread.)*/
public static Drawable createDrawableFromUrl(String imageWebAddress)
{
  Drawable drawable = null;

  try
  {
    InputStream inputStream = new URL(imageWebAddress).openStream();
    drawable = Drawable.createFromStream(inputStream, null);
    inputStream.close();
  }
  catch (MalformedURLException ex) { }
  catch (IOException ex) { }

  return drawable;
}

/** Returns a Bitmap object containing the image located at 'imageWebAddress'
 * if successful, and null otherwise.
 * (Pre: 'imageWebAddress' is non-null and non-empty;
 * method should not be called from the main/ui thread.)*/
public static Bitmap createBitmapFromUrl(String imageWebAddress)
{
  Bitmap bitmap = null;

  try
  {
    InputStream inputStream = new URL(imageWebAddress).openStream();
    bitmap = BitmapFactory.decodeStream(inputStream);
    inputStream.close();
  }
  catch (MalformedURLException ex) { }
  catch (IOException ex) { }

  return bitmap;
}

Friday, 27 January 2012

Android: getting text to roll (marquee animate) in TextView

Set the following TextView properties in your xml layout file…

<TextView
 …
 android:id="@+id/myTextView"
 android:singleLine="true"
 android:ellipsize="marquee"
 android:marqueeRepeatLimit="marquee_forever"
 android:focusable="true"
 android:focusableInTouchMode="true"
 … />

… and now whenever the width of the text in the TextView is longer than the width of the TextView itself, the text will roll right to left along the TextView repeatedly. The number of times the animation repeats is determined by the integer value you set marqueeRepeatLimit to.

Note that sometimes the above is not sufficient and you need to make the following call in your code:
myTextView.setSelected(true);

Done!

Thursday, 26 January 2012

Android: using ViewSwitcher with in and out animations

In your xml layout file, you'll want something like the followng…

<ViewSwitcher
 android:id="@+id/viewSwitcher"
 android:inAnimation="@android:anim/slide_in_left"
 android:outAnimation="@android:anim/slide_out_right"
 … >
<View
 android:id="@+id/myFirstView"
 … />
<View
 android:id="@+id/mySecondView"
 … />

… This defines a ViewSwitcher which slides the next View to be shown in from the left and slides the current View out to the right.

In your code then where this layout file is referenced, you can initialise your Views as follows...

ViewSwitcher viewSwitcher =
 (ViewSwitcher)findViewById(R.id.viewSwitcher);
View myFirstView = findViewById(R.id.myFirstView);
View mySecondView = findViewById(R.id.mySecondView);

… And define some helper methods like the following to toggle between the two Views…

void showFirstView()
{
 if (viewSwitcher.getCurrentView() != myFirstView)
  viewSwitcher.showPrevious();
}

void showSecondView()
{
 if (viewSwitcher.getCurrentView() != mySecondView)
  viewSwitcher.showNext();
}

Done! And I guess the above applies equal well for ViewFlipper too.

Other animations are available too like fading in and fading out. Check out the following reference:
http://developer.android.com/reference/android/R.anim.html