mirror of
https://github.com/MatomoCamp/matomocamp-companion-android.git
synced 2024-09-19 16:13:46 +02:00
Implement a custom MovementMethod to properly support clickable spans with text selection. Fixes #38
This commit is contained in:
parent
27bb707c93
commit
65178e5b5a
2 changed files with 68 additions and 7 deletions
|
@ -23,7 +23,6 @@ import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.text.method.MovementMethod;
|
|
||||||
import android.text.style.ClickableSpan;
|
import android.text.style.ClickableSpan;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
@ -47,6 +46,7 @@ import be.digitalia.fosdem.model.Event;
|
||||||
import be.digitalia.fosdem.model.Link;
|
import be.digitalia.fosdem.model.Link;
|
||||||
import be.digitalia.fosdem.model.Person;
|
import be.digitalia.fosdem.model.Person;
|
||||||
import be.digitalia.fosdem.model.RoomStatus;
|
import be.digitalia.fosdem.model.RoomStatus;
|
||||||
|
import be.digitalia.fosdem.utils.ClickableArrowKeyMovementMethod;
|
||||||
import be.digitalia.fosdem.utils.DateUtils;
|
import be.digitalia.fosdem.utils.DateUtils;
|
||||||
import be.digitalia.fosdem.utils.StringUtils;
|
import be.digitalia.fosdem.utils.StringUtils;
|
||||||
import be.digitalia.fosdem.viewmodels.EventDetailsViewModel;
|
import be.digitalia.fosdem.viewmodels.EventDetailsViewModel;
|
||||||
|
@ -115,8 +115,6 @@ public class EventDetailsFragment extends Fragment {
|
||||||
textView.setText(text);
|
textView.setText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
MovementMethod linkMovementMethod = LinkMovementMethod.getInstance();
|
|
||||||
|
|
||||||
// Set the persons summary text first; replace it with the clickable text when the loader completes
|
// Set the persons summary text first; replace it with the clickable text when the loader completes
|
||||||
holder.personsTextView = view.findViewById(R.id.persons);
|
holder.personsTextView = view.findViewById(R.id.persons);
|
||||||
String personsSummary = event.getPersonsSummary();
|
String personsSummary = event.getPersonsSummary();
|
||||||
|
@ -124,7 +122,7 @@ public class EventDetailsFragment extends Fragment {
|
||||||
holder.personsTextView.setVisibility(View.GONE);
|
holder.personsTextView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
holder.personsTextView.setText(personsSummary);
|
holder.personsTextView.setText(personsSummary);
|
||||||
holder.personsTextView.setMovementMethod(linkMovementMethod);
|
holder.personsTextView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
holder.personsTextView.setVisibility(View.VISIBLE);
|
holder.personsTextView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +161,7 @@ public class EventDetailsFragment extends Fragment {
|
||||||
ds.setUnderlineText(false);
|
ds.setUnderlineText(false);
|
||||||
}
|
}
|
||||||
}, 0, roomText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
}, 0, roomText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
textView.setMovementMethod(linkMovementMethod);
|
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
}
|
}
|
||||||
textView.setText(roomText);
|
textView.setText(roomText);
|
||||||
textView.setContentDescription(getString(R.string.room_content_description, roomText));
|
textView.setContentDescription(getString(R.string.room_content_description, roomText));
|
||||||
|
@ -177,7 +175,7 @@ public class EventDetailsFragment extends Fragment {
|
||||||
textView.setVisibility(View.GONE);
|
textView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
textView.setText(StringUtils.parseHtml(text, getResources()));
|
textView.setText(StringUtils.parseHtml(text, getResources()));
|
||||||
textView.setMovementMethod(linkMovementMethod);
|
textView.setMovementMethod(ClickableArrowKeyMovementMethod.getInstance());
|
||||||
}
|
}
|
||||||
textView = view.findViewById(R.id.description);
|
textView = view.findViewById(R.id.description);
|
||||||
text = event.getDescription();
|
text = event.getDescription();
|
||||||
|
@ -185,7 +183,7 @@ public class EventDetailsFragment extends Fragment {
|
||||||
textView.setVisibility(View.GONE);
|
textView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
textView.setText(StringUtils.parseHtml(text, getResources()));
|
textView.setText(StringUtils.parseHtml(text, getResources()));
|
||||||
textView.setMovementMethod(linkMovementMethod);
|
textView.setMovementMethod(ClickableArrowKeyMovementMethod.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.linksHeader = view.findViewById(R.id.links_header);
|
holder.linksHeader = view.findViewById(R.id.links_header);
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package be.digitalia.fosdem.utils;
|
||||||
|
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.text.Layout;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.method.ArrowKeyMovementMethod;
|
||||||
|
import android.text.method.MovementMethod;
|
||||||
|
import android.text.style.ClickableSpan;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An extension of ArrowKeyMovementMethod supporting clickable spans as well.
|
||||||
|
*/
|
||||||
|
public class ClickableArrowKeyMovementMethod extends ArrowKeyMovementMethod {
|
||||||
|
|
||||||
|
private static ClickableArrowKeyMovementMethod instance;
|
||||||
|
|
||||||
|
private final RectF touchedLineBounds = new RectF();
|
||||||
|
|
||||||
|
public static MovementMethod getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new ClickableArrowKeyMovementMethod();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
|
||||||
|
// If action has finished
|
||||||
|
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||||
|
// Locate the area that was pressed
|
||||||
|
int x = (int) event.getX();
|
||||||
|
int y = (int) event.getY();
|
||||||
|
x -= widget.getTotalPaddingLeft();
|
||||||
|
y -= widget.getTotalPaddingTop();
|
||||||
|
x += widget.getScrollX();
|
||||||
|
y += widget.getScrollY();
|
||||||
|
|
||||||
|
// Locate the text line
|
||||||
|
Layout layout = widget.getLayout();
|
||||||
|
int line = layout.getLineForVertical(y);
|
||||||
|
|
||||||
|
// Check that the touch actually happened within the line bounds
|
||||||
|
touchedLineBounds.left = layout.getLineLeft(line);
|
||||||
|
touchedLineBounds.top = layout.getLineTop(line);
|
||||||
|
touchedLineBounds.right = layout.getLineWidth(line) + touchedLineBounds.left;
|
||||||
|
touchedLineBounds.bottom = layout.getLineBottom(line);
|
||||||
|
|
||||||
|
if (touchedLineBounds.contains(x, y)) {
|
||||||
|
int offset = layout.getOffsetForHorizontal(line, x);
|
||||||
|
// Find a clickable span at that text offset, if any
|
||||||
|
ClickableSpan[] link = buffer.getSpans(offset, offset, ClickableSpan.class);
|
||||||
|
if (link.length > 0) {
|
||||||
|
link[0].onClick(widget);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onTouchEvent(widget, buffer, event);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue