前提:之前遇到過一次textview顯示url的方式,但是并未深入探究。但是,上個禮拜一個朋友問我如何在textview上面加載url,并且點擊跳轉到指定頁面。當時對這個比較感興趣也就深入探究了一番。雖然實現了,但是效果并不理想。如果哪位看官對這一點,理解的比較深入,請告訴我一聲,謝謝了。
首先
- 對TextView屬性比較熟悉的開發者應該都知道TextView有一個叫做autoLink的屬性,可以將符合指定格式的文本轉換為可單擊的超鏈接形式,在幫助文檔中也可以發現Android給我們提供了如下幾種格式:
1、none:表示不進行任何匹配,默認;
2、Web:表示匹配Web Url, 如: 連接地址為http://www.baidu.com會成為可單擊跳轉的超鏈接;
3、Email:表示匹配郵件地址, 如:郵件地址為xx@sina.com會成為可單擊的超鏈接;
4、Phone:表示匹配電話號碼,如:點擊號碼10000會跳到撥號界面;
5、Map:表示匹配地圖地址;
6、All:表示將會匹配web、email、phone、map;
如下圖所示
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_margin="16dp"
android:text="123"
android:autoLink="phone"/>
- 其中android:autoLink=" "就是加載的屬性
其次
- 要實現點擊textview中url的跳轉到指定功能頁面的功能,有這樣兩種功能
1、直接跳轉到指定頁面(可以直接自定義頁面);
2、通過手機瀏覽器到指定頁面
首先,來看跳轉到指定頁面的寫法
public class MainActivity extends AppCompatActivity {
TextView mTxtWeb;
CharSequence mContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
/**
* 初始化控件
*/
private void initView() {
mTxtWeb = (TextView) findViewById(R.id.txt_web);
String htmlLinkText = "天下"+"www.google.com"+"為公";
mTxtWeb.setText(Html.fromHtml(htmlLinkText));
mTxtWeb.setMovementMethod(LinkMovementMethod.getInstance());
CharSequence text = mTxtWeb.getText();
if (text instanceof Spannable) {
int end = text.length();
Spannable sp = (Spannable) mTxtWeb.getText();
URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);
SpannableStringBuilder style = new SpannableStringBuilder(text);
style.clearSpans();
for (final URLSpan url : urls) {
//最主要的一點
CustomClickUrlSpan myURLSpan = new CustomClickUrlSpan(url.getURL(), new CustomClickUrlSpan.OnLinkClickListener() {
@Override
public void onLinkClick(View view) {
Intent intent= new Intent(this,WebActivity.class);
intent.putExtra("url",url.getURL());
startActivity(intent);
}
});
style.setSpan(myURLSpan, sp.getSpanStart(url), sp.getSpanEnd(url), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
mTxtWeb.setText(style);
}
}
-
其中CustomClickUrlSpan,是點擊url跳轉,其中傳入一個url,一個自定義接口,達到跳轉到指定頁面的目的。
public class CustomClickUrlSpan extends ClickableSpan { private String url; private OnLinkClickListener mListener; public CustomClickUrlSpan(String url, OnLinkClickListener listener) { this.url=url; this.mListener=listener; } @Override public void onClick(View widget) { if (mListener!=null){ mListener.onLinkClick(widget); } } /** * 跳轉鏈接接口 */ public interface OnLinkClickListener{ void onLinkClick(View view); } }
-
其中ClicableSpan是系統的方法,其中定義了一個抽象點擊的方法(來看看系統源碼)
public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance { private static int sIdCounter = 0; private int mId = sIdCounter++; /** * Performs the click action associated with this span. * 這個是點擊方法 */ public abstract void onClick(View widget); /** * Makes the text underlined and in the link color. */ @Override public void updateDrawState(TextPaint ds) { //這個是設置url顏色 ds.setColor(ds.linkColor); //這個是設置是否有下劃線 ds.setUnderlineText(true); } /** * Get the unique ID for this span. * * @return The unique ID. * @hide */ public int getId() { return mId; } }
-
當然也有簡單的寫法,比如:
/** * 點擊跳轉 */ private class MyURLSpan extends ClickableSpan { private String mUrl; MyURLSpan(String url) { mUrl = url; } @Override public void onClick(View widget) { Toast.makeText(MainActivity.this, mContent.toString(), Toast.LENGTH_LONG).show(); } }
第二種用的內部類的方法,但是會有局限性,會讓主頁變得太繁瑣,也會讓跳轉受限,為了讓代碼看著清晰簡潔,所以推薦使用第一種方法。(個人理解,不對的還請指正)
其次,通過瀏覽器跳轉到指定頁面(并取消下劃線)
public class CustomUrlSpan extends UnderlineSpan implements Parcelable {
String url;
public CustomUrlSpan(String url) {
this.url = url;
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
if (ds != null) {
ds.setUnderlineText(false);
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.url);
}
protected CustomUrlSpan(Parcel in) {
super(in);
this.url = in.readString();
}
public static final Creator<CustomUrlSpan> CREATOR = new Creator<CustomUrlSpan>() {
public CustomUrlSpan createFromParcel(Parcel source) {
return new CustomUrlSpan(source);
}
public CustomUrlSpan[] newArray(int size) {
return new CustomUrlSpan[size];
}
};
}
-
一定要實現Parcelable接口,要不會有錯誤提示(下面是activity中的用法,其中通過瀏覽器跳轉到指定頁面,并且取消了下劃線)。
/** * 初始化控件 */ private void initView() { mTxtWeb = (TextView) findViewById(R.id.txt_web); String htmlLinkText = "天下"+"www.google.com"+"為公"; mTxtWeb.setText(Html.fromHtml(htmlLinkText)); mTxtWeb.setMovementMethod(LinkMovementMethod.getInstance()); CharSequence text = mTxtWeb.getText(); if (text instanceof Spannable) { int end = text.length(); Spannable sp = (Spannable) mTxtWeb.getText(); URLSpan[] urls = sp.getSpans(0, end, URLSpan.class); SpannableStringBuilder style = new SpannableStringBuilder(text); style.clearSpans(); for (final URLSpan url : urls) { CustomUrlSpan myURLSpan = new CustomUrlSpan(url.getURL()); style.setSpan(myURLSpan, sp.getSpanStart(url), sp.getSpanEnd(url), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } mTxtWeb.setText(style); } }
最后(還有一點比較困惑)
- UnderlineSpan和ClickableSpan都有設置取消下劃線的方法(updateDrawState),重寫了方法之后,UnderlineSpan取消了下劃線,但是ClickableSpan卻取消不了這一點比較困惑。
- 看源碼可以看到UnderlineSpan和ClickableSpan都是繼承CharacterStyle,并且有一個抽象方法updateDrawState(),那么直接繼承CharacterStyle,然后再自定義一個跳轉接口可否實現跳轉到指定接口呢,經過試驗之后還是會有些許不盡如人意。如果哪位仁兄對這一點比較了解,還請告訴我一聲,不勝感激。
感悟
對于我們來說,不管做什么事情應該盡自己最大努力去做好,事事都怕認真二字
引用知乎上面的一段話就是:
如果天空是黑暗的,那就摸黑生存;如果發出聲音是危險的,那就保持沉默;如果自覺無力發光的,那就蜷伏于墻角。但不要習慣了黑暗就為黑暗辯護;不要為自己的茍且而得意;不要嘲諷那些比自己更勇敢熱情的人們。我們可以卑微如塵土,不可扭曲如蛆蟲。——季業推薦一個探討技術的技術群(493180098)