1

I have a main layout in which I'd like to sequentially display / hide various custom layouts according to timers and user input.

In my example, I'd like the following timeline:

  1. show an initial layout, created by the class MainStart. The user will click on the button when they're ready to start.

  2. after the user clicks, we'll run a countdown timer, displaying the countdown to the screen. This is done by MainCountdown.

  3. once the countdown is complete, MainLast is displayed. It has a button allowing the user to click "Again?" when they want to start over.

  4. if the user clicks "Again?" then go to step 1.

According to this question, I may have to use removeView() and addView() to achieve what I want.

I pushed to GitHub a trimmed down version of what I want to do: Hide and Show Layouts so you can see everything, but the problem seems to boil down to myView still being visible after this:

myView = inflate(mContext, R.layout.main_start, _view_group);
myView.setVisibility(View.GONE);

direct link to code on GitHub

direct link to related layout

Can I make a small change to my code/layouts to make the views hide/appear the way I want?

Am I completely Doing It Wrong?

Community
  • 1
  • 1
Thunder Rabbit
  • 5,405
  • 8
  • 44
  • 82
  • 1
    The code appears to be going about some things the wrong way, but I'm not sure that I'm even following your intent yet. Can you describe in words what you want to accomplish? More than just "display/hide layouts" .. I mean describe maybe a timeline of what you expect to occur. Have you looked at [ViewFlipper](http://developer.android.com/reference/android/widget/ViewFlipper.html)? – Joe Jun 14 '11 at 03:10
  • @Joe, thanks for suggesting that; I've added my English description for what I'm trying to do. – Thunder Rabbit Jun 14 '11 at 03:18
  • Also, thanks for reminding me about ViewFlipper, but in my real app, the views need to be displayed according to user clicks, not in a specific order. On brief glance at that page, I don't see a way to "displayView(index)" – Thunder Rabbit Jun 14 '11 at 03:22
  • `setDisplayedChild(index)` would do that. – Joe Jun 14 '11 at 03:35

1 Answers1

1

From your 1-4 steps, it sounds like a custom View might be overkill for this, but if for whatever reason, you require that it be a custom View, it can still be done pretty easily... And it can be done with a ViewFlipper (or other ViewAnimator), or you can simply have 3 sibling children, and set visibility of each as needed. A bird's eye view would be something like...

<ViewSwitcher
    android:layout_height="wrap_content"
    android:layout_width="match_parent">

    <Button
        android:id="@android:id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Go" />

    <TextView
        android:id="@android:id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:id="@android:id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Again" />

</ViewSwitcher>
  1. startCountdown(): setDisplayedChild(1) -- this is the TextView. Also start the countdown: this can be with a Timer object, or using View#postDelayed().

  2. onCountdownComplete(): setDisplayedChild(2) -- this shows the end "Again?" button.

  3. onClick of button2: setDisplayedChild(0)

The countdown can be done with postDelayed() and a Runnable object to decrement the counter, or possibly more performant: use sendEmptyMessageDelayed(). When that handler message is received, decrement the internal counter, and update the TextView.

Edit Another option for the countdown is CountDownTimer -- similar concept, but has more of a "callback" feel to it. Your tick interval would be 1000, and millisInFuture would be 1000 * <numberOfSeconds>. In the onTick() method, update the TextView with millisUntilFinished / 1000. In the onFinish() method, call setDisplayedChild(2).

Joe
  • 42,036
  • 13
  • 45
  • 61
  • Thanks, Joe! I need them to be custom views; the real app has layouts that are more complex, and do more things than my sample. In your sample, you have hardcoded the integers in setDisplayedChild(). Is there a preferred way to get the indices of each child? Maybe button1Id = findViewById("id/theviewswitcher").getViewId("id/button1") ?? – Thunder Rabbit Jun 14 '11 at 03:54
  • yes, I'm using CountDownTimer. (not that you'd easily find it on GH) :-) – Thunder Rabbit Jun 14 '11 at 03:56
  • If you have to reference it by id, and it's not as simple as button1/text1/button2, then you're better off **not** using a ViewFlipper, and instead have your countdown extend `ViewGroup` or `FrameLayout`. Then you can use class fields to reference the views explicitly (yes, using `findViewById()`), and simply hide/show the views as needed. The example above was based on the limited example of button/countdown/button, where a ViewFlipper is easy. I suggest **not** using removeView() and addView(), because that will incur more overhead. – Joe Jun 14 '11 at 04:06
  • On my real app, the seven xml layouts are relatively simple, but the classes running each one is a bit complex. My boss is saying "go for it" with the ViewFlipper. "We can create a hashed list of the ids by iterating through the ViewFlipper if the ids get too hard to manage." – Thunder Rabbit Jun 14 '11 at 04:22
  • If you need more ideas, take a look at the source for [ViewAnimator](http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/widget/ViewAnimator.java;h=907cfb352a41b11821f799d02cc4923dd00b21aa;hb=refs/heads/master) (superclass to ViewFlipper) – Joe Jun 14 '11 at 04:29