您的位置:首页 > 其它

SpannableString中的ClickableSpan和Textview点击事件冲突解决

2017-01-05 14:24 1176 查看
背景描述:项目中有这样的需求:在展示评论内容的Textview中展示文字,其中包含3种类型数据:

1、普通文字:评论内容或者回复内容。因为这个Textview是展示评论或者回复的,点击后,要展示软键盘(popupwindow等忽略)

2、股票代码:该类型文字显示另一种颜色,并且点击后去到展示webView的activity展示股票网页

3、关联的人名:如:@123,显示不同于普通文字的颜色,点击后去到这个人的个人详情页

出现问题:在用SpannableString中的ClickableSpan的时候,会出现问题:点击了股票代码或者人名后,虽然会跳转,但是,会在跳转过程中出现软键盘,到底目标activity后,软键盘消失。这样展示不美观

解决方法:需要将点击的关键字的点击事件(即:ClickableSpan的点击事件和Textview的点击事件分开)

效果图:

图1:



———————————————————————————————————–

图2:



——————————————————————————————————–

代码:

1、activity:

package com.chen.customviewdemo.activity;

import android.content.Context;
import android.view.View;
import android.view.inputmethod.InputMethodManager;

import com.chen.customviewdemo.R;
import com.chen.customviewdemo.bean.KeyBean;
import com.chen.customviewdemo.view.MyTextView_1;
import com.chen.customviewdemo.view.MyTextView_2;

import java.util.ArrayList;

/**
* 一个Textview中,有需要点击后专门处理的关键字,也有Textview自己的点击事件,
* 如:点击关键字跳转到其他activity中,点击非关键字后出现软键盘
* 有时候,会出现这样的情况:点击关键字后,跳转过程中,软键盘会弹出一瞬间。影响美观.
*/
public class MainActivity_34_Maching_ClickableSpan extends BaseActivity {

/**
* 说明:
* MyTextView_1:没有对关键字区域专门处理,点击后,非关键字区域还是会得到点击事件
* MyTextView_2:对关键字区域专门处理,点击后,非关键字区域没有获得点击事件
* 点击MyTextView_1中的关键字区域去跳转,没有出现软键盘闪现问题。但是项目中确实出现过。建议使用MyTextView_2
* 这里,为了说明情况,没有使用跳转。而是点击后弹出吐司。
* 在MyTextView_1中,点击关键字,弹出吐司,并且出现软键盘
* 在MyTextView_2中,点击关键字,仅弹出吐司,不出现软键盘
*/

MyTextView_1 my_textview_1;
MyTextView_2 my_textview_2;

@Override
void initview() {
setContentView(R.layout.activity_main_34);

my_textview_1 = (MyTextView_1) findViewById(R.id.my_textview_1);
my_textview_2 = (MyTextView_2) findViewById(R.id.my_textview_2);

ArrayList<KeyBean> keyBeanList = new ArrayList<KeyBean>();

keyBeanList.add(new KeyBean("我", "我"));
keyBeanList.add(new KeyBean("你", "你"));
keyBeanList.add(new KeyBean("他", "他"));
keyBeanList.add(new KeyBean("哦", "哦"));
keyBeanList.add(new KeyBean("哈哈", "哈哈"));
keyBeanList.add(new KeyBean("605", "605"));
keyBeanList.add(new KeyBean("@嗯嗯", "嗯嗯"));

String content = "我们123哈哈哦缴费基数机诶@嗯嗯5623";

String redStr = "123";

my_textview_1.insertData(content, redStr, keyBeanList);

my_textview_1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showKeyBoard();
}
});

my_textview_2.insertData(content, redStr, keyBeanList);

my_textview_2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showKeyBoard();
}
});

}

/**
* 展示软键盘
*/
public void showKeyBoard() {
InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
}

}


2、布局:activity_main_34

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical"
>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:padding="5dp"
android:text="Activity34_ClickableSpan和Textview点击事件冲突"
android:textColor="#ec434b"
android:textSize="20sp"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:padding="5dp"
android:text="tv_1"
android:textSize="20sp"/>

<com.chen.customviewdemo.view.MyTextView_1
android:id="@+id/my_textview_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="#f6f6f6"
android:padding="10dp"/>

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="20dp"
android:background="#000000"
/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:padding="5dp"
android:text="tv_2"
android:textSize="20sp"/>

<com.chen.customviewdemo.view.MyTextView_2
android:id="@+id/my_textview_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="#f6f6f6"
android:padding="10dp"/>

</LinearLayout>


3、MyTextView_1:没有对关键字区域专门处理,点击后,非关键字区域还是会得到点击事件

package com.chen.customviewdemo.view;

import android.content.Context;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.chen.customviewdemo.R;
import com.chen.customviewdemo.bean.KeyBean;

import java.util.ArrayList;

public class MyTextView_1 extends TextView {

private Context context;

private String toRedWord = "";

public MyTextView_1(Context context) {
this(context, null);
}

public MyTextView_1(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}

public MyTextView_1(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
myTextViewInit();
}

/**
* 初始化
*/
private void myTextViewInit() {

}

public void insertData(String str, String redStr, final ArrayList<KeyBean> keyBeanList) {

toRedWord = redStr;

//        final SpannableString spannableString = ExpressionUtil.getSpannableString(str, context);
SpannableString spannableString = new SpannableString(str);
String content = spannableString.toString();

//处理文本中的关键字
if (keyBeanList != null && keyBeanList.size() > 0) {
for (int i = 0; i < keyBeanList.size(); i++) {
final String data = keyBeanList.get(i).getContent();
final String hide_content = keyBeanList.get(i).getHide_content();
String temp = content;
int startNew = 0;
int startOld = 0;
if (temp.contains(data)) {
while (temp.contains(data)) {
spannableString.setSpan(new ClickableSpan() {
@Override
public void updateDrawState(TextPaint ds) {
// TODO Auto-generated method stub
super.updateDrawState(ds);
ds.setColor(context.getResources().getColor(R.color.linkcolor));
ds.setUnderlineText(false);
}

@Override
public void onClick(View widget) {
Toast.makeText(context, hide_content, Toast.LENGTH_SHORT).show();

//Intent intent = null;
//if (data.startsWith("@")) {
//   intent = new Intent(context, PersonActivity.class);
//} else {
//    intent = new Intent(context, WebActivity.class);
//}
//intent.putExtra("hide_content", hide_content);
//context.startActivity(intent);

}

}, startOld + temp.indexOf(data), startOld + temp.indexOf(data) + data.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
setText(spannableString);
setMovementMethod(LinkMovementMethod.getInstance());
startNew = temp.indexOf(data) + data.length();
startOld += startNew;
temp = temp.substring(startNew);
}
} else {
setText(spannableString);
}
}

} else {
setText(spannableString);
}

//处理要变红的字
if (!TextUtils.isEmpty(toRedWord)) {
//只要把关键字变红就行了,不需要加点击事件。如果需要,可以自己加
String temp = content;
int startNew = 0;
int startOld = 0;
while (temp.contains(toRedWord)) {
spannableString.setSpan(new ClickableSpan() {

@Override
public void updateDrawState(TextPaint ds) {
// TODO Auto-generated method stub
super.updateDrawState(ds);
ds.setColor(0xffff0000);
ds.setUnderlineText(false);
}

@Override
public void onClick(View widget) {
}

}, startOld + temp.indexOf(toRedWord), startOld + temp.indexOf(toRedWord) + toRedWord.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
setText(spannableString);
setMovementMethod(LinkMovementMethod.getInstance());
startNew = temp.indexOf(toRedWord) + toRedWord.length();
startOld += startNew;
temp = temp.substring(startNew);
}
} else {
setText(spannableString);
}

}

}


4、MyTextView_2:对关键字区域专门处理,点击后,非关键字区域没有获得点击事件

package com.chen.customviewdemo.view;

import android.content.Context;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.method.Touch;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.chen.customviewdemo.R;
import com.chen.customviewdemo.bean.KeyBean;

import java.util.ArrayList;

public class MyTextView_2 extends TextView {

private Context context;

private String toRedWord = "";

public MyTextView_2(Context context) {
this(context, null);
}

public MyTextView_2(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}

public MyTextView_2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
myTextViewInit();
}

/**
* 初始化
*/
private void myTextViewInit() {

}

public void insertData(String str, String redStr, final ArrayList<KeyBean> keyBeanList) {

toRedWord = redStr;

//        final SpannableString spannableString = ExpressionUtil.getSpannableString(str, context);
SpannableString spannableString = new SpannableString(str);
String content = spannableString.toString();

//处理文本中的关键字
if (keyBeanList != null && keyBeanList.size() > 0) {
for (int i = 0; i < keyBeanList.size(); i++) {
final String data = keyBeanList.get(i).getContent();
final String hide_content = keyBeanList.get(i).getHide_content();
String temp = content;
int startNew = 0;
int startOld = 0;
if (temp.contains(data)) {
while (temp.contains(data)) {
spannableString.setSpan(new ClickableSpan() {
@Override
public void updateDrawState(TextPaint ds) {
// TODO Auto-generated method stub
super.updateDrawState(ds);
ds.setColor(context.getResources().getColor(R.color.linkcolor));
ds.setUnderlineText(false);
}

@Override
public void onClick(View widget) {
Toast.makeText(context, hide_content, Toast.LENGTH_SHORT).show();

//Intent intent = null;
//if (data.startsWith("@")) {
//     intent = new Intent(context, PersonActivity.class);
//} else {
//     intent = new Intent(context, WebActivity.class);
//}
//intent.putExtra("hide_content", hide_content);
//context.startActivity(intent);

}

}, startOld + temp.indexOf(data), startOld + temp.indexOf(data) + data.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
setText(spannableString);
setMovementMethod(CustomLinkMovementMethod.getInstance());
startNew = temp.indexOf(data) + data.length();
startOld += startNew;
temp = temp.substring(startNew);
}
} else {
setText(spannableString);
}
}

} else {
setText(spannableString);
}

//处理要变红的字
if (!TextUtils.isEmpty(toRedWord)) {
//只要把关键字变红就行了,不需要加点击事件。如果需要,可以自己加
String temp = content;
int startNew = 0;
int startOld = 0;
while (temp.contains(toRedWord)) {
spannableString.setSpan(new ClickableSpan() {

@Override
public void updateDrawState(TextPaint ds) {
// TODO Auto-generated method stub
super.updateDrawState(ds);
ds.setColor(0xffff0000);
ds.setUnderlineText(false);
}

@Override
public void onClick(View widget) {
}

}, startOld + temp.indexOf(toRedWord), startOld + temp.indexOf(toRedWord) + toRedWord.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
setText(spannableString);
setMovementMethod(CustomLinkMovementMethod.getInstance());
startNew = temp.indexOf(toRedWord) + toRedWord.length();
startOld += startNew;
temp = temp.substring(startNew);
}
} else {
setText(spannableString);
}

}

//-------------------------------------------------------------

public boolean linkHit;//内部链接是否被点击

@Override
public boolean performClick() {
if (linkHit) {
return true;
}
return super.performClick();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
linkHit = false;
return super.onTouchEvent(event);
}

public static class CustomLinkMovementMethod extends LinkMovementMethod {

static CustomLinkMovementMethod 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);

ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);

if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);

} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}

if (widget instanceof MyTextView_2) {
((MyTextView_2) widget).linkHit = true;
}

return true;
} else {
Selection.removeSelection(buffer);
super.onTouchEvent(widget, buffer, event);
return false;
}
}

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

public static CustomLinkMovementMethod getInstance() {
if (sInstance == null) {
sInstance = new CustomLinkMovementMethod();
}
return sInstance;
}
}

}


5、KeyBean

package com.chen.customviewdemo.bean;

/**
* 关键字bean。
* 包含显式内容和隐式内容。
* 如:在界面上显示“百度”,点击了它,就去一个界面打开百度的网页。要打开网页,肯定需要Url。这就需要,在点击的时候,把Url传递过去。
* 这个时候,这个Url,就是隐式内容了。不必让用户看到,只是在触发后,隐含的做一定操作就行
*/
public class KeyBean {

public KeyBean(String content, String hide_content) {
this.content = content;
this.hide_content = hide_content;
}

/**
* 内容
*/
public String content;

/**
* 隐藏的内容,点击内容后,要传递的值或者要做的事
*/
public String hide_content;

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public String getHide_content() {
return hide_content;
}

public void setHide_content(String hide_content) {
this.hide_content = hide_content;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐