1

I have an app which is reading its information from a json file online, the format of which is like so:

       {
            "title":"Title",
            "introParagraph":"Text for introParagraph",
            "heading1":"Text for heading1",
            "paragraph1":"Text for paragraph1 \n\n image1"
            "heading2":"Text for heading2",
            "paragraph2":"Text for paragraph2 \n\n image2"
            "image1":"http://url.for.image1",
            "image2":"http://url.for.image2",
        },

I've shortened the json for simplicity. Each json object can have up to 7 headings and paragraphs and 5 images though they don't all have this and some don't have any images.

I'm trying to find a way to check if any of the paragraphs contain the text "image1", "image2", "image3" etc. and if so to replace it with the image from the url correlating to that key.

I've found similar questions such as this: How to replace String with an image inside an EditText?, however that shows how to replace the text with a drawable not an image from a url (i'm using Picasso to make this easier but I still don't know how to replace the text).

My layout file looks like this:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true">

    <LinearLayout android:orientation="vertical"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="300dp">

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

        </RelativeLayout>

        <TextView
            android:id="@+id/wiki_intro_paragraph"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

        <TextView
            android:id="@+id/wiki_heading1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

        <TextView
            android:id="@+id/wiki_paragraph1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

        <TextView
            android:id="@+id/wiki_heading2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

        <TextView
            android:id="@+id/wiki_paragraph2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    </LinearLayout>

</ScrollView>

just with more formatting and the headings and paragraphs go up to 7.

I can't put imageViews into my layout file because I don't know whether there will be any images from the json or where the text to be replaced will appear in the json i.e. sometimes the "image1" text is in the middle of the paragraph text, sometimes "image1" is in "paragraph1" sometimes it is in "paragraph7" etc.

Any help would be appreciated.


Update: Based on the answers below I am now working with this code:

private WikiItem mWikiItem;
private TextView mHeading1;
private TextView mParagraph1;
private Drawable image0;

@Override
protected void onCreate(Bundle savedInstanceBundle) {
    super.onCreate(savedInstanceBundle);

    mHeading1 = (TextView) findViewById(R.id.wiki_heading1);
    mParagraph1 = (TextView) findViewById(R.id.wiki_paragraph1);

    if (!(mWikiItem.getHeading1() == null)) {
        mHeading1.setText(mWikiItem.getHeading1());
        mParagraph1.setText(mWikiItem.getParagraph1());
    } else {
        mHeading1.setVisibility(View.GONE);
        mParagraph1.setVisibility(View.GONE);
    }

    if (!(mWikiItem.getImage0() == null)) {
        Picasso.with(this)
                .load(Uri.parse(mWikiItem.getImage0()))
                .into(new Target() {
                    @Override
                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                        image0 = new BitmapDrawable(getResources(), bitmap);
                    }

                    @Override
                    public void onBitmapFailed(Drawable errorDrawable) {

                    }

                    @Override
                    public void onPrepareLoad(Drawable placeHolderDrawable) {

                    }
                });

        ImageSpan span;
        String abc = mParagraph1.getText().toString();
        SpannableString ss = new SpannableString(abc);
        for(int i = 0; i<abc.length();i++){//loop to check presence of other emoji strings.
            if (abc.contains("image0")){
                int startSpan = abc.indexOf("image0");
                image0.setBounds(0, 0, image0.getIntrinsicWidth(), image0.getIntrinsicHeight());
                span = new ImageSpan(image0, ImageSpan.ALIGN_BASELINE);
                ss.setSpan(span, startSpan, startSpan+2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
                abc = abc.replaceFirst("image0","  "); //replace with two blank spaces.
            }
            //to check other types of emoji, use else if ladder and place the similar code.
        }
        mParagraph1.append(ss);
    }
}

but I keep getting a Null Pointer error on the drawable "image0":

java.lang.RuntimeException: Unable to start activity ComponentInfo{xyz.jameslester.cryptozoologytoday/xyz.jameslester.cryptozoologytoday.WikiSection.WikiDetailActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.drawable.Drawable.getIntrinsicWidth()' on a null object reference

and I can't figure out why.


Update 2: Seems the way to fix it is by putting the code at the end within the internal method "onBitmapLoaded":

Picasso.with(this)
       .load(uri2)
       .into(new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                Drawable image0 = new BitmapDrawable(getResources(), bitmap);

                ImageSpan span;
                String abc = mParagraph1.getText().toString();
                SpannableString ss = new SpannableString(abc);

                for(int i = 0; i<abc.length();i++){//loop to check presence of other emoji strings.
                    if (abc.contains("image0")){
                        int startSpan = abc.indexOf("image0");
                        image0.setBounds(0, 0, image0.getIntrinsicWidth(), image0.getIntrinsicHeight());
                        span = new ImageSpan(image0, ImageSpan.ALIGN_BASELINE);
                        ss.setSpan(span, startSpan, startSpan+2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
                        abc = abc.replaceFirst("image0","  "); //replace with two blank spaces.
                    }

                }
                mParagraph1.append(ss);
            }

            @Override
            public void onBitmapFailed(Drawable errorDrawable) {

            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {

            }
        });
Community
  • 1
  • 1
ghertyish
  • 193
  • 1
  • 11
  • Would the image JSON Field be empty or not exist? Can you post the actual JSON? – basic Jul 14 '16 at 15:56
  • It just wouldn't exist, you can see it here if you want but it's a bit longer than the simplified version: [link](http://jameslester.xyz/wiki.json) – ghertyish Jul 14 '16 at 15:59
  • So you want to set your imageview to the image? Just not getting where you want the image to go. – basic Jul 14 '16 at 16:05
  • It sounds like you want to put the image inline with the text...? – kris larson Jul 14 '16 at 16:07
  • The image view in the layout file is for the "image" key which each object has. This works fine. What I'm trying to get is if you look at the object titled "Dogman" for example, it has two more keys; "image0" and "image1". The text "image0" can be found in "paragraph1" and the text "image1" can be found in paragraph2". I want to replace this text with the images at the urls for "image0" and "image1". – ghertyish Jul 14 '16 at 16:12
  • I feel I've probably made it confusing by leaving the image view in the layout file. I'll edit it to take it out. – ghertyish Jul 14 '16 at 16:13

2 Answers2

1

Create drawable from bitmap :

Drawable drawable;
Picasso.with(this)
   .load("youUrl")
   .into(new Target() {
       @Override
       public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
          drawable = new BitmapDrawable(getResources(), bitmap);
       }

       @Override
       public void onBitmapFailed(Drawable errorDrawable) {

       }

       @Override
       public void onPrepareLoad(Drawable placeHolderDrawable) {

       }
   });

And then use it on span like the link you provided.

Faruk
  • 5,438
  • 3
  • 30
  • 46
1

If you want the image to be apart of your textview you will need to set a drawable on your textview. A quick and dirty example would be:

TextView txt = (TextView) findViewById(R.id.textview);
Drawable bitmapDrawable = new BitmapDrawable(getResources(), YOURBITMAP FROM PICASSO);
txt.setCompoundDrawablesWithIntrinsicBounds(bitmapDrawable, 0, 0, 0);

The drawable can go in whichever location you want.

void setCompoundDrawablesWithIntrinsicBounds (int left, 
            int top, 
            int right, 
            int bottom)

So essentially create your BITMAP from Picasso. Convert it to a drawable and then set a CompoundDrawable on your TextView which will allow you to put the image wherever needed.

Resource: https://developer.android.com/reference/android/widget/TextView.html#setCompoundDrawablesWithIntrinsicBounds%28int,%20int,%20int,%20int%29

EDIT Alright so here is a more "complete" example of how you would do this. First we create our drawable from Picasso and then set the text and the image drawable to wherever we want it.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    txt = (TextView)findViewById(R.id.txt);

    //Load our image with Picasso.
    Picasso.with(this)
            .load(imgUrl)
            .into(new Target() {
                @Override
                public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                    //create a drawable from the bitmap. 
                    d = new BitmapDrawable(getResources(), bitmap);

                    //set the main text of the textview. 
                    txt.setText(p1);

                    //now we set the image drawable to the right (left, top, right, bottom)
                    txt.setCompoundDrawablesWithIntrinsicBounds(null, null, d, null);
                }

                @Override
                public void onBitmapFailed(Drawable errorDrawable) {

                }

                @Override
                public void onPrepareLoad(Drawable placeHolderDrawable) {

                }
            });
}

Result

enter image description here

basic
  • 3,348
  • 3
  • 21
  • 36
  • I don't really get the setCompoundDrawablesWithIntrinsicBounds bit, but creating a drawable from Picasso seems like a good first step. As Al Zill says in the other answer I could then follow the steps in the link in my question. I'll try it out and report back, thanks – ghertyish Jul 14 '16 at 16:19
  • I get where you're coming from now but the problem I'm having is trying to replace some text inside the paragraph with the image, not just position the image by the text. – ghertyish Jul 14 '16 at 16:42
  • Hi, I've updated my question with what I'm now working with. Can you see why I'm getting a Null Pointer exception? – ghertyish Jul 14 '16 at 17:00