18

enter image description here

I am trying to align the TextView around ImageView. I am using the following code:

 private void createSpannableText(){
        TextView myTextView = (TextView) findViewById(R.id.textView);
        SpannableStringBuilder builder = new SpannableStringBuilder();
        builder.append(this.getText(R.string.loren__ipsum__max));
        int lengthOfPart1 = builder.length();
        builder.append(" ");
        builder.append(this.getText(R.string.lorem__ipsum));
        Drawable d = getResources().getDrawable(R.drawable.myImage);
        d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); // <---- Very important otherwise your image won't appear
        ImageSpan myImage = new ImageSpan(d);
        builder.setSpan(myImage, 0, lengthOfPart1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        myTextView.setText(builder);
    }

But couldn't get the exact result. What shall I do? Do I need to use SpannableStringBuilder in this case or there is another way. Please help. I used this post-http://majaxandroidtips.blogspot.in/2009/06/how-to-have-few-layout-elements-wrap_17.html to have the solution.

P.S.: I also want 6dp margin around the ImageView

Debopam Mitra
  • 1,720
  • 3
  • 24
  • 50

1 Answers1

18

You can achieve this by using the android.text.style.LeadingMarginSpan.LeadingMarginSpan2 interface which is available in API 8. Here is the article, not in English though, translate it using your browser. Besides you can download the source code of the example directly from here.

Your layout:

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="5dp">
    <TextView
        android:textSize="18.0sp"
        android:id="@+id/message_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/text" />
    <ImageView
        android:src="@drawable/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/icon" />
</RelativeLayout>

Helper class implements LeadingMarginSpan.LeadingMarginSpan2

class MyLeadingMarginSpan2 implements LeadingMarginSpan.LeadingMarginSpan2 {
    private int margin;
    private int lines;

    MyLeadingMarginSpan2(int lines, int margin) {
        this.margin = margin;
        this.lines = lines;
    }

    /* Возвращает значение, на которе должен быть добавлен отступ */
    @Override
    public int getLeadingMargin(boolean first) {
        if (first) {
            /*
             * Данный отступ будет применен к количеству строк
             * возвращаемых getLeadingMarginLineCount()
             */
            return margin;
        } else {
            // Отступ для всех остальных строк
            return 0;
        }
    }

    @Override
    public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, 
            int top, int baseline, int bottom, CharSequence text, 
            int start, int end, boolean first, Layout layout) {}

    /*
     * Возвращает количество строк, к которым должен быть 
     * применен отступ возвращаемый методом getLeadingMargin(true)
     * Замечание:
     * Отступ применяется только к N строкам первого параграфа.
     */
    @Override
    public int getLeadingMarginLineCount() {
        return lines;
    }
};

Your activity code:

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        String text = getString(R.string.text);

        // Получаем иконку и ее ширину
        Drawable dIcon = getResources().getDrawable(R.drawable.icon);
        int leftMargin = dIcon.getIntrinsicWidth() + 10;

        // Устанавливаем иконку в R.id.icon
        ImageView icon = (ImageView) findViewById(R.id.icon);
        icon.setBackgroundDrawable(dIcon);

        SpannableString ss = new SpannableString(text);
        // Выставляем отступ для первых трех строк абазца
        ss.setSpan(new MyLeadingMarginSpan2(3, leftMargin), 0, ss.length(), 0);

        TextView messageView = (TextView) findViewById(R.id.message_view);
        messageView.setText(ss);
    }

And finally here a demo result:

enter image description here

K_Anas
  • 30,228
  • 9
  • 65
  • 80
  • I have implemented it. But the ImageView gets behind the text not in its actual position. – Debopam Mitra Jul 15 '12 at 18:12
  • Ok. I get it. But is there a possibility to determine no. of line counts according to the height of the Image. What I mean to say is that is the lines will be determined by the height of the image. It is not possible by using dIcon.getIntrinsicHeight() because it returns the value which is greater than my no. of lines. – Debopam Mitra Jul 15 '12 at 18:47
  • 1
    @Debopam I think you can get the number by using image height and text line height of textview, you can see vortex's answer http://stackoverflow.com/questions/2248759/how-to-layout-text-to-flow-around-an-image – K_Anas Jul 15 '12 at 19:08
  • 1
    @Debopam he used int lines = (int)Math.round(height / textLineHeight); – K_Anas Jul 15 '12 at 19:09
  • Why don't you use an ImageSpan? – JPMagalhaes Aug 15 '13 at 08:36
  • This works well! One peculiarity to note: in the function getLeadingMargin(boolean first), "first" represents lines 0..n-1 where n is the value returned by getLeadingMarginLineCount(). – Peri Hartman Apr 12 '14 at 00:38
  • @K_Anas : How would this code change if I have imageview on right side and text has to align using right margin ? It's possible with this custom code, rigth ? – Wahib Ul Haq Sep 25 '15 at 13:31
  • The problem with this solution is that the margin created to avoid the image is applied to every carriage return in the field. – Yoann Hercouet Jun 28 '16 at 13:05
  • @K_Anas how to change your code for image placed on the right side? – Ramona Jul 30 '17 at 21:06
  • @PeriHartman hello. any idea on how to change this code for image placed on the right side of the screen? – Ramona Aug 08 '17 at 11:13
  • @WahibUlHaq did you solve this problem and manged to set this code for image placed on the right side of the screen? – Ramona Aug 10 '17 at 12:55
  • @Ramona I won't even remember coz its almost a 2 year old problem :) But you can try and give a look at this solution https://stackoverflow.com/a/8463221/1016544 and I have seen examples where people solved a similar problem using `android.text.style.LeadingMarginSpan.LeadingMarginSpan2` – Wahib Ul Haq Aug 10 '17 at 20:17