Intereting Posts
URL-адреса Android-рынка Исключение с веб-службой (исключение java.net.SocketException Permission denied) в Android Запрос AJAX с Android-телефона Phonegap Обновление фрагмента ListView, когда он не сфокусирован Как получить String Resource в адаптере ViewPager? Проблема с обновлением представления строки в recycliewiew Как зарегистрировать приемник для захвата завершенной загрузки? Launcher + singleTask активность в Android Преимущество использования одиночного TableLayout вместо нескольких LinearLayouts, поскольку TableRow расширяет только LinearLayout Запись скринкаста приложения для Android с использованием эмулятора Ошибка в файле styles_base.xml – приложение для Android – Ресурс не найден, который соответствует указанному имени 'android: Widget.Material.ActionButton' Скрыть MenuItem в некоторых фрагментах Ограничения установки APK за пределами Google Store Android Proguard ZipException при создании подписанного APK Храните сервис, даже если приложение закрыто.

Как щелкнуть clickablespan с помощью эспрессо?

У меня есть текстовое окно с несколькими кликабельными промежутками. Я хочу иметь возможность проверить щелчок по этим промежуткам.

Я попытался настроить пользовательский ViewAction, который найдет области clickables в TextView, а затем сопоставляет их текст с нужным текстом, а затем нажимает на координаты xy этого текста. Тем не менее, кажется, что промежутки, добавленные в TextView, не относятся к типу ClickableSpan и вместо этого являются фрагментом, который добавил диапазон.

Поэтому я не могу отличить промежутки ссылок. Есть лучший способ сделать это?

Добавление интервалов:

Util.addClickableSpan(spannableString, string, linkedString, new ClickableSpan() { @Override public void onClick(View textView) {} }); tvAcceptTc.setText(spannableString); tvAcceptTc.setMovementMethod(LinkMovementMethod.getInstance()); 

Метод полезности:

 public static void addClickableSpan(SpannableString spannableString, String text, String subText, ClickableSpan clickableSpan) { int start = text.indexOf(subText); int end = text.indexOf(subText) + subText.length(); int flags = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; spannableString.setSpan(clickableSpan, start, end, flags); } 

Определение ViewAction:

 @Override public void perform(UiController uiController, View view) { uiController.loopMainThreadUntilIdle(); if (view instanceof TextView) { TextView textView = (TextView) view; Layout textViewLayout = textView.getLayout(); SpannableString fullSpannable = new SpannableString(textView.getText()); Object[] spans = fullSpannable.getSpans(0, fullSpannable.length(), Object.class); ClickableSpan span = null; for (Object object : spans) { if (object instanceof BaseFragment) { ClickableSpan foundSpan = (ClickableSpan)object; int spanStart = fullSpannable.getSpanStart(foundSpan); int spanEnd = fullSpannable.getSpanEnd(foundSpan); if (fullSpannable.subSequence(spanStart, spanEnd).equals(aSubstring)) { //Found the correct span! span = foundSpan; } } } ... go on to click the xy-coordinates 

    Это мое решение. Это проще, потому что нам не нужно находить координаты. Как только мы найдем ClickableSpan, мы просто нажимаем на него:

     public static ViewAction clickClickableSpan(final CharSequence textToClick) { return new ViewAction() { @Override public Matcher<View> getConstraints() { return Matchers.instanceOf(TextView.class); } @Override public String getDescription() { return "clicking on a ClickableSpan"; } @Override public void perform(UiController uiController, View view) { TextView textView = (TextView) view; SpannableString spannableString = (SpannableString) textView.getText(); if (spannableString.length() == 0) { // TextView is empty, nothing to do throw new NoMatchingViewException.Builder() .includeViewHierarchy(true) .withRootView(textView) .build(); } // Get the links inside the TextView and check if we find textToClick ClickableSpan[] spans = spannableString.getSpans(0, spannableString.length(), ClickableSpan.class); if (spans.length > 0) { ClickableSpan spanCandidate; for (ClickableSpan span : spans) { spanCandidate = span; int start = spannableString.getSpanStart(spanCandidate); int end = spannableString.getSpanEnd(spanCandidate); CharSequence sequence = spannableString.subSequence(start, end); if (textToClick.toString().equals(sequence.toString())) { span.onClick(textView); return; } } } // textToClick not found in TextView throw new NoMatchingViewException.Builder() .includeViewHierarchy(true) .withRootView(textView) .build(); } }; } 

    Теперь вы можете использовать наш пользовательский ViewAction так:

      onView(withId(R.id.myTextView)).perform(clickClickableSpan("myLink")); 

    Это работает для меня:

     /** * Clicks the first ClickableSpan in the TextView */ public static ViewAction clickFirstClickableSpan() { return new GeneralClickAction( Tap.SINGLE, new CoordinatesProvider() { @Override public float[] calculateCoordinates(View view) { //https://leons.im/posts/how-to-get-coordinate-of-a-clickablespan-inside-a-textview/ TextView textView = (TextView) view; Rect parentTextViewRect = new Rect(); SpannableString spannableString = (SpannableString) textView.getText(); Layout textViewLayout = textView.getLayout(); ClickableSpan spanToLocate = null; if (spannableString.length() == 0) { return new float[2]; } ClickableSpan[] spans = spannableString.getSpans(0, spannableString.length(), ClickableSpan.class); if (spans.length > 0) { spanToLocate = spans[0]; } if (spanToLocate == null) { // no specific view found throw new NoMatchingViewException.Builder() .includeViewHierarchy(true) .withRootView(textView) .build(); } double startOffsetOfClickedText = spannableString.getSpanStart(spanToLocate); double endOffsetOfClickedText = spannableString.getSpanEnd(spanToLocate); double startXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal((int) startOffsetOfClickedText); double endXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal((int) endOffsetOfClickedText); // Get the rectangle of the clicked text int currentLineStartOffset = textViewLayout.getLineForOffset((int) startOffsetOfClickedText); int currentLineEndOffset = textViewLayout.getLineForOffset((int) endOffsetOfClickedText); boolean keywordIsInMultiLine = currentLineStartOffset != currentLineEndOffset; textViewLayout.getLineBounds(currentLineStartOffset, parentTextViewRect); // Update the rectangle position to his real position on screen int[] parentTextViewLocation = {0, 0}; textView.getLocationOnScreen(parentTextViewLocation); double parentTextViewTopAndBottomOffset = ( parentTextViewLocation[1] - textView.getScrollY() + textView.getCompoundPaddingTop() ); parentTextViewRect.top += parentTextViewTopAndBottomOffset; parentTextViewRect.bottom += parentTextViewTopAndBottomOffset; parentTextViewRect.left += ( parentTextViewLocation[0] + startXCoordinatesOfClickedText + textView.getCompoundPaddingLeft() - textView.getScrollX() ); parentTextViewRect.right = (int) ( parentTextViewRect.left + endXCoordinatesOfClickedText - startXCoordinatesOfClickedText ); int screenX = (parentTextViewRect.left + parentTextViewRect.right) / 2; int screenY = (parentTextViewRect.top + parentTextViewRect.bottom) / 2; if (keywordIsInMultiLine) { screenX = parentTextViewRect.left; screenY = parentTextViewRect.top; } return new float[]{screenX, screenY}; } }, Press.FINGER); } 

    Вы можете использовать Spannable вместо SpannableString совместимый с SpannableStringBuilder .

    Извините, я новый человек, имею только 1 репутацию, не могу добавить комментарий. Даже мой английский очень плохой …..

    Я предлагаю использовать:

     Spannable spannableString = (Spannable) textView.getText(); 

    вместо :

     SpannableString spannableString = (SpannableString) textView.getText(); 

    Разместите весь код ниже:

     public class CustomViewActions { /** * click specific spannableString */ public static ViewAction clickClickableSpan(final CharSequence textToClick) { return clickClickableSpan(-1, textToClick); } /** * click the first spannableString */ public static ViewAction clickClickableSpan() { return clickClickableSpan(0, null); } /** * click the nth spannableString */ public static ViewAction clickClickableSpan(final int index) { return clickClickableSpan(index, null); } public static ViewAction clickClickableSpan(final int index,final CharSequence textToClick) { return new ViewAction() { @Override public Matcher<View> getConstraints() { return instanceOf(TextView.class); } @Override public String getDescription() { return "clicking on a ClickableSpan"; } @Override public void perform(UiController uiController, View view) { TextView textView = (TextView) view; Spannable spannableString = (Spannable) textView.getText(); ClickableSpan spanToLocate = null; if (spannableString.length() == 0) { // TextView is empty, nothing to do throw new NoMatchingViewException.Builder() .includeViewHierarchy(true) .withRootView(textView) .build(); } // Get the links inside the TextView and check if we find textToClick ClickableSpan[] spans = spannableString.getSpans(0, spannableString.length(), ClickableSpan.class); if (spans.length > 0) { if(index >=spans.length){ throw new NoMatchingViewException.Builder() .includeViewHierarchy(true) .withRootView(textView) .build(); }else if (index >= 0) { spanToLocate = spans[index]; spanToLocate.onClick(textView); return; } for (int i = 0; i < spans.length; i++) { int start = spannableString.getSpanStart(spans[i]); int end = spannableString.getSpanEnd(spans[i]); CharSequence sequence = spannableString.subSequence(start, end); if (textToClick.toString().equals(sequence.toString())) { spanToLocate = spans[i]; spanToLocate.onClick(textView); return; } } } // textToClick not found in TextView throw new NoMatchingViewException.Builder() .includeViewHierarchy(true) .withRootView(textView) .build(); } }; } }