Как установить часть текстового представления кликабельна

У меня есть текст & quot;Android is a Software stack& Quot ;. В этом тексте я хочу установить & quot;stack& Quot; текст кликабелен. в том случае, если вы нажмете на него, он будет перенаправлен на новое действие (не в браузере).

Я пытался, но я не получаю.

 Rashmi.B22 мая 2012 г., 08:54
& quot; Я пытался, но не получаю & quot; Я хотел бы знать, что вы пытались и где вы потерпели неудачу

Ответы на вопрос(13)

Для смелых,

mySpannable.setSpan(new StyleSpan(Typeface.BOLD),termStart,termStop,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

Моя функция для создания нескольких ссылок внутриTextView

public void makeLinks(TextView textView, String[] links, ClickableSpan[] clickableSpans) {
    SpannableString spannableString = new SpannableString(textView.getText());
    for (int i = 0; i < links.length; i++) {
        ClickableSpan clickableSpan = clickableSpans[i];
        String link = links[i];

        int startIndexOfLink = textView.getText().toString().indexOf(link);
        spannableString.setSpan(clickableSpan, startIndexOfLink,
                startIndexOfLink + link.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
    textView.setHighlightColor(
            Color.TRANSPARENT); // prevent TextView change background when highlight
    textView.setMovementMethod(LinkMovementMethod.getInstance());
    textView.setText(spannableString, TextView.BufferType.SPANNABLE);
}

USING

textView.setLinkTextColor(Color.BLUE); // default link color for clickable span, we can also set it in xml by android:textColorLink=""
ClickableSpan normalLinkClickSpan = new ClickableSpan() {
    @Override
    public void onClick(View view) {
        Toast.makeText(getApplicationContext(), "Normal Link", Toast.LENGTH_SHORT).show();
    }

};

ClickableSpan noUnderLineClickSpan = new ClickableSpan() {
    @Override
    public void onClick(View view) {
        Toast.makeText(getApplicationContext(), "NoUnderLine Link", Toast.LENGTH_SHORT)
                .show();
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        super.updateDrawState(ds);
        ds.setUnderlineText(false);
        ds.setColor(Color.MAGENTA); // specific color for this link
    }
};

ClickableSpan highlightClickSpan = new ClickableSpan() {
    @Override
    public void onClick(View view) {
        Toast.makeText(getApplicationContext(), "Highlight Link", Toast.LENGTH_SHORT)
                .show();
        view.invalidate(); // need put invalidate here to make text change to GREEN after clicked
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setUnderlineText(false);
        if (textView.isPressed() && textView.getSelectionStart() != -1 && textView.getText()
                    .toString()
                    .substring(textView.getSelectionStart(), textView.getSelectionEnd())
                    .equals("Highlight Link")) {
                ds.setColor(Color.RED); // need put invalidate here to make text change to RED when pressed on Highlight Link                    textView.invalidate();
            } else {
                ds.setColor(Color.GREEN);
            }
            // dont put invalidate here because if you put invalidate here `updateDrawState` will called forever
    }
};

makeLinks(textView, new String[] {
        "Normal Link", "NoUnderLine Link", "Highlight Link"
}, new ClickableSpan[] {
        normalLinkClickSpan, noUnderLineClickSpan, highlightClickSpan
});

XML

<TextView
    android:id="@+id/myText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Please read Normal Link and NoUnderLine Link and Highlight Link"
    android:textSize="30sp"
    />

enter image description here

 03 окт. 2018 г., 10:18
Работает отлично. Но есть что-то странное в поведении. У меня есть текст, оканчивающийся на "Политика". Где "." будет пропущен Clickable Spanable. У кого-нибудь была такая же проблема? & Quot;. & Quot; пропускается, только если это конечный символ текстового представления.
 18 дек. 2018 г., 09:47
отличное решение, но кто-то должен позаботиться, если есть локализация (многоязычное приложение) строк
Решение Вопроса

android.text.style.ClickableSpan может решить вашу проблему.

SpannableString ss = new SpannableString("Android is a Software stack");
ClickableSpan clickableSpan = new ClickableSpan() {
    @Override
    public void onClick(View textView) {
        startActivity(new Intent(MyActivity.this, NextActivity.class));
    }
    @Override
    public void updateDrawState(TextPaint ds) {
        super.updateDrawState(ds);
        ds.setUnderlineText(false);
    }
};
ss.setSpan(clickableSpan, 22, 27, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

TextView textView = (TextView) findViewById(R.id.hello);
textView.setText(ss);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setHighlightColor(Color.TRANSPARENT);

// В XML: TextView: android: textColorLink = & quot; @ drawable / your_selector & quot;

 19 янв. 2015 г., 07:48
как изменить цвет с синего на любой другой цвет ???
 17 февр. 2015 г., 12:54
Чтобы изменить цвет на синий, вы можете добавить:ForegroundColorSpan fcs = new ForegroundColorSpan(Color.BLUE); ss.setSpan(fcs, 22, 27, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
 23 июл. 2015 г., 08:13
Это произошло в моем случае, чтобы изменить цвет с синего на какой-то другой. ЗадаватьForegroundColorSpan вsetSpan after Вы установили кликабельный интервал. При размещении переднего плана перед кликабельным промежутком новый цвет не будет отображаться.
 07 окт. 2013 г., 15:56
Да, вы можете установить несколько кликабельных интервалов в разделяемую строку.
 16 июн. 2014 г., 06:58
и добавьте эту строку в TextView android: clickable = & quot; true & quot; ..

Я бы предложил другой подход, который, на мой взгляд, требует меньше кода и является более «дружественным к локализации».

Предположим, что ваше целевое действие называется «ActivityStack», определите в манифесте фильтр намерений для него с помощью пользовательской схемы (например, «myappscheme») в AndroidManifest.xml:

<activity
    android:name=".ActivityStack">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:host="stack"/>
        <data android:scheme="myappscheme" />
    </intent-filter>
</activity>

Определите TextView без какого-либо специального тега (важно НЕ использовать тег & quot; android: autoLink & quot; см.https://stackoverflow.com/a/20647011/1699702):

<TextView
    android:id="@+id/stackView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/stack_string" />

затем используйте ссылку с пользовательской схемой и хостом в тексте TextView как (в String.xml):

<string name="stack_string">Android is a Software <a href="myappscheme://stack">stack</a></string>

и & quot; активировать & quot; ссылка с setMovementMethod () (в onCreate () для действий или onCreateView () для фрагментов):

TextView stack = findViewById(R.id.stackView);
stack.setMovementMethod(LinkMovementMethod.getInstance());

Это откроет активность стека нажатием на «стек» слово.

Kotlin Version от ответа Фан Ван Линха.

Please note it has some minor modifications.

fun makeLinks(textView: TextView, links: Array<String>, clickableSpans: Array<ClickableSpan>) {
    val spannableString = SpannableString(textView.text)

    for (i in links.indices) {
        val clickableSpan = clickableSpans[i]
        val link = links[i]

        val startIndexOfLink = textView.text.indexOf(link)

        spannableString.setSpan(clickableSpan, startIndexOfLink, startIndexOfLink + link.length,
                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
    }

    textView.movementMethod = LinkMovementMethod.getInstance()
    textView.setText(spannableString, TextView.BufferType.SPANNABLE)
}

fun setupClickableTextView() {
    val termsOfServicesClick = object : ClickableSpan() {
        override fun onClick(p0: View?) {
            Toast.makeText(applicationContext, "ToS clicked", Toast.LENGTH_SHORT).show()
        }
    }

    val privacyPolicyClick = object : ClickableSpan() {
        override fun onClick(p0: View?) {
            Toast.makeText(applicationContext, "PP clicked", Toast.LENGTH_SHORT).show()
        }
    }

    makeLinks(termsTextView, arrayOf("terms", "privacy policy"), arrayOf(termsOfServicesClick, privacyPolicyClick))
}

Я сделал этот вспомогательный метод на случай, если кому-то понадобится начальная и конечная позиции из строки.

public static TextView createLink(TextView targetTextView, String completeString,
    String partToClick, ClickableSpan clickableAction) {

    SpannableString spannableString = new SpannableString(completeString);

    // make sure the String is exist, if it doesn't exist
    // it will throw IndexOutOfBoundException
    int startPosition = completeString.indexOf(partToClick);
    int endPosition = completeString.lastIndexOf(partToClick) + partToClick.length();

    spannableString.setSpan(clickableAction, startPosition, endPosition,
        Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

    targetTextView.setText(spannableString);
    targetTextView.setMovementMethod(LinkMovementMethod.getInstance());

    return targetTextView;
}

А вот как вы это используете

private void initSignUp() {
    String completeString = "New to Reddit? Sign up here.";
    String partToClick = "Sign up";
    ClickableTextUtil
        .createLink(signUpEditText, completeString, partToClick,
            new ClickableSpan() {
                @Override
                public void onClick(View widget) {
                    // your action
                    Toast.makeText(activity, "Start Sign up activity",
                        Toast.LENGTH_SHORT).show();
                }

                @Override
                public void updateDrawState(TextPaint ds) {
                    super.updateDrawState(ds);
                    // this is where you set link color, underline, typeface etc.
                    int linkColor = ContextCompat.getColor(activity, R.color.blumine);
                    ds.setColor(linkColor);
                    ds.setUnderlineText(false);
                }
            });
}
 27 сент. 2018 г., 10:00
Это лучше, так как принимает во внимание локализацию

Ты можешь использоватьClickableSpan как описано в этомсообщение

Sample code:
TextView myTextView = new TextView(this);
String myString = "Some text [clickable]";
int i1 = myString.indexOf("[");
int i2 = myString.indexOf("]");
myTextView.setMovementMethod(LinkMovementMethod.getInstance());
myTextView.setText(myString, BufferType.SPANNABLE);
Spannable mySpannable = (Spannable)myTextView.getText();
ClickableSpan myClickableSpan = new ClickableSpan() {
   @Override
   public void onClick(View widget) { /* do something */ }
};
mySpannable.setSpan(myClickableSpan, i1, i2 + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

Ссылка

 t= (TextView) findViewById(R.id.PP1);

 t.setText(Html.fromHtml("<bThis is normal text </b>" +
                "<a href=\"http://www.xyz-zyyx.com\">This is cliclable text</a> "));
 t.setMovementMethod(LinkMovementMethod.getInstance());
 29 апр. 2013 г., 14:28
Можете ли вы объяснить свой ответ. Отвечать с объяснениями всегда лучше. Я также отредактировал, поскольку ваш фрагмент кода был не все в правильном формате.
 20 авг. 2013 г., 20:32
Похоже, что ссылка будет на веб-страницу, а не на действие, запрошенное OP.

Вы можете использовать пример кода. Вы хотите узнать подробнее о ClickableSpan. пожалуйста, проверьтеthis documentaion

  SpannableString myString = new SpannableString("This is example");

            ClickableSpan clickableSpan = new ClickableSpan() {
                    @Override
                    public void onClick(View textView) {
                        ToastUtil.show(getContext(),"Clicked Smile ");
                    }
                };

        //For Click
         myString.setSpan(clickableSpan,startIndex,lastIndex,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

        //For UnderLine
         myString.setSpan(new UnderlineSpan(),startIndex,lastIndex,0);

        //For Bold
        myString.setSpan(new StyleSpan(Typeface.BOLD),startIndex,lastIndex,0);

        //Finally you can set to textView. 

        TextView textView = (TextView) findViewById(R.id.txtSpan);
        textView.setText(myString);
        textView.setMovementMethod(LinkMovementMethod.getInstance());

Вы можете этот метод, чтобы установить кликабельное значение

public void setClickableString(String clickableValue, String wholeValue, TextView yourTextView){
    String value = wholeValue;
    SpannableString spannableString = new SpannableString(value);
    int startIndex = value.indexOf(clickableValue);
    int endIndex = startIndex + clickableValue.length();
    spannableString.setSpan(new ClickableSpan() {
                                @Override
                                public void updateDrawState(TextPaint ds) {
                                    super.updateDrawState(ds);
                                    ds.setUnderlineText(false); // <-- this will remove automatic underline in set span
                                }

                                @Override
                                public void onClick(View widget) {
                                    // do what you want with clickable value
                                }
                            }, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    yourTextView.setText(spannableString);
    yourTextView.setMovementMethod(LinkMovementMethod.getInstance()); // <-- important, onClick in ClickableSpan won't work without this
}

Вот как это использовать:

TextView myTextView = findViewById(R.id.myTextView);
setClickableString("stack", "Android is a Software stack", myTextView);

ВотKotlin метод, чтобы сделать частиTextView кликабельны:

private fun makeTextLink(textView: TextView, str: String, underlined: Boolean, color: Int?, action: (() -> Unit)? = null) {
    val spannableString = SpannableString(textView.text)
    val textColor = color ?: textView.currentTextColor
    val clickableSpan = object : ClickableSpan() {
        override fun onClick(textView: View) {
            action?.invoke()
        }
        override fun updateDrawState(drawState: TextPaint) {
            super.updateDrawState(drawState)
            drawState.isUnderlineText = underlined
            drawState.color = textColor
        }
    }
    val index = spannableString.indexOf(str)
    spannableString.setSpan(clickableSpan, index, index + str.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
    textView.text = spannableString
    textView.movementMethod = LinkMovementMethod.getInstance()
    textView.highlightColor = Color.TRANSPARENT
}

Его можно вызывать несколько раз, чтобы создать несколько ссылок в TextView:

makeTextLink(myTextView, str, false, Color.RED, action = { Log.d("onClick", "link") })
makeTextLink(myTextView, str1, true, null, action = { Log.d("onClick", "link1") })

Это моеMovementMethod для обнаружения ссылок / текста / изображения кликов. МодифицированоLinkMovementMethod.

import android.text.Layout;
import android.text.NoCopySpan;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.ScrollingMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.ImageSpan;
import android.text.style.URLSpan;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

public class ClickMovementMethod extends ScrollingMovementMethod {
private Object FROM_BELOW = new NoCopySpan.Concrete();

private static final int CLICK = 1;
private static final int UP = 2;
private static final int DOWN = 3;

private Listener listener;

public void setListener(Listener listener) {
    this.listener = listener;
}

@Override
public boolean canSelectArbitrarily() {
    return true;
}

@Override
protected boolean handleMovementKey(TextView widget, Spannable buffer, int keyCode,
                                    int movementMetaState, KeyEvent event) {
    switch (keyCode) {
        case KeyEvent.KEYCODE_DPAD_CENTER:
        case KeyEvent.KEYCODE_ENTER:
            if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
                if (event.getAction() == KeyEvent.ACTION_DOWN &&
                        event.getRepeatCount() == 0 && action(CLICK, widget, buffer)) {
                    return true;
                }
            }
            break;
    }
    return super.handleMovementKey(widget, buffer, keyCode, movementMetaState, event);
}

@Override
protected boolean up(TextView widget, Spannable buffer) {
    if (action(UP, widget, buffer)) {
        return true;
    }

    return super.up(widget, buffer);
}

@Override
protected boolean down(TextView widget, Spannable buffer) {
    if (action(DOWN, widget, buffer)) {
        return true;
    }

    return super.down(widget, buffer);
}

@Override
protected boolean left(TextView widget, Spannable buffer) {
    if (action(UP, widget, buffer)) {
        return true;
    }

    return super.left(widget, buffer);
}

@Override
protected boolean right(TextView widget, Spannable buffer) {
    if (action(DOWN, widget, buffer)) {
        return true;
    }

    return super.right(widget, buffer);
}

private boolean action(int what, TextView widget, Spannable buffer) {
    Layout layout = widget.getLayout();

    int padding = widget.getTotalPaddingTop() +
            widget.getTotalPaddingBottom();
    int areatop = widget.getScrollY();
    int areabot = areatop + widget.getHeight() - padding;

    int linetop = layout.getLineForVertical(areatop);
    int linebot = layout.getLineForVertical(areabot);

    int first = layout.getLineStart(linetop);
    int last = layout.getLineEnd(linebot);

    ClickableSpan[] candidates = buffer.getSpans(first, last, URLSpan.class);

    int a = Selection.getSelectionStart(buffer);
    int b = Selection.getSelectionEnd(buffer);

    int selStart = Math.min(a, b);
    int selEnd = Math.max(a, b);

    if (selStart < 0) {
        if (buffer.getSpanStart(FROM_BELOW) >= 0) {
            selStart = selEnd = buffer.length();
        }
    }

    if (selStart > last)
        selStart = selEnd = Integer.MAX_VALUE;
    if (selEnd < first)
        selStart = selEnd = -1;

    switch (what) {
        case CLICK:
            if (selStart == selEnd) {
                return false;
            }

            if (listener != null) {
                URLSpan[] link = buffer.getSpans(selStart, selEnd, URLSpan.class);
                if (link.length >= 1) {
                    listener.onClick(link[0].getURL());
                } else {
                    ImageSpan[] image = buffer.getSpans(selStart, selEnd, ImageSpan.class);
                    if (image.length >= 1) {
                        listener.onImageClicked(image[0].getSource());
                    } else {
                        listener.onTextClicked();
                    }
                }
            }
            break;

        case UP:
            int beststart, bestend;

            beststart = -1;
            bestend = -1;

            for (int i = 0; i < candidates.length; i++) {
                int end = buffer.getSpanEnd(candidates[i]);

                if (end < selEnd || selStart == selEnd) {
                    if (end > bestend) {
                        beststart = buffer.getSpanStart(candidates[i]);
                        bestend = end;
                    }
                }
            }

            if (beststart >= 0) {
                Selection.setSelection(buffer, bestend, beststart);
                return true;
            }

            break;

        case DOWN:
            beststart = Integer.MAX_VALUE;
            bestend = Integer.MAX_VALUE;

            for (int i = 0; i < candidates.length; i++) {
                int start = buffer.getSpanStart(candidates[i]);

                if (start > selStart || selStart == selEnd) {
                    if (start < beststart) {
                        beststart = start;
                        bestend = buffer.getSpanEnd(candidates[i]);
                    }
                }
            }

            if (bestend < Integer.MAX_VALUE) {
                Selection.setSelection(buffer, beststart, bestend);
                return true;
            }

            break;
    }

    return false;
}

@Override
public boolean onTouchEvent(TextView widget, Spannable buffer,
                            MotionEvent event) {
    int action = event.getAction();

    if (action == MotionEvent.ACTION_UP ||
            action == MotionEvent.ACTION_DOWN) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        x -= widget.getTotalPaddingLeft();
        y -= widget.getTotalPaddingTop();

        x += widget.getScrollX();
        y += widget.getScrollY();

        Layout layout = widget.getLayout();
        int line = layout.getLineForVertical(y);
        int off = layout.getOffsetForHorizontal(line, x);

        URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);

        if (action == MotionEvent.ACTION_UP) {
            if (listener != null) {
                if (link.length >= 1) {
                    listener.onClick(link[0].getURL());
                } else {
                    ImageSpan[] image = buffer.getSpans(off, off, ImageSpan.class);
                    if (image.length >= 1) {
                        listener.onImageClicked(image[0].getSource());
                    } else if (Selection.getSelectionStart(buffer) == Selection.getSelectionEnd(buffer)) {
                        listener.onTextClicked();
                    }
                }
            }
        }

        if (action == MotionEvent.ACTION_DOWN && link.length != 0) {
            Selection.setSelection(buffer,
                    buffer.getSpanStart(link[0]),
                    buffer.getSpanEnd(link[0]));
            return true;
        }

        if (link.length == 0) {
            Selection.removeSelection(buffer);
        }
    }

    return super.onTouchEvent(widget, buffer, event);
}

@Override
public void initialize(TextView widget, Spannable text) {
    Selection.removeSelection(text);
    text.removeSpan(FROM_BELOW);
}

@Override
public void onTakeFocus(TextView view, Spannable text, int dir) {
    Selection.removeSelection(text);

    if ((dir & View.FOCUS_BACKWARD) != 0) {
        text.setSpan(FROM_BELOW, 0, 0, Spannable.SPAN_POINT_POINT);
    } else {
        text.removeSpan(FROM_BELOW);
    }
}

public interface Listener {

    void onClick(String clicked);

    void onTextClicked();

    void onImageClicked(String source);

}

}

Это действительно полезно для кликабельной части некоторой части текста.

Точка - это специальный символ в регулярном выражении. Если вы хотите растянуть точку, вам нужно экранировать точку как\\, вместо того, чтобы просто пропустить & quot;.& Quot; к методу разделяемого текста. Кроме того, вы также можете использовать регулярное выражение[.] разделить строку на точку в Java.

Ваш ответ на вопрос