Html.ImageGetter TextView

前端 未结 5 1676
猫巷女王i
猫巷女王i 2020-11-27 17:58

So Im using ImageGetter to display the images from JSON blog posts. Im getting the correct source in the log but the URL changes when it reaches setBounds. Any ideas?

<
相关标签:
5条回答
  • 2020-11-27 18:06

    If you have mTV (I mean TextView), you can calculate based on its dimensions (mTv.getWidth() and mTv.getHeight()) and dimension of created bitmap (bitmap.getWidth() and bitmap.getHeight()) and set these values as new dimensions of TextView (mTv).

            if (bitmap != null) {
                BitmapDrawable d = new BitmapDrawable(bitmap);
                mDrawable.addLevel(1, 1, d);
                int width = mTv.getWidth() < bitmap.getWidth() ? mTv.getWidth() : bitmap.getWidth();
                int height = bitmap.getHeight() * width / bitmap.getWidth();
                mDrawable.setBounds(0, 0, width, height);
                mDrawable.setLevel(1);
                // i don't know yet a better way to refresh TextView 
                // mTv.invalidate() doesn't work as expected 
                // but we can calculate new TextView dimensions
                mTv.setHeight(height);
                CharSequence t = mTv.getText();
                mTv.setText(t);
            } 
    
    0 讨论(0)
  • 2020-11-27 18:19

    This answer may help someone. I used Jsoup to extract <Img/> tag out of the string then i show the image in ImageView and <p> in Textview. Results was according to what i needed. Also i used Universal Image Loader Libaray to load images in ImageView Then i added view programmatically to the layout in my case layout was the linearlayout so i made a helper class and passed content,html string and linear layout as the parameter.

    add jsoup in your project.

    compile 'org.jsoup:jsoup:1.9.2'
    

    Here some snippet.

    public class PostContentHandler {
    Context context;
    String content;
    LinearLayout linearLayout;
    
    public PostContentHandler(Context context, String content, LinearLayout linearLayout) {
        this.context = context;
        this.content = content;
        this.linearLayout = linearLayout;
    
    }
    
    public void setContentToView() {
    
        //custom font
        Typeface bitterBoldFont = Typeface.createFromAsset(context.getAssets(), "fonts/Bitter-Regular.otf");
    
        List<String> p = new ArrayList<>();
        List<String> src = new ArrayList<>();
        List<String> li = new ArrayList<>();
        Document doc = Jsoup.parse(content);
    
        Elements elements = doc.getAllElements();
    
        for (Element element : elements) {
            Tag tag = element.tag();
            if (tag.getName().matches("h[1-6]{1}")) {
                String heading = element.select(tag.getName().toString()).text();
                TextView textView = new TextView(context);
                textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT));
                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams();
                int top = (int) context.getResources().getDimension(R.dimen.heading_margin_top);
                int start = (int) context.getResources().getDimension(R.dimen.content_margin);
                int end = (int) context.getResources().getDimension(R.dimen.content_margin);
                params.setMargins(start, top, end, 0);
                textView.setTextSize(20);
                textView.setTypeface(bitterBoldFont);
                textView.setText(heading);
                textView.setTextColor(context.getResources().getColor(R.color.black));
                linearLayout.addView(textView);
            }
     if (tag.getName().equalsIgnoreCase("p")) {
                element.select("img").remove();
                String body = element.html();
                TextView textView = new TextView(context);
                textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT));
                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams();
                int top = (int) context.getResources().getDimension(R.dimen.heading_margin_top);
                int start = (int) context.getResources().getDimension(R.dimen.content_margin);
                int end = (int) context.getResources().getDimension(R.dimen.content_margin);
                params.setMargins(start, top, end, 0);
                textView.setTypeface(bitterBoldFont);
                textView.setLinksClickable(true);
                textView.setAutoLinkMask(Linkify.WEB_URLS);
                textView.setText(Html.fromHtml(body));
                textView.setTextColor(context.getResources().getColor(R.color.content_color));
                linearLayout.addView(textView);
                p.add(body);
            }
            if (tag.getName().equalsIgnoreCase("ol")) {
                String ol = element.select(tag.getName().toString()).outerHtml();
                TextView textView = new TextView(context);
                textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT));
                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams();
                params.setMarginStart((int) context.getResources().getDimension(R.dimen.content_margin));
                int top = (int) context.getResources().getDimension(R.dimen.heading_margin_top);
                int start = (int) context.getResources().getDimension(R.dimen.content_margin);
                int end = (int) context.getResources().getDimension(R.dimen.content_margin);
                params.setMargins(start, top, end, 0);
                textView.setTypeface(bitterBoldFont);
                textView.setLinksClickable(true);
                textView.setAutoLinkMask(Linkify.WEB_URLS);
                textView.setTextColor(context.getResources().getColor(R.color.content_color));
                textView.setText(Html.fromHtml(ol, null, new MyTagHandler()));
                linearLayout.addView(textView);
    
            }
            if (tag.getName().equalsIgnoreCase("ul")) {
                String ul = element.select(tag.getName().toString()).outerHtml();
                TextView textView = new TextView(context);
    
                textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT));
                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams();
                int top = (int) context.getResources().getDimension(R.dimen.heading_margin_top);
                int start = (int) context.getResources().getDimension(R.dimen.content_margin);
                int end = (int) context.getResources().getDimension(R.dimen.content_margin);
                params.setMargins(start, top, end, 0);
                textView.setTypeface(bitterBoldFont);
                textView.setLinksClickable(true);
                textView.setAutoLinkMask(Linkify.WEB_URLS);
                textView.setTextColor(context.getResources().getColor(R.color.content_color));
                textView.setText(Html.fromHtml(ul, null, new MyTagHandler()));
                linearLayout.addView(textView);
            }
            if (tag.getName().equalsIgnoreCase("img")) {
                String url = element.select("img").attr("src");
                final ImageView imageView = new ImageView(context);
                imageView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT));
                final ProgressBar progressBar = new ProgressBar(context);
                linearLayout.addView(progressBar);
                progressBar.setVisibility(View.GONE);
                ImageLoader imageLoader = ImageLoader.getInstance();
                imageLoader.displayImage(url, imageView, new SimpleImageLoadingListener() {
                    @Override
                    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                        super.onLoadingComplete(imageUri, view, loadedImage);
                        progressBar.setVisibility(View.INVISIBLE);
                        int height = loadedImage.getHeight();
                        imageView.getLayoutParams().height = getScreenWidth();
                        imageView.setAdjustViewBounds(true);
                        imageView.requestLayout();
                    }
    
                    @Override
                    public void onLoadingStarted(String imageUri, View view) {
                        super.onLoadingStarted(imageUri, view);
                        progressBar.setVisibility(View.VISIBLE);
                    }
                });
                linearLayout.addView(imageView);
                src.add(url);
            }
    
        }
    }
    
    public static int getScreenWidth() {
        return Resources.getSystem().getDisplayMetrics().widthPixels;
    }
    }
    

    I hope my answer will help someone.

    0 讨论(0)
  • 2020-11-27 18:26

    An alternative solution using Glide and Coroutines with the assumption that a retry is not required:

    import android.content.res.Resources
    import android.graphics.Bitmap
    import android.graphics.Canvas
    import android.graphics.drawable.BitmapDrawable
    import android.graphics.drawable.Drawable
    import android.text.Html
    import android.widget.TextView
    import androidx.lifecycle.LifecycleCoroutineScope
    import com.bumptech.glide.RequestManager
    import kotlinx.coroutines.Dispatchers
    import kotlinx.coroutines.launch
    import kotlinx.coroutines.withContext
    import kotlin.math.roundToInt
    
    class HtmlImageGetter(
        private val scope: LifecycleCoroutineScope,
        private val res: Resources,
        private val glide: RequestManager,
        private val htmlTextView: TextView
    ) : Html.ImageGetter {
    
        override fun getDrawable(url: String): Drawable {
            val holder = BitmapDrawablePlaceHolder(res, null)
    
            scope.launch(Dispatchers.IO) {
                runCatching {
                    val bitmap = glide
                        .asBitmap()
                        .load(url)
                        .submit()
                        .get()
    
                    val drawable = BitmapDrawable(res, bitmap)
    
                    val scale = 1.25 // This makes the image scale in size.
                    val width = (drawable.intrinsicWidth * scale).roundToInt()
                    val height = (drawable.intrinsicHeight * scale).roundToInt()
                    drawable.setBounds(0, 0, width, height)
    
                    holder.setDrawable(drawable)
                    holder.setBounds(0, 0, width, height)
    
                    withContext(Dispatchers.Main) { htmlTextView.text = htmlTextView.text }
                }
            }
    
            return holder
        }
    
        internal class BitmapDrawablePlaceHolder(res: Resources, bitmap: Bitmap?) : BitmapDrawable(res, bitmap) {
            private var drawable: Drawable? = null
    
            override fun draw(canvas: Canvas) {
                drawable?.run { draw(canvas) }
            }
    
            fun setDrawable(drawable: Drawable) {
                this.drawable = drawable
            }
        }
    }
    

    In a Fragment or Activity use with HtmlCompat

    val imageGetter = HtmlImageGetter(lifecycleScope, resources, glide, htmlTextView)
    val styledText = HtmlCompat.fromHtml(htmlString, flags, imageGetter, null)
    htmlTextView.text = styledText
    
    0 讨论(0)
  • 2020-11-27 18:26

    If you have mTV (I mean TextView), you can calculate based on its dimensions (mTv.getWidth() and mTv.getHeight()) and dimension of created bitmap (bitmap.getWidth() and bitmap.getHeight()) and set these values as new dimensions of TextView (mTv).

    0 讨论(0)
  • 2020-11-27 18:32

    the easiest solution is:

    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.MalformedURLException;
    import java.net.URL;
    
    import org.pskink.soom.R;
    
    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.drawable.BitmapDrawable;
    import android.graphics.drawable.Drawable;
    import android.graphics.drawable.LevelListDrawable;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.text.Html;
    import android.text.Html.ImageGetter;
    import android.text.Spanned;
    import android.util.Log;
    import android.widget.TextView;
    
    public class TestImageGetter extends Activity implements ImageGetter {
        private final static String TAG = "TestImageGetter";
        private TextView mTv;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.test_image_getter);
            String source = "this is a test of <b>ImageGetter</b> it contains " +
                    "two images: <br/>" +
                    "<img src=\"http://developer.android.com/assets/images/dac_logo.png\"><br/>and<br/>" +
                    "<img src=\"http://developer.android.com/assets/images/icon_search.png\">";
    
            Spanned spanned = Html.fromHtml(source, this, null);
            mTv = (TextView) findViewById(R.id.text);
            mTv.setText(spanned);
        }
    
        @Override
        public Drawable getDrawable(String source) {
            LevelListDrawable d = new LevelListDrawable();
            Drawable empty = getResources().getDrawable(R.drawable.ic_launcher);
            d.addLevel(0, 0, empty);
            d.setBounds(0, 0, empty.getIntrinsicWidth(), empty.getIntrinsicHeight());
    
            new LoadImage().execute(source, d);
    
            return d;
        }
    
        class LoadImage extends AsyncTask<Object, Void, Bitmap> {
    
            private LevelListDrawable mDrawable;
    
            @Override
            protected Bitmap doInBackground(Object... params) {
                String source = (String) params[0];
                mDrawable = (LevelListDrawable) params[1];
                Log.d(TAG, "doInBackground " + source);
                try {
                    InputStream is = new URL(source).openStream();
                    return BitmapFactory.decodeStream(is);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
    
            @Override
            protected void onPostExecute(Bitmap bitmap) {
                Log.d(TAG, "onPostExecute drawable " + mDrawable);
                Log.d(TAG, "onPostExecute bitmap " + bitmap);
                if (bitmap != null) {
                    BitmapDrawable d = new BitmapDrawable(bitmap);
                    mDrawable.addLevel(1, 1, d);
                    mDrawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
                    mDrawable.setLevel(1);
                    // i don't know yet a better way to refresh TextView
                    // mTv.invalidate() doesn't work as expected
                    CharSequence t = mTv.getText();
                    mTv.setText(t);
                }
            }
        }
    }
    

    there is one not quite elegant way to re-layout a TextView after image downloading:

    // i don't know yet a better way to refresh TextView
    // mTv.invalidate() doesn't work as expected
    CharSequence t = mTv.getText();
    mTv.setText(t);
    

    if anybody knows better solution please let me know

    0 讨论(0)
提交回复
热议问题