Làm cách nào để thêm hình ảnh trong văn bản TextView?


83

Tôi đã tìm kiếm trên Google và xem qua trang web này, nơi tôi tìm thấy một câu hỏi tương tự như câu hỏi của tôi, trong đó làm thế nào để đưa hình ảnh vào TextViewvăn bản, ví dụ "xin chào, tên tôi là [image]" và câu trả lời là:

ImageSpan is = new ImageSpan(context, resId);
text.setSpan(is, index, index + strLength, 0);

Tôi muốn biết trong mã này,

  1. Tôi phải nhập hoặc làm gì trong ngữ cảnh?
  2. Tôi phải làm điều gì đó để text.setSpan()nhập hoặc tham chiếu tương tự hay để nguyên văn bản?

Nếu ai đó có thể phá vỡ điều này cho tôi, điều đó sẽ được đánh giá cao.

Câu trả lời:


200

Thử đi ..

    txtview.setCompoundDrawablesWithIntrinsicBounds(
                    R.drawable.image, 0, 0, 0);

Cũng xem phần này .. http://developer.android.com/reference/android/widget/TextView.html

Hãy thử điều này trong tệp xml

    <TextView
        android:id="@+id/txtStatus"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:drawableLeft="@drawable/image"
        android:drawablePadding="5dp"
        android:maxLines="1"
        android:text="@string/name"/>

Tôi đã nhận ra lỗi "Không thể tạo ra một tài liệu tham khảo tĩnh đến setCompoundDrawablesWithIntrinsicBounds phương pháp không tĩnh (int, int, int, int) từ loại TextView"
Cranosaur

Cảm ơn Umesh, phương thức xml đã phù hợp với tôi. Tôi sử dụng bố cục xml cho TextView của mình nên tôi không biết liệu điều đó có tạo ra sự khác biệt hay không và có lẽ đó là lý do tại sao nó không hoạt động trong Java.
Cranosaur,

1
@Umesh Lakhani: Làm cách nào để có thể đưa nhiều tệp có thể vẽ vào văn bản bằng cách tiếp cận này?
Behnam

Trong XML, một hình ảnh được vẽ từ bên trái, không phải ở giữa.
CoolMind

Xin chào @Umesh. Làm thế nào để đặt một số lợi nhuận cho nó. setCompoundDrawablePaddingkhông làm gì cả
Prabs

73

com / xyz / customandroid / TextViewWithImages .java :

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.content.Context;
import android.text.Spannable;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class TextViewWithImages extends TextView {

    public TextViewWithImages(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    public TextViewWithImages(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public TextViewWithImages(Context context) {
        super(context);
    }
    @Override
    public void setText(CharSequence text, BufferType type) {
        Spannable s = getTextWithImages(getContext(), text);
        super.setText(s, BufferType.SPANNABLE);
    }

    private static final Spannable.Factory spannableFactory = Spannable.Factory.getInstance();

    private static boolean addImages(Context context, Spannable spannable) {
        Pattern refImg = Pattern.compile("\\Q[img src=\\E([a-zA-Z0-9_]+?)\\Q/]\\E");
        boolean hasChanges = false;

        Matcher matcher = refImg.matcher(spannable);
    while (matcher.find()) {
        boolean set = true;
        for (ImageSpan span : spannable.getSpans(matcher.start(), matcher.end(), ImageSpan.class)) {
            if (spannable.getSpanStart(span) >= matcher.start()
             && spannable.getSpanEnd(span) <= matcher.end()
               ) {
                spannable.removeSpan(span);
            } else {
                set = false;
                break;
            }
        }
        String resname = spannable.subSequence(matcher.start(1), matcher.end(1)).toString().trim();
        int id = context.getResources().getIdentifier(resname, "drawable", context.getPackageName());
        if (set) {
            hasChanges = true;
            spannable.setSpan(  new ImageSpan(context, id),
                                matcher.start(),
                                matcher.end(),
                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                             );
        }
    }

        return hasChanges;
    }
    private static Spannable getTextWithImages(Context context, CharSequence text) {
        Spannable spannable = spannableFactory.newSpannable(text);
        addImages(context, spannable);
        return spannable;
    }
}

Sử dụng:

trong res / layout / mylayout.xml :

            <com.xyz.customandroid.TextViewWithImages
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#FFFFFF00"
                android:text="@string/can_try_again"
                android:textSize="12dip"
                style=...
                />

Lưu ý rằng nếu bạn đặt TextViewWithImages.java ở một số vị trí ngoài com / xyz / customandroid / , bạn cũng phải thay đổi tên gói com.xyz.customandroidở trên.

trong res / giá trị / string.xml :

<string name="can_try_again">Press [img src=ok16/] to accept or [img src=retry16/] to retry</string>

trong đó ok16.pngretry16.png là các biểu tượng trong thư mục res / drawable /


Khi tôi sử dụng, textView.setText(R.string.can_try_again);nó không hiển thị hình ảnh, nó chỉ hiển thị văn bản thuần túy Press [img src=ok16/] to accept or [img src=retry16/] to retry. Bất kỳ trợ giúp? Điều này là do tôi muốn tải động các hình ảnh và đặt chúng trong textView.
Anas Azeem

@AnasAzeem bạn có thể hiển thị ok16 và thử lại 16 "bình thường" thông qua ImageView không? Bạn đã chỉ định TextViewWithImages thay cho TextView chưa?
18446744073709551615

1
đừng quên thay đổi <com.xyz.customandroid.TextViewWithImages với <YourPackageName.TextViewWithImages nếu không bạn có một lỗi trong lạm phát và NoClassFound ngoại lệ
AndroidGeek

1
làm việc của mình nhưng tôi không thể thiết lập chiều rộng chiều cao của hình ảnh và cũng không nhận được hình ảnh trong trung tâm của văn bản
Rajesh Koshti

1
Nó là một lớp tuyệt vời cho đến khi bạn đóng gói nó trong một bản phát hành. Nó bị lỗi và tôi vẫn không thể tìm ra lý do. Thậm chí đánh dấu lớp này trong bảo vệ-giữ trong. Vẫn không có may mắn. Hoặc có thể những hình ảnh tôi đã sử dụng là vector đó là lý do tại sao nó có thể bị rơi. Tôi không biết.
Uday

18

Tôi đã thử nhiều giải pháp khác nhau và điều này đối với tôi là tốt nhất:

SpannableStringBuilder ssb = new SpannableStringBuilder(" Hello world!");
ssb.setSpan(new ImageSpan(context, R.drawable.image), 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
tv_text.setText(ssb, TextView.BufferType.SPANNABLE);

Mã này sử dụng bộ nhớ tối thiểu.


2
trong trường hợp đó hình ảnh bổ sung nhưng class với cơ sở của văn bản tôi muốn class với đỉnh của văn bản mà bạn có thể giúp tôi
humayoon Siddique

2
nó hoạt động nhưng làm thế nào chúng ta có thể thay đổi kích thước hình ảnh biểu tượng theo kích thước văn bản
kushwah sunil

12

Câu trả lời này dựa trên câu trả lời xuất sắc này của 18446744073709551615 . Giải pháp của họ, mặc dù hữu ích, không kích thước biểu tượng hình ảnh bằng văn bản xung quanh. Nó cũng không đặt màu biểu tượng thành màu của văn bản xung quanh.

Giải pháp dưới đây có một biểu tượng hình vuông, màu trắng và làm cho nó phù hợp với kích thước và màu sắc của văn bản xung quanh.

public class TextViewWithImages extends TextView {

    private static final String DRAWABLE = "drawable";
    /**
     * Regex pattern that looks for embedded images of the format: [img src=imageName/]
     */
    public static final String PATTERN = "\\Q[img src=\\E([a-zA-Z0-9_]+?)\\Q/]\\E";

    public TextViewWithImages(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public TextViewWithImages(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TextViewWithImages(Context context) {
        super(context);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        final Spannable spannable = getTextWithImages(getContext(), text, getLineHeight(), getCurrentTextColor());
        super.setText(spannable, BufferType.SPANNABLE);
    }

    private static Spannable getTextWithImages(Context context, CharSequence text, int lineHeight, int colour) {
        final Spannable spannable = Spannable.Factory.getInstance().newSpannable(text);
        addImages(context, spannable, lineHeight, colour);
        return spannable;
    }

    private static boolean addImages(Context context, Spannable spannable, int lineHeight, int colour) {
        final Pattern refImg = Pattern.compile(PATTERN);
        boolean hasChanges = false;

        final Matcher matcher = refImg.matcher(spannable);
        while (matcher.find()) {
            boolean set = true;
            for (ImageSpan span : spannable.getSpans(matcher.start(), matcher.end(), ImageSpan.class)) {
                if (spannable.getSpanStart(span) >= matcher.start()
                        && spannable.getSpanEnd(span) <= matcher.end()) {
                    spannable.removeSpan(span);
                } else {
                    set = false;
                    break;
                }
            }
            final String resName = spannable.subSequence(matcher.start(1), matcher.end(1)).toString().trim();
            final int id = context.getResources().getIdentifier(resName, DRAWABLE, context.getPackageName());
            if (set) {
                hasChanges = true;
                spannable.setSpan(makeImageSpan(context, id, lineHeight, colour),
                        matcher.start(),
                        matcher.end(),
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                );
            }
        }
        return hasChanges;
    }

    /**
     * Create an ImageSpan for the given icon drawable. This also sets the image size and colour.
     * Works best with a white, square icon because of the colouring and resizing.
     *
     * @param context       The Android Context.
     * @param drawableResId A drawable resource Id.
     * @param size          The desired size (i.e. width and height) of the image icon in pixels.
     *                      Use the lineHeight of the TextView to make the image inline with the
     *                      surrounding text.
     * @param colour        The colour (careful: NOT a resource Id) to apply to the image.
     * @return An ImageSpan, aligned with the bottom of the text.
     */
    private static ImageSpan makeImageSpan(Context context, int drawableResId, int size, int colour) {
        final Drawable drawable = context.getResources().getDrawable(drawableResId);
        drawable.mutate();
        drawable.setColorFilter(colour, PorterDuff.Mode.MULTIPLY);
        drawable.setBounds(0, 0, size, size);
        return new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
    }

}

Cách sử dụng:

Chỉ cần nhúng tham chiếu đến các biểu tượng mong muốn trong văn bản. Không quan trọng là văn bản được đặt theo chương trình thông qua textView.setText(R.string.string_resource);hay nếu nó được đặt trong xml.

Để nhúng một biểu tượng drawable tên example.png, bao gồm các chuỗi sau đây trong văn bản: [img src=example/].

Ví dụ: một tài nguyên chuỗi có thể trông như thế này:

<string name="string_resource">This [img src=example/] is an icon.</string>

3
Đây là một giải pháp tốt. Tôi chỉ đề xuất một cải tiến: thêm drawable.mutate () trước drawable.setColorFilter; nếu không làm như vậy, bạn sẽ có thể vẽ với màu khác trong các phần khác của ứng dụng.
moondroid

@moondroid Cảm ơn bạn đã gợi ý, tôi đã chỉnh sửa câu trả lời cho phù hợp.
Phục hồi Monica

Trên thực tế tôi đã có một vấn đề, bởi vì drawable của tôi không phải là hình vuông, và giải pháp này sẽ luôn luôn làm cho chiều rộng drawable cùng với chiều cao drawable, nó sẽ thay đổi kích thước drawable tôi unproportionally
HendraWD

1

Điều này một phần dựa trên câu trả lời trước đó của @A Boschman ở trên . Trong giải pháp đó, tôi thấy rằng kích thước đầu vào của hình ảnh ảnh hưởng rất nhiều đến khả năng makeImageSpan()căn giữa hình ảnh đúng cách. Ngoài ra, tôi thấy rằng giải pháp ảnh hưởng đến khoảng cách văn bản bằng cách tạo ra khoảng cách dòng không cần thiết.

Tôi thấy BaseImageSpan (từ thư viện Fresco của Facebook) thực hiện công việc đặc biệt tốt:

 /**
 * Create an ImageSpan for the given icon drawable. This also sets the image size. Works best
 * with a square icon because of the sizing
 *
 * @param context       The Android Context.
 * @param drawableResId A drawable resource Id.
 * @param size          The desired size (i.e. width and height) of the image icon in pixels.
 *                      Use the lineHeight of the TextView to make the image inline with the
 *                      surrounding text.
 * @return An ImageSpan, aligned with the bottom of the text.
 */
private static BetterImageSpan makeImageSpan(Context context, int drawableResId, int size) {
    final Drawable drawable = context.getResources().getDrawable(drawableResId);
    drawable.mutate();
    drawable.setBounds(0, 0, size, size);
    return new BetterImageSpan(drawable, BetterImageSpan.ALIGN_CENTER);
}

Sau đó cung cấp phiên bản goodImageSpan của bạn spannable.setSpan()như bình thường


0

Điều này có thể giúp bạn

  SpannableStringBuilder ssBuilder;

        ssBuilder = new SpannableStringBuilder(" ");
        // working code ImageSpan image = new ImageSpan(textView.getContext(), R.drawable.image);
        Drawable image = ContextCompat.getDrawable(textView.getContext(), R.drawable.image);
        float scale = textView.getContext().getResources().getDisplayMetrics().density;
        int width = (int) (12 * scale + 0.5f);
        int height = (int) (18 * scale + 0.5f);
        image.setBounds(0, 0, width, height);
        ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BASELINE);
        ssBuilder.setSpan(
                imageSpan, // Span to add
                0, // Start of the span (inclusive)
                1, // End of the span (exclusive)
                Spanned.SPAN_INCLUSIVE_EXCLUSIVE);// Do not extend the span when text add later

        ssBuilder.append(" " + text);
        ssBuilder = new SpannableStringBuilder(text);
        textView.setText(ssBuilder);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.