问题
I designing an interactive kids book. I am using a canvas on surfaceview since I need animations which I think are best suited to surfaceview
I want to make each word touchable and read that word aloud. This worked great when I used a regular view with a textview inside. I then tried canvas for animations and do not know how to do it.
I have used a staticlayout on the canvas to hold the spannable text. I do not know how I can activate the onTouchListener.
Here I set up the staticlayout
public class OurView extends SurfaceView implements Runnable, Callback {
public OurView(Context context, AttributeSet attribs) {
super(context, attribs);
init(context);
}
private void init(Context context) {
ball = BitmapFactory.decodeResource(getResources(), R.drawable.ball);
text = context.getString(R.string.para1);
tpaint = new TextPaint();
tpaint.setColor(Color.WHITE);
tpaint.setStyle(Style.FILL);
tpaint.setTextSize(40F);
TextView tv = splitWords(text);
staticLayout = new StaticLayout(??????????, tpaint, 1000F,
Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
holder = getHolder();
holder.addCallback(this);
}
This was my split the text into words and make an on touch listener for each word. It currently returns a Textview, I tried to return spaanablestring but I could not activate the listener. I want to change it to suit my needs. I do not know how to do tv.setMovementMethod(new LinkTouchMovementMethod()) without a textview.
public TextView splitWords(final String text) {
TextView tv = new TextView(getContext());
final SpannableString ssText = new SpannableString(text);
Pattern pattern;
String regex = "\\w+";
pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
final int begin = matcher.start();
final int end = matcher.end();
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View widget) {
String word = (String) text.subSequence(begin, end)
.toString();
Toast.makeText(getContext(), word, Toast.LENGTH_SHORT)
.show();
return;
}
};
ssText.setSpan(clickableSpan, begin, end, 0);
}
tv.setMovementMethod(new LinkMovementMethod());
tv.setText(text, BufferType.SPANNABLE);
return tv;
}
For completeness my DoDraw
private void doDraw(Canvas canvas) {
canvas.drawBitmap(ball, x, 100, null);
incrementX();
canvas.save();
canvas.translate(100.0f, 350.0f);
staticLayout.draw(canvas);
canvas.restore();
}
I want either to add a textview to staticlayout or add spannableString and activate the listeners.
回答1:
You need to override onTouch method in your custom view. Refer the following code, most of them are copied from LinkTouchMovementMethod.onTouchEvent().
private boolean updateSelection(MotionEvent event, Spannable buffer,Layout layout) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= getPaddingLeft();
y -= getPaddingTop();
x += getScrollX();
y += getScrollY();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(this);
} else {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}
return true;
} else {
Selection.removeSelection(buffer);
}
}
return false;
Call the updateSelection method in your View.onTouchEvent() method.
@Override
public boolean onTouchEvent(MotionEvent event) {
return updateSelection(event, layout.getText(), layout);
}
Refer Weex RichText to see a real demo.
来源:https://stackoverflow.com/questions/14975621/how-to-include-clickable-text-in-staticlayout-and-surfaceview