Search code examples
javaandroidtextviewspannablestring

Android: SpannableString with correctly formated numbers


I would like to have a list of instructions that are correctly numbered in an enumeration. For that I use the SpannableString and I have the following code:

//Get string array from a sqLite Database
String [] instructions = MainActivity.sqLiteDataba.getPreparationInstructions(item);

//Create Spannable String Builder
int numberOfCurrentInstruction = 1;
SpannableStringBuilder builderInstructions =  new SpannableStringBuilder();
for (int i =0; i<instructions.length;i++) {
    if(instructions[i] == null ) {
        continue;
    }

    builderInstructions.append(numberOfCurrentInstruction + ". " + instructions[i] + "\n");
    numberOfCurrentInstruction++;
}

The output in a textview (called in a Fragment) does not look like the desired way, as you can see in the screenshot: enter image description here

I would like the numbers to serve as "bullet points" meaning that if there is a linebreak in the textView, the following text should not start under the number but with a little bit of space. Any idea how I can do that?

Update: I tried the suggested approach posted below (Darkman) with the layout inflator but unfortunately only the very first item is being displayed. Here is the code from inside a Fragment:

    String [] instructions = MainActivity.sqLiteDB.getPreparationInstructions(item);

    
    int numberOfCurrentInstruction = 1;
    ViewGroup main = getView().findViewById(R.id.main);
    LayoutInflater inflator = getLayoutInflater();

    for (int i =0; i<instructions.length;i++) {
        if(instructions[i] == null ) {
            continue;

        }

        ViewGroup mainLayout = (ViewGroup) inflator.inflate(R.layout.custom, main, true);
        ViewGroup customLayout = (ViewGroup) mainLayout.getChildAt(i);


        TextView num = (TextView) customLayout.getChildAt(0);
        TextView text = (TextView) customLayout.getChildAt(1);
        num.setText((numberOfCurrentInstruction) + ".");
        text.setText(instructions[i]);
        numberOfCurrentInstruction++;
    }

Here is the custom.xml file

<?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="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:gravity="right"
        android:layout_marginTop="@dimen/_2sdp"
        android:layout_marginLeft="@dimen/_5sdp"
        android:textSize="@dimen/_7ssp"/>

    <TextView
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:gravity="left"
        android:layout_marginTop="@dimen/_2sdp"
        android:layout_marginLeft="@dimen/_2sdp"
        android:layout_marginRight="@dimen/_5sdp"
        android:textSize="@dimen/_7ssp"/>
</LinearLayout>

And the main.xml is inside a xml file for a fragment and looks like this:

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:id="@+id/main">


    </LinearLayout>

The array instructions has 5 elements in it and none of them is null and the for loop is executed 5 times (I checked this by using LogTag). However, only the first instruction is displayed and the others not. Any idea what the problem might be?


Solution

  • You can achieve that by using two TextViews via XML like the following example.

    main.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:gravity="center"
        android:background="#333333"
        android:orientation="vertical"
        android:id="@+id/main">
    
    </LinearLayout>
    

    custom.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="wrap_content"
        android:orientation="horizontal">
    
        <TextView
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:gravity="right"
            android:layout_marginLeft="10dp"/>
    
        <TextView
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:gravity="left"
            android:layout_marginRight="10dp"/>
    
    </LinearLayout>
    

    MainActivity.java

    public class MainActivity extends Activity 
    {
        private static final String[] str = {
            "Instruction 1: This is the first instruction that you have to do.",
            "Instruction 2: This is the second instruction that you have to do.",
            "Instruction 3: This is the third instruction that you have to do."
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.main);
            
            ViewGroup main = findViewById(R.id.main);
            LayoutInflater inflator = getLayoutInflater();
            
            for(int i=0; i<3; i++) {
                ViewGroup mainLayout = (ViewGroup) inflator.inflate(R.layout.custom, main, true);
                ViewGroup customLayout = (ViewGroup) mainLayout.getChildAt(i);
                TextView num = (TextView) customLayout.getChildAt(0);
                TextView text = (TextView) customLayout.getChildAt(1);
                num.setText((i+1) + ".");
                text.setText(str[i]);
            }
        }
    }
    

    Output: enter image description here