一、为TextView设置链接的三种方式
1、为TextView设置带有<a>
标签的的文本
设置带<a>
标签的方式有两种:
- 通过Html.formHtml()方法设置,示例代码如下:
<TextView android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
var html="<a href='http://www.baidu.com'>百度一下</a>"
var cs:CharSequence = Html.fromHtml(html)
textView.text = cs
- 通过引用strings.xml定义的带有
<a>
标签的文本,示例代码如下:
<resources>
<string name="link_text"><a href="http://www.baidu.com">百度一下</a></string>
</resources>
<TextView android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/link_text"/>
2、为TextView设置android:autoLink
属性
android:autoLink属性有几个值:
- none:不匹配任何连接
- web:匹配网址
- email:匹配邮箱
- phone:匹配手机号
- map:匹配映射
- all:匹配网址、邮箱、手机号和映射
所有匹配上的网址、邮箱、手机号和映射都会产生链接。
示例代码如下:
<TextView android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="all"/>
var link=StringBuilder()
link.append("百度URL:http://www.baidu.com\n")
.append("邮箱:[email protected]\n")
.append("手机:18802703417")
textView.text = link.toString()
3、通过SpannableString
为TextView部分文字设置链接
示例代码如下:
var textView = findViewById(R.id.textview4)
var text = "显示Activity1"
//拆分字符串添加点击
var span=SpannableString(text)
span4.setSpan(object:ClickableSpan(){
override fun onClick(widget: View?) {
var intent = Intent(this@TextViewActivity,OneActivity::class.java)
startActivity(intent)
}},0,text.length,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.text = span
此例实现了点击文字跳转到别的Activity界面。
SpannableString类丰富文本的表现形式方面很强大,具体介绍可以看参考资料。
注意: 以上三种方式,只是给文本添加上了链接效果,点击链接并没有什么效果。必须调用textview.movementMethod = LinkMovementMethod.getInstance()
激活链接。
二、为TextView实现图文混排的两种方式
1、Html
实现图文混排
Spanned fromHtml(String source, int flags)
Spanned fromHtml (String source, int flags, Html.ImageGetter imageGetter, Html.TagHandler tagHandler)
扫描到source中每个标签都会调用Html.ImageGetter对象的’getDrawable(String source)’方法,并且把中src的值作为入参传递给这个方法。如果有无法解析的标签,就会调用Html.TagHandler对象的方法进行通知处理。
- source:可能包含html标签的字符串;
- imageGetter:Html.ImageGetter接口对象,需要自己实现其内部方法’public Drawable getDrawable(String source)’,形参source接收的是标签src属性的值;
- tagHandler:如果有不能解析的标签,会调用这个对象的方法进行通知处理。
关于Html.ImageGetter对象的不完整实现示例代码如下:
object:Html.ImageGetter{
override fun getDrawable(source: String?): Drawable {
//第一步:获取图片的drawable对象
var drawable: Drawable =
//第二步:设置图片边界
drawable.setBounds(0,0,drawable.intrinsicWidth,drawable.intrinsicHeight)
return drawable
}
}
经过观察发现,fromHtml
方法的关键是如何通过属性src的值获取指定图片的Drawable对象。
由于图片可能存储在项目drawable文件夹,也可能存储在安卓存储器上,也可能存储在服务器上,下面分三种情况来探讨如何获取对象的Drawable对象。
(1)、存储在项目drawable文件夹中
通常会设置src值为图片名称或R.drawable.图片名称
(注意这里的图片名称不带扩展名)
如果设置的是图片名称,我们需要使用反射机制获取到R.drawable.图片名称
的值。
然后调用Resources类对象的public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme)
方法即可获取到这张图片的Drawable对象,其中R.drawable.图片名称
的值要作为入参传递给方法形参id。
kotlin示例代码实现如下:
var drawable = resources.getDrawable([R.drawable.图片名称]的值,null)
注意:如何通过图片名称获取
R.drawable.图片名称
的值?
首先需要清楚:每当在drawable文件夹添加一张图片,系统都会在R类的内部类drawable中添加一个图片名称的属性,同时为这个属性生成一个值。也就是说这个属性值就指代这张图片资源,我们可以通过调用’resources.getDrawable([R.drawable.图片名称]的值)’获取这张图片的Drawable对象。
向drawable文件夹添加一张图片image1.jpg,R类大致情况如下:
public final class R {
public static final class drawable {
public static final int image1=0x7f060057;
}
}
使用反射机制通过image1名称获取到R.drawable.image1的值,kotlin实现代码如下:
fun getResourceId(name:String):Int{
var field = R.drawable::class.java.getField(name)
return field.get(null).toString().toInt()
}
(2)、存储在安卓存储器上
图片存储在安卓存储器,通常属性src值为具体的图片路径,可以通过调用Drawable类的public static Drawable createFromPath(String pathName)
方法获取图片资源。
(3)、存储在服务器上
图片存储在服务器,通常属性src值为一个服务器图片的网址。
首先需要异步方式从服务器下载这个图片,也就是从服务器获取图片流,从服务器获取图片的细节具体可看《http请求》,简化步骤如下:
var connection = URL("").openConnection() as HttpURLConnection
connection.connect()
inputStream = connection.inputStream
然后如果直接这样更新ui:imageView.setImageDrawable(Drawable.createFromStream(inputStream),image1),你会发现ui渲染不能展示完整的图片,甚至是一片黑。
具体内部实现不清楚,但是经过调试发现,’inputStream = connection.inputStream’并不能从服务器一次性获取全部的图片流,甚至完全获取不到图片流,这才导致更新
部分ui或者全黑,可能的原因是系统有什么的默认缓存的限制。知道这个,解决方案就有了,方案一:把接收的图片流输出为手机存储器的一张图片;方案二:把全部图片流转存到一片缓存空间。
有了完整的图片或者完整的图片流缓存,那么就容易获得这个图片的Drawable对象。
两种方案代码实现如下(kotlin):
import android.graphics.drawable.Drawable
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.widget.ImageView
import com.mapc.demo.R
import java.io.*
import java.net.HttpURLConnection
import java.net.URL
class HttpActivity : AppCompatActivity() {
private lateinit var ivURLImage:ImageView
private var image1 = "1.jpg"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_http)
this.title = ""
ivURLImage = findViewById(R.id.iv_url_image)
var inputStream: InputStream?=null
var byteArray:ByteArray?=null
var handler = object : Handler() {
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
//获取网络图片Drawable对象的两种方式
//方案1:图片方式渲染
//var drawable = Drawable.createFromPath(File(Environment.getExternalStorageDirectory(),image1).path)
//方案2:流方式渲染
var drawable = Drawable.createFromStream(ByteArrayInputStream(byteArray),image1)
ivURLImage.setImageDrawable(drawable)
}
}
Thread(Runnable {
var connection = URL("http://192.168.1.6:8080/android/api/image/"+image1).openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.connectTimeout = 3000
connection.doInput = true
connection.doOutput = true
connection.setRequestProperty("accept", "*/*")
connection.setRequestProperty("Content-Type", "*/*")
connection.connect()
if (connection.responseCode == 200) {
inputStream = connection.inputStream
// 方式2:转存全部流,然后从流渲染ui
var byteout=ByteArrayOutputStream()
var byte = ByteArray(200)
var len = inputStream?.read(byte)
while (len !=null && len != -1) {
byteout.write(byte, 0, len)
len = inputStream?.read(byte)
}
byteArray=byteout.toByteArray()
connection.disconnect()
//方式1:流输出为图片,然后从图片渲染ui。
//var file = File(Environment.getExternalStorageDirectory(),image1)
//var out = FileOutputStream(file)
//val buffer = ByteArray(1024)
//var len: Int? = inputStream?.read(buffer)
//while (len!=null && len != -1) {
// out.write(buffer, 0, len)
// len = inputStream?.read(buffer)
//}
//out.flush()
//out.close()
//connection.disconnect()
handler.sendEmptyMessage(1)
} else {}
}).start()
}
}
注意,以上是ImgeView控件显示网络图片的demo,可以在此用以说明本文本节问题。
(3)、SpannableString
实现图文混排
示例代码如下:
var spannableString = SpannableString("在文本中添加表情(表情)")
var drawable = resources.getDrawable(R.mipmap.image1)
drawable.setBounds(0, 0, 42, 42);
var imageSpan = ImageSpan(drawable);
spannableString.setSpan(imageSpan, 6, 8, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);
SpannableString很强大,是通过拆字实现部分文本的效果。
三、跑马灯效果设置
示例代码如下:
<TextView android:id="@+id/textview6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
android:focusableInTouchMode="true"/>
必须设置的几个属性如下:
android:singleLine,必须设置为单行。
android:ellipsize可选值:
start:省略号显示在开头,比如:…789
end:省略号显示在结尾,比如:123…
middle:省略号显示在中间,比如:12…89
marquee:以横向滚动方式显示,必须获得当前焦点
none:不做任何处理,会截断显示的文字
- android:marqueeRepeatLimit
android:ellipsize设置为marquee时生效,指示滚动重复特点,滚动的必要条件之一
- android:focusable,是否获得焦点,滚动的必要条件之一
android:focusableInTouchMode,抚摸模式下获得焦点
[完整demo]
参考资料:
2、Html
4、使用Html.fromHtml()怎么加载Html中的图片
5、为TextView添加链接-setMovementMethod
8、安卓开发中SpannableString之富文本显示效果
10、R类源码
11、android.graphics.drawable.Drawable类源码