安卓ImageGetter图片重叠文字问题

24
我正在尝试将一块包含图片的 HTML 代码加载到 TextView 中,可以使用以下方法:
URLImageParser p = new URLImageParser(articleBody, this);
Spanned htmlSpan = Html.fromHtml(parsedString, p, null);

顺便说一下,parsedString是HTML。总之,它会加载,但是图像没有为其创建任何空间以坐在其中,因此它们最终会重叠在它们上面的文本上。这是我的URLImageParser文件:

public class URLImageParser implements Html.ImageGetter {
Context c;
View container;

/***
 * Construct the URLImageParser which will execute AsyncTask and refresh the container
 * @param t
 * @param c
 */
public URLImageParser(View t, Context c) {
    this.c = c;
    this.container = t;
}

public Drawable getDrawable(String source) {
    URLDrawable urlDrawable = new URLDrawable();

    // get the actual source
    ImageGetterAsyncTask asyncTask = 
        new ImageGetterAsyncTask( urlDrawable);

    asyncTask.execute(source);

    // return reference to URLDrawable where I will change with actual image from
    // the src tag
    return urlDrawable;
}

public class ImageGetterAsyncTask extends AsyncTask<String, Void, Drawable>  {
    URLDrawable urlDrawable;

    public ImageGetterAsyncTask(URLDrawable d) {
        this.urlDrawable = d;
    }

    @Override
    protected Drawable doInBackground(String... params) {
        String source = params[0];
        return fetchDrawable(source);
    }

    @Override
    protected void onPostExecute(Drawable result) {
        // set the correct bound according to the result from HTTP call
        Log.d("height",""+result.getIntrinsicHeight());
        Log.d("width",""+result.getIntrinsicWidth());
        urlDrawable.setBounds(0, 0, 0+result.getIntrinsicWidth(), 0+result.getIntrinsicHeight()); 

        // change the reference of the current drawable to the result
        // from the HTTP call
        urlDrawable.drawable = result;

        // redraw the image by invalidating the container
        URLImageParser.this.container.invalidate();
    }

    /***
     * Get the Drawable from URL
     * @param urlString
     * @return
     */
    public Drawable fetchDrawable(String urlString) {
        try {
            URL aURL = new URL(urlString);
            final URLConnection conn = aURL.openConnection(); 
            conn.connect(); 
            final BufferedInputStream bis = new BufferedInputStream(conn.getInputStream()); 
            final Bitmap bm = BitmapFactory.decodeStream(bis);
            Drawable drawable = new BitmapDrawable(bm);
            drawable.setBounds(0,0,bm.getWidth(),bm.getHeight());
            return drawable;
        } catch (Exception e) {
            return null;
        } 
    }
}

有什么想法吗?非常感谢。


你正在尝试进行图片的懒加载吗?如果是这样,我认为这可能是唯一的问题。为什么不尝试同时加载图像和文本呢? - PH7
“Lazy load” 究竟是什么意思? - Nick
懒加载意味着在图片下载时显示它们。另一种选择是等待图片下载完成,然后再显示视图。 - Kurtis Nusbaum
我正在尝试做类似的事情,你能告诉我这里的URLDrawable是什么吗? - Abhay Kumar
@AbhayKumar 我认为包括URLDrawable的原始代码在https://dev59.com/fWs05IYBdhLWcg3wIehj#7442725中定义。 - Kuitsi
5个回答

55

你可以将你的容器c (视图) 改为TextView,然后使你的onPostExecute看起来像这样:

@Override 
protected void onPostExecute(Drawable result) { 
    // set the correct bound according to the result from HTTP call 
    Log.d("height",""+result.getIntrinsicHeight()); 
    Log.d("width",""+result.getIntrinsicWidth()); 
    urlDrawable.setBounds(0, 0, 0+result.getIntrinsicWidth(), 0+result.getIntrinsicHeight());  

    // change the reference of the current drawable to the result 
    // from the HTTP call 
    urlDrawable.drawable = result; 

    // redraw the image by invalidating the container 
    URLImageParser.this.container.invalidate();

    // For ICS
    URLImageParser.this.container.setHeight((URLImageParser.this.container.getHeight() 
    + result.getIntrinsicHeight()));

    // Pre ICS
    URLImageParser.this.textView.setEllipsize(null);
} 

这将首先绘制图像,然后立即将TextView的高度设置为可绘制对象的高度 + TextView的高度。


12
container.setText(container.getText())也可以使用(前提是container是一个TextView)。不过我想知道,强制TextView重新布局的最佳方法是什么。 - dcow
4
setHeight 不起作用 :( Eclipse 建议使用 setMinimumHeight,但这并没有帮助解决问题。 - Groosha
2
@Kondra007,你需要按照Martin的指示将容器c(视图)更改为textView,这样Eclipse就不会要求你使用setMinimumHeight。 - Najeebullah Shah
当我在列表适配器中使用此代码并回收convertView时,容器高度出现问题。但是,正如@DavidCowden指出的那样,使用container.setText(container.getText())似乎可以解决这个问题。 - swanson
根据@dcow所说和@swanson的评论,我遇到了同样的问题,然后container.setText(container.getText())解决了我的问题。 - Jeeten Parmar
显示剩余4条评论

2

我没有足够的声望来为Martin S投票,但他的回答确实很有帮助。如果TextView在加载前显示了默认图片,我们可以像这样改变setHeight()方法:

    URLImageParser.this.container.setHeight((URLImageParser.this.container.getHeight() 
+ result.getIntrinsicHeight()-mDefaultDrawable.getInstrinsicHeight()));

0
我发现这些解决方案有一个有趣的行为: 如果图像加载得太快,而且textview还没有被渲染(例如,我使用带缓存的Okhttp,所以第二次调用非常快),那么textview的大小为0。
为了解决这个问题,我将ImageGetter从AsyncTask转换回来,而是启动一个AsyncTask,为我的TextView创建Spanned,并在此之后设置文本。
通过这种解决方案,每次加载图像时都不需要调整TextView的大小。
new AsyncTask<TextView, Void, Spanned>() {
      TextView tv;
      @Override
      protected Spanned doInBackground(TextView... params) {
        tv = params[0];
        return Html.fromHtml(feedEntry.getContent(),
                new HttpImageGetter(getActivity(), HttpLoaderImpl.getInstance(getActivity())),
                new Html.TagHandler() {

                  @Override
                  public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
                    //do nothing...
                  }
                });
      }

      @Override
      protected void onPostExecute(final Spanned result) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {

          @Override
          public void run() {
            tv.setText(result);
          }
        });
      }
    }.execute(textView);

0
也许我们不需要将容器从View更改为TextView。
   @Override
    protected void onPostExecute(Drawable result) {
        // set the correct bound according to the result from HTTP call
        urlDrawable.setBounds(0, 0, 0 + result.getIntrinsicWidth(), 0
                + result.getIntrinsicHeight());

        // change the reference of the current drawable to the result
        // from the HTTP call
        urlDrawable.drawable = result;

        // redraw the image by invalidating the container
        URLImageParser.this.container.setMinimumHeight((URLImageParser.this.container.getHeight()+ result.getIntrinsicHeight()));
        URLImageParser.this.container.requestLayout();
        URLImageParser.this.container.invalidate();
    }

-2

你需要将它加载到一个文本视图中的特定原因是什么?你可以使用WebView来代替吗?

如果你不能使用WebView,则最好的解决方案是不要将图像放在你的文本视图中,而是放在ImageView中。TextViews没有任何布局引擎功能,无法确定在彼此相关的图像和文本之间放置它们的位置。它们不是ViewGroups(如LinearLayout或RelativeLayout),因此没有内部布局规定功能。如果你真的不想使用webview(以及它具有的所有良好的布局引擎功能),则你需要自己想出如何排列单个TextViews和ImageViews。


3
WebViews 会影响用户体验。我正试图编写一个优秀的本地应用程序。我的图片已经能够显示了,我现在只需要让它们正确地排列布局即可。 - Nick
那很有道理。我会过滤掉图片并单独处理它们。 - Nick
11
@Nick,我认为你应该选择下面的答案。因为它解决了在TextView内的问题,不需要使用WebView。WebView不适合这个目的。而且,如果在ListView中使用WebView可能会出现问题。 - Timuçin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接