Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading a TextView from xml into a TextSwitcher

I've been trying to setup a TextSwitcher with the TextView loading in from an xml file. I have this basic TextSwitcher example that uses an empty TextView working ok:

.java

public class TextSwitcherTest extends Activity 
{
    private TextSwitcher textSwitcher;

    private ViewFactory viewFactory = new ViewFactory() 
    {
        public View makeView() 
        {
            TextView textView = new TextView(TextSwitcherTest.this);

            return textView;
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        textSwitcher = (TextSwitcher) findViewById(R.id.textSwitcher);

        textSwitcher.setFactory(viewFactory);

        Animation in = AnimationUtils.loadAnimation(this,android.R.anim.fade_in);
        Animation out = AnimationUtils.loadAnimation(this,android.R.anim.fade_out);

        textSwitcher.setInAnimation(in);
        textSwitcher.setOutAnimation(out);

        textSwitcher.setText("test ok");
    }    
}

-

main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextSwitcher 
        android:id="@+id/textSwitcher"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

But when I change the code to try and load a TextView from an xml file, it spits out a pile of errors. Here's the amended code:

.java

public class TextSwitcherTest extends Activity 
{
    private TextSwitcher textSwitcher;

    private ViewFactory viewFactory = new ViewFactory() 
    {
        public View makeView() 
        {
            LayoutInflater inflater = LayoutInflater.from(TextSwitcherTest.this);

            TextView textView = (TextView) inflater.inflate(R.id.textView,null);

            return textView;
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        textSwitcher = (TextSwitcher) findViewById(R.id.textSwitcher);

        textSwitcher.setFactory(viewFactory);

        Animation in = AnimationUtils.loadAnimation(this,android.R.anim.fade_in);
        Animation out = AnimationUtils.loadAnimation(this,android.R.anim.fade_out);

        textSwitcher.setInAnimation(in);
        textSwitcher.setOutAnimation(out);

        textSwitcher.setText("test ok");
    }    
}

-

textview.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

</LinearLayout>

Can anyone offer a suggestion where I'm going wrong? The code compiles ok but I'm sure it's with the LayoutInflater being misused in some way?


error messages (it didn't display the '11 more'):

07-22 03:51:24.096: W/dalvikvm(580): threadid=1: thread exiting with uncaught exception (group=0x409c01f8)
07-22 03:51:24.137: E/AndroidRuntime(580): FATAL EXCEPTION: main
07-22 03:51:24.137: E/AndroidRuntime(580): java.lang.RuntimeException: Unable to start activity ComponentInfo{test09.TextSwitcher01/test09.TextSwitcher01.TextSwitcherTest}: android.content.res.Resources$NotFoundException: Resource ID #0x7f050001 type #0x12 is not valid
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.app.ActivityThread.access$600(ActivityThread.java:123)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.os.Handler.dispatchMessage(Handler.java:99)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.os.Looper.loop(Looper.java:137)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.app.ActivityThread.main(ActivityThread.java:4424)
07-22 03:51:24.137: E/AndroidRuntime(580):  at java.lang.reflect.Method.invokeNative(Native Method)
07-22 03:51:24.137: E/AndroidRuntime(580):  at java.lang.reflect.Method.invoke(Method.java:511)
07-22 03:51:24.137: E/AndroidRuntime(580):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
07-22 03:51:24.137: E/AndroidRuntime(580):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
07-22 03:51:24.137: E/AndroidRuntime(580):  at dalvik.system.NativeStart.main(Native Method)
07-22 03:51:24.137: E/AndroidRuntime(580): Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x7f050001 type #0x12 is not valid
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.content.res.Resources.loadXmlResourceParser(Resources.java:2110)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.content.res.Resources.getLayout(Resources.java:857)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.view.LayoutInflater.inflate(LayoutInflater.java:394)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
07-22 03:51:24.137: E/AndroidRuntime(580):  at test09.TextSwitcher01.TextSwitcherTest$1.makeView(TextSwitcherTest.java:23)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.widget.ViewSwitcher.obtainView(ViewSwitcher.java:80)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.widget.ViewSwitcher.setFactory(ViewSwitcher.java:99)
07-22 03:51:24.137: E/AndroidRuntime(580):  at test09.TextSwitcher01.TextSwitcherTest.onCreate(TextSwitcherTest.java:38)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.app.Activity.performCreate(Activity.java:4465)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
07-22 03:51:24.137: E/AndroidRuntime(580):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
07-22 03:51:24.137: E/AndroidRuntime(580):  ... 11 more
like image 908
Spoonface Avatar asked Jul 22 '12 01:07

Spoonface


2 Answers

There are several things wrong with your code:

First, the LayoutInflater.inflate() method expects the id of a layout file in the form of R.layout.layout_name and not in the form of R.id.some_id:

TextView textView = (TextView) inflater.inflate(R.layout.textView, null);

Second, the code you use will throw a ClassCastException because the root of the inflated layout is a LinearLayout and not a TextView as you try to cast it. Your code should be:

LinearLayout ll = (Linearlayout) inflater.inflate(R.layout.textView, null);

But even the line above will not work because, as its name suggest, a TextSwitcher will take only children of type TextView, nothing can come between the TextSwitcher and the two TextView children. The correct code to use will be in the end:

Layout for textview.xml:

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello" />

And the viewFactory field will be:

private ViewFactory viewFactory = new ViewFactory() {
        public View makeView()  {
            LayoutInflater inflater = LayoutInflater.from(TextSwitcherTest.this);
            TextView textView = (TextView) inflater.inflate(R.layout.textView, null);
            return textView;
        }
};
like image 125
user Avatar answered Oct 11 '22 18:10

user


Pretty simple using mostly XML.

In your XML add a TextSwitcher root view and two TextViews within it:

<TextSwitcher
    android:id="@+id/textswitcher_id"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentEnd="true"
    android:inAnimation="@android:anim/fade_in"
    android:outAnimation="@android:anim/fade_out">

    <TextView
        android:id="@+id/tv_onboarding_next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Text1" />

    <TextView
        android:id="@+id/tv_onboarding_letsgo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Text2" />

</TextSwitcher>

Then in code, wherever you want the animation action to occur:

Using Kotlin:

textswitcher_id.setText(getString("Text2"))

// and somewhere else, switch it back:

textswitcher_id.setText(getString("Text1"))

Or in Java:

findViewById(R.id.textswitcher_id).setText(getString("Text2"));

// and somewhere else, switch it back:

findViewById(R.id.textswitcher_id).setText(getString("Text1"));

Note:

  • Within the XML you can also use two includes rather TextView twice, see: https://stackoverflow.com/a/42724239/1852191

  • The reason we have the default text in the XML even though we set it programmatically later is because on the first view it will be blank, until it's set

like image 42
Abushawish Avatar answered Oct 11 '22 17:10

Abushawish