問題描述
我有一個可以包含可點擊鏈接的文本視圖.單擊其中一個鏈接時,我想開始一項活動.這很好用,但也應該可以單擊整個文本視圖并開始另一個活動.
I have a textview that can contain clickable links. When one of this links is clicked, I want to start an activity. This works fine, but it should also be possible to click the whole textview and start another activity.
這就是我目前的解決方案:
So that's my current solution:
TextView tv = (TextView)findViewById(R.id.textview01);
Spannable span = Spannable.Factory.getInstance().newSpannable("test link span");
span.setSpan(new ClickableSpan() {
@Override
public void onClick(View v) {
Log.d("main", "link clicked");
Toast.makeText(Main.this, "link clicked", Toast.LENGTH_SHORT).show();
} }, 5, 9, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(span);
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("main", "textview clicked");
Toast.makeText(Main.this, "textview clicked", Toast.LENGTH_SHORT).show();
}
});
tv.setMovementMethod(LinkMovementMethod.getInstance());
問題是,當我設置 OnClickListener 時,每次點擊鏈接時首先整個文本視圖的監聽器然后調用 ClickableSpan 的監聽器.
The problem is, that when I set an OnClickListener, everytime I click on a link first the listener for the whole textview and then the one for the ClickableSpan is called.
當點擊鏈接時,有沒有辦法阻止 android 調用整個 textview 的偵聽器?或者在整個視圖的監聽器中決定是否點擊了鏈接?
Is there a way to prevent android from calling the listener for the whole textview, when a link is clicked? Or to decide in the listener for the whole view, if a link was clicked or not?
推薦答案
Matthew 建議對 TextView 進行子類化,并提出了一個相當丑陋的解決方法.但它有效:
Matthew suggested subclassing TextView and with that hint a came up with a rather ugly workaround. But it works:
我創建了一個ClickPreventableTextView",當我在 TextView 中有可點擊的跨度時,我會使用它作為一個整體應該是可點擊的.
I've created a "ClickPreventableTextView" which I use when I have clickablespans in a TextView that should be clickable as a whole.
在其 onTouchEvent 方法中,該類在調用其基 TextView 類的 onTouchEvent 之前調用 MovementMethod 的 onTouchEvent 方法.因此,可以保證 clickablespan 的 Listener 將首先被調用.而且我可以防止為整個 TextView 調用 OnClickListener
In its onTouchEvent method this class calls the onTouchEvent method of MovementMethod before calling onTouchEvent on its base TextView class. So it is guaranted, that the Listener of the clickablespan will be invoked first. And I can prevent invoking the OnClickListener for the whole TextView
/**
* TextView that allows to insert clickablespans while whole textview is still clickable<br>
* If a click an a clickablespan occurs, click handler of whole textview will <b>not</b> be invoked
* In your span onclick handler you first have to check whether {@link ignoreSpannableClick} returns true, if so just return from click handler
* otherwise call {@link preventNextClick} and handle the click event
* @author Lukas
*
*/
public class ClickPreventableTextView extends TextView implements OnClickListener {
private boolean preventClick;
private OnClickListener clickListener;
private boolean ignoreSpannableClick;
public ClickPreventableTextView(Context context) {
super(context);
}
public ClickPreventableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ClickPreventableTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public boolean onTouchEvent(MotionEvent event) {
if (getMovementMethod() != null)
getMovementMethod().onTouchEvent(this, (Spannable)getText(), event);
this.ignoreSpannableClick = true;
boolean ret = super.onTouchEvent(event);
this.ignoreSpannableClick = false;
return ret;
}
/**
* Returns true if click event for a clickable span should be ignored
* @return true if click event should be ignored
*/
public boolean ignoreSpannableClick() {
return ignoreSpannableClick;
}
/**
* Call after handling click event for clickable span
*/
public void preventNextClick() {
preventClick = true;
}
@Override
public void setOnClickListener(OnClickListener listener) {
this.clickListener = listener;
super.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (preventClick) {
preventClick = false;
} else if (clickListener != null)
clickListener.onClick(v);
}
}
可點擊范圍的監聽器現在看起來像這樣
The listener for the clickable span now looks like that
span.setSpan(new ClickableSpan() {
@Override
public void onClick(View v) {
Log.d("main", "link clicked");
if (widget instanceof ClickPreventableTextView) {
if (((ClickPreventableTextView)widget).ignoreSpannableClick())
return;
((ClickPreventableTextView)widget).preventNextClick();
}
Toast.makeText(Main.this, "link clicked", Toast.LENGTH_SHORT).show();
} }, 5, 9, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
對我來說主要的缺點是,現在 getMovementMethod().onTouchEvent 將被調用兩次(TextView 在它的 onTouchEvent 方法中調用該方法).我不知道這是否有任何副作用,atm 它按預期工作.
For me the main disadvantage is, that now getMovementMethod().onTouchEvent will be called twice (TextView calls that method in it's onTouchEvent method). I don't know if this has any side effects, atm it works as expected.
這篇關于Android:可點擊 TextView 中的 ClickableSpan的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!