Пользовательский URLSpan не запускает событие onClick, используя kotlin [duplicate]

Здесь есть замечательные ответы на эти вопросы, которые вовлекают во всевозможные подробные сведения о интерфейсах и слабосвязанный код, инверсию управления и т. д. Есть несколько довольно острых дискуссий, поэтому я хотел бы воспользоваться возможностью немного разобраться в том, почему интерфейс полезен.

Когда я впервые начал работать с интерфейсами, я тоже был смущен об их значимости. Я не понимал, зачем вам это нужно. Если мы используем такой язык, как Java или C #, у нас уже есть наследование, и я рассматривал интерфейсы как более слабую форму наследования и мысли «зачем беспокоиться»? В некотором смысле я был прав, вы можете думать о интерфейсах как о какой-то слабой форме наследования, но помимо этого я, наконец, понял их использование в качестве языковой конструкции, считая их как средство классификации общих черт или моделей поведения, которые были представлены потенциально много несвязанных классов объектов.

Например, скажем, у вас есть игра с SIM-картой, и у вас есть следующие классы:

 class HouseFly inherits Insect {
   void FlyAroundYourHead(){}
   void LandOnThings(){}
 }

 class Telemarketer inherits Person {
   void CallDuringDinner(){}
   void ContinueTalkingWhenYouSayNo(){}
 }

Очевидно, что эти два объекта не имеют ничего в общий с точки зрения прямого наследования. Но вы могли бы сказать, что они оба раздражают.

Предположим, что в нашей игре должно быть какое-то случайное вещь , которая раздражает игрока, когда они едят обед. Это могут быть HouseFly или Telemarketer или оба, но как вы можете использовать обе функции с одной функцией? И как вы просите каждый из разных типов объектов «делать свою раздражающую вещь» таким же образом?

Ключом к пониманию является то, что как Telemarketer, так и HouseFly имеют общее слабо интерпретируемое поведение даже несмотря на то, что они не имеют ничего общего с их моделированием. Итак, давайте создадим интерфейс, который оба могут реализовать:

 interface IPest {
    void BeAnnoying();
 }

 class HouseFly inherits Insect implements IPest {
   void FlyAroundYourHead(){}
   void LandOnThings(){}

   void BeAnnoying() {
     FlyAroundYourHead();
     LandOnThings();
   }
 }

 class Telemarketer inherits Person implements IPest {
   void CallDuringDinner(){}
   void ContinueTalkingWhenYouSayNo(){}

   void BeAnnoying() {
      CallDuringDinner();
      ContinueTalkingWhenYouSayNo();
   }
 }

Теперь у нас есть два класса, каждый из которых может раздражать по-своему. И им не нужно выводить из одного базового класса и обладать общими присущими характеристиками - им просто нужно удовлетворить контракт IPest - этот контракт прост. Вам просто нужно BeAnnoying. В этой связи мы можем моделировать следующее:

 class DiningRoom {

   DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

   void ServeDinner() {
     when diningPeople are eating,

       foreach pest in pests
         pest.BeAnnoying();
   }
 }

Здесь у нас есть столовая, в которой принимают несколько посетителей и несколько вредителей - обратите внимание на использование интерфейса. Это означает, что в нашем маленьком мире членом массива pests может быть объект Telemarketer или объект HouseFly.

Метод ServeDinner вызывается при подаче обеда и наши люди в столовой должны есть. В нашей маленькой игре, вот когда наши вредители выполняют свою работу - каждый вредитель инструктируется быть раздражающим через интерфейс IPest. Таким образом, мы с легкостью можем раздражать как Telemarketers, так и HouseFlys в каждом из своих способов - мы заботимся только о том, что у нас есть что-то в объекте DiningRoom, являющемся вредителем, нам все равно что это такое, и они не могли иметь ничего общего с другими.

Этот очень надуманный пример псевдокода (который тянулся намного дольше, чем я ожидал) просто предназначен для иллюстрации того, что, наконец, включило свет для меня с точки зрения того, когда мы могли бы использовать интерфейс. Я заранее извиняюсь за глупость примера, но надеюсь, что это поможет в вашем понимании. И, конечно же, другие опубликованные ответы, которые вы получили здесь, действительно охватывают диапазон использования интерфейсов сегодня в шаблонах проектирования и методологиях разработки.

1
задан Avinash Ravilla 18 August 2015 в 05:43
поделиться

2 ответа

Последний код, pls см. link form github

message.setSpan(span, start, end, flags);

Вам нужно удалить начальный интервал перед установкой нового интервала. См. Ниже Функция onClick () для ClickableSpan не работает для URLSpan?

РЕДАКТИРОВАТЬ Вы можете захватить любое событие клика по диапазону extends LinkMovementMethod

    import android.os.Handler;
import android.os.Message;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.widget.TextView;

import java.lang.ref.WeakReference;

public class LinkMovementMethodExt extends LinkMovementMethod {
    public static final int LinkMovementMethod_Down = 1001;
    public static final int LinkMovementMethod_Up = 2002;
    private static LinkMovementMethod sInstance;
    private Class mSpanClass = null;
    private WeakReference<Handler> mWeakReference = null;

    public static MovementMethod getInstance(Handler handler, Class spanClass) {
        if (sInstance == null) {
            sInstance = new LinkMovementMethodExt();
            ((LinkMovementMethodExt) sInstance).mWeakReference = new WeakReference<>(handler);
            ((LinkMovementMethodExt) sInstance).mSpanClass = spanClass;
        }
        return sInstance;
    }

    @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);
            /**
             * get you interest span
             */
            Object[] spans = buffer.getSpans(off, off, mSpanClass);
            if (spans.length != 0) {
                if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer, buffer.getSpanStart(spans[0]), buffer.getSpanEnd(spans[0]));
                    MessageSpan obj = new MessageSpan();
                    obj.setObj(spans);
                    obj.setView(widget);
                    Handler handler = mWeakReference.get();
                    if (handler != null) {
                        Message message = handler.obtainMessage();
                        message.obj = obj;
                        message.what = LinkMovementMethod_Down;
                        message.sendToTarget();
                        return true;
                    }
                    return false;
                } else if (action == MotionEvent.ACTION_UP) {
                    Handler handler = mWeakReference.get();
                    if (handler != null) {
                        MessageSpan obj = new MessageSpan();
                        obj.setView(widget);
                        Message message = handler.obtainMessage();
                        message.obj = obj;
                        message.what = LinkMovementMethod_Up;
                        message.sendToTarget();
                        return true;
                    }
                    return false;
                }
            }
        }

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

    public boolean canSelectArbitrarily() {
        return true;
    }

    public boolean onKeyUp(TextView widget, Spannable buffer, int keyCode,
                           KeyEvent event) {
        return false;
    }

textView.setMovementMethod (LinkMovementMethodExt.getInstance ());


Изменить для «разработчика Android». Это лучший способ добавить свойство Handler для класса LinkMovementMethodExt. Вы можете захватить все Spanned, которые поставляются как объект Message. Снайперский код в методе onTouchEvent:

Message message = Handler.obtainMessage();
message.obj = buffer.getSpans(off, off, Spanned.class);//get all spanned
message.what = 111;//which value ,it is up to you
message.sendToTarget(); //send message to you target handler

Вы можете обработать ожидаемое в вашем классе обработчика. Возможно, это гибкий способ обработки. Надеюсь помочь вам.


enter image description here [/g3]

Над текстом textview <a href='/a'>aaaa</a>123456<a href='/b'>bbbb</b>7890 Я понимаю ваше требование: нажмите «aaaa», вы хотите получить его s href value '/a', click 'bbbb',get it s href '/ b'; Не запускайте действие по умолчанию, которое открывается в веб-браузере. Если я правильно понимаю, вы можете сделать следующее:

  • Установить LinkMovementMethod для текстового просмотра и т. Д .: textview.setMovementMethod(LinkMovementMethodExt.getInstance(handler, URLSpan.class));
  • Получить процентный охват, вот URLSpan. В методе handler handleMessage вы можете сделать следующее:
private Handler handler = new Handler() {
      public void handleMessage(Message msg) {
          int what = msg.what;
          if (what == 100) {
              Object[] spans = (Object[])msg.obj;
              for (Object span : spans) {
                  if (span instanceof URLSpan) {
                      System.out.println(((URLSpan) span).getURL());
                  }
              }
          }
      };
  };

Загрузить демонстрационный код

  • Функция MainActivity имеет свойство цвета, которое вы можете назначить, какое значение цвета вы хотите.

Как это сделать?

  • Шаг1, получить текущий
  • Шаг 2, установите BackgroundColorSpan для текущего диапазона кликов
8
ответ дан boiledwater 23 August 2018 в 02:13
поделиться
  • 1
    это действительно хорошее решение. могу ли я настроить действие при нажатии на ссылку, но все же имеет тот же эффект нажатия на ссылку (вместо этого я использую ClickableSpan)? – android developer 3 September 2013 в 13:27
  • 2
    Разработчик @android, пожалуйста, отредактирован. – boiledwater 4 September 2013 в 09:31
  • 3
    я не понимаю. возможно я объясню лучше: предположим, у меня есть textView, который я установил текст из strings.xml, который имеет несколько ссылок внутри него. я хочу захватить щелчок по каждому из них, так что я буду обрабатывать то, что происходит дальше сам, вместо того, чтобы открывать намерение для веб-браузера. как бы я это сделал? – android developer 4 September 2013 в 10:40
  • 4
    Разработчик @android, я отредактировал сообщение. – boiledwater 5 September 2013 в 03:38
  • 5
    @androiddeveloper, я нажимаю последний код. изменить цвет фона ссылки на цвет по умолчанию (view.getLink Text Colors (). getDefault Color ()) – boiledwater 10 September 2013 в 06:53

Предполагая, что вы хотите щелкнуть отдельные слова в текстовом виде ?. Я не понимаю, как конвертирует все буквы в слова в вашем комментарии.

Ниже можно использовать щелчок по отдельным работам, и он отображается в тосте.

    public class MainActivity extends Activity {

    TextView _tv;
    String[] each;
    SpannableString ss1;
    Button b;
    EditText et;
    String s;
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    b= (Button) findViewById(R.id.button1);
    et = (EditText) findViewById(R.id.ed);
    _tv = (TextView) findViewById( R.id.tv );
    b.setOnClickListener(new OnClickListener()
    {

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        s=et.getText().toString();
        _tv.setText("");
        for(int i=0;i<s.length();i++)
        {
            each = s.split("\\s+");
        }
        for(int i=0;i<each.length;i++)
        {
            System.out.println("................"+each[i]);
            ss1=  new SpannableString(each[i]);
            //StyleSpan boldSpan = new StyleSpan( Typeface.BOLD );
            //spannable.setSpan( boldSpan, 41, 52, Spannable.SPAN_INCLUSIVE_INCLUSIVE );
            ss1.setSpan(new MyClickableSpan(each[i]), 0, ss1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            _tv.append(ss1); 
            _tv.append(" "); 

        }
        _tv.setMovementMethod(LinkMovementMethod.getInstance());
    }
       });
      }
      class MyClickableSpan extends ClickableSpan{ 
      String clicked;
          public MyClickableSpan(String string) {
    // TODO Auto-generated constructor stub
       clicked =string;
      }
      //clickable span
      public void onClick(View textView) {
      //do something


      Toast.makeText(MainActivity.this,clicked ,
        Toast.LENGTH_SHORT).show();
     }
     @Override
     public void updateDrawState(TextPaint ds) {
     ds.setColor(Color.BLACK);//set text color 
     ds.setUnderlineText(false); // set to false to remove underline
     }
    }
    }
0
ответ дан Raghunandan 23 August 2018 в 02:13
поделиться
  • 1
    @ TheMan68 - это то, что вы искали? – Raghunandan 29 March 2013 в 10:59
  • 2
    не совсем так, как это все еще приносит, делает все элементы, такие как число и вещи кликабельными. Я только указал слова. Поэтому я использовал регулярные выражения для вставки тега вокруг слов. спасибо за помощь – TheMan68 30 March 2013 в 06:29
Другие вопросы по тегам:

Похожие вопросы: