├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── cc │ │ └── ibooker │ │ └── ztextview │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── cc │ │ │ └── ibooker │ │ │ └── ztextview │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── cc │ └── ibooker │ └── ztextview │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── settings.gradle └── ztextviewlib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src ├── androidTest └── java │ └── cc │ └── ibooker │ └── ztextviewlib │ └── ExampleInstrumentedTest.java ├── main ├── AndroidManifest.xml ├── java │ └── cc │ │ └── ibooker │ │ └── ztextviewlib │ │ ├── AutoVerticalScrollTextView.java │ │ ├── AutoVerticalScrollTextViewUtil.java │ │ ├── MarqueeTextView.java │ │ ├── SpannableStringTextViewUtil.java │ │ └── ZTextViewClickUtil.java └── res │ └── values │ └── strings.xml └── test └── java └── cc └── ibooker └── ztextviewlib └── ExampleUnitTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZTextView 2 | Android:不一样的TextView(一)水平滚动-跑马灯,以及自定义跑马灯TextView(MarqueeTextView)。Android:不一样的TextView(二)自定义垂直滚动TextView(AutoVerticalScrollTextView)。Android:不一样的TextView(三)SpannableStringTextView。使用工具Android Studio 3 | 4 | 引入Android Studio: 5 | 6 | 1、在build.gradle文件中添加以下代码: 7 | ``` 8 | allprojects { 9 | repositories { 10 | maven { url 'https://jitpack.io' } 11 | } 12 | } 13 | ``` 14 | ``` 15 | dependencies { 16 | compile 'com.github.zrunker:ZTextView:v1.0.2' 17 | } 18 | ``` 19 | 2、在maven文件中添加以下代码: 20 | ``` 21 | 22 | 23 | jitpack.io 24 | https://jitpack.io 25 | 26 | 27 | ``` 28 | ``` 29 | 30 | com.github.zrunker 31 | ZTextView 32 | v1.0.2 33 | 34 | ``` 35 | 36 | 用法: 37 | 38 | Android:不一样的TextView(一)水平滚动-跑马灯,以及自定义跑马灯TextView(MarqueeTextView): 39 | 只需要在XML布局文件中引入(android:singleLine="true"一定要有): 40 | ``` 41 | 45 | ``` 46 | Android:不一样的TextView(二)自定义垂直滚动TextView(AutoVerticalScrollTextView)。 47 | 1、在XML布局文件中引入: 48 | ``` 49 | 61 | ``` 62 | 2、在java文件中进行调用(AutoVerticalScrollTextViewUtil): 63 | ``` 64 | public class MainActivity extends AppCompatActivity implements AutoVerticalScrollTextViewUtil.OnMyClickListener { 65 | private ArrayList list; 66 | private AutoVerticalScrollTextViewUtil aUtil; 67 | 68 | @Override 69 | protected void onCreate(Bundle savedInstanceState) { 70 | super.onCreate(savedInstanceState); 71 | setContentView(R.layout.activity_main); 72 | 73 | AutoVerticalScrollTextView textView = (AutoVerticalScrollTextView) findViewById(R.id.autoVerticalScrollTextView); 74 | 75 | list = new ArrayList<>(); 76 | for (int i = 0; i < 5; i++) { 77 | if (i == 0 || i == 2 || i == 4) { 78 | list.add(Html.fromHtml("" + "测试垂直滚动" + "" + i + "特殊")); 79 | } else { 80 | list.add("测试垂直滚动" + i); 81 | } 82 | } 83 | 84 | // 初始化 85 | aUtil = new AutoVerticalScrollTextViewUtil(textView, list); 86 | aUtil.setDuration(5000)// 设置上下滚动事件间隔 87 | .start(); 88 | // 点击事件监听 89 | aUtil.setOnMyClickListener(this); 90 | } 91 | 92 | // autoVerticalScrollTextView点击事件监听 93 | @Override 94 | public void onMyClickListener(int position, CharSequence title) { 95 | Toast.makeText(this, list.get(position) + " --- " + title, Toast.LENGTH_SHORT).show(); 96 | if (aUtil.getIsRunning()) 97 | // 停止滚动 98 | aUtil.stop(); 99 | else 100 | // 开启滚动 101 | aUtil.start(); 102 | } 103 | 104 | @Override 105 | protected void onDestroy() { 106 | super.onDestroy(); 107 | aUtil.stop(); 108 | } 109 | } 110 | ``` 111 | Android:不一样的TextView(三)SpannableStringTextView。 112 | ``` 113 | TextView testTv = (TextView) findViewById(R.id.tv_test); 114 | 115 | // testTv.setText("测试修改颜色"); 116 | // SpannableStringTextViewUtil.updateForeColorSpan(testTv, 1, 3, "#40aff2"); 117 | 118 | // testTv.setText("测试添加颜色"); 119 | // SpannableStringTextViewUtil.addForeColorSpan(testTv, "TEST", 1, 3 , "#40aff2"); 120 | 121 | // testTv.setText("测试修改颜色"); 122 | // SpannableStringTextViewUtil.updateBackColorSpan(testTv, 1, 3, "#40aff2"); 123 | 124 | // testTv.setText("测试添加颜色"); 125 | // SpannableStringTextViewUtil.addBackColorSpan(testTv, "TEST", 1, 3 , "#40aff2"); 126 | 127 | // testTv.setText("测试添加文本大小"); 128 | // SpannableStringTextViewUtil.addFontSizeSpan(testTv, "TEST", 1, 3, 60); 129 | 130 | // testTv.setText("测试添加超链接"); 131 | // SpannableStringTextViewUtil.addUrlSpan(testTv, "超链接", 0, 3, "http://www.baidu.com"); 132 | 133 | // testTv.setText("测试添加点击"); 134 | // SpannableStringTextViewUtil.addClickableSpan(testTv, "点击", 0, 2, new SpannableStringTextViewUtil.OnClickSpanListener() { 135 | // @override 136 | // public void onClickSpan() { 137 | // Toast.makeText(MainActivity.this, "点击", Toast.LENGTH_SHORT).show(); 138 | // } 139 | // }); 140 | 141 | // testTv.setText("测试添加粗体+斜体"); 142 | // SpannableStringTextViewUtil.addStyleSpan(testTv, "TEST", 0, 3); 143 | 144 | // testTv.setText("测试添加粗体"); 145 | // SpannableStringTextViewUtil.addStyleBoldSpan(testTv, "TEST", 0, 3); 146 | 147 | // testTv.setText("测试添加斜体"); 148 | // SpannableStringTextViewUtil.addStyleItalicSpan(testTv, "TEST", 0, 3); 149 | 150 | // testTv.setText("测试添加删除线"); 151 | // SpannableStringTextViewUtil.addStrikeSpan(testTv, "TEST", 0 , 3); 152 | 153 | // testTv.setText("测试修改删除线"); 154 | // SpannableStringTextViewUtil.updateStrikeMySelfSpan(testTv, 0 , 3); 155 | 156 | // testTv.setText("测试添加下划线"); 157 | // SpannableStringTextViewUtil.addUnderLineSpan(testTv, "下划线", 0, 3); 158 | 159 | testTv.setText("测试添加图片"); 160 | SpannableStringTextViewUtil.addImageSpan(testTv, getResources().getDrawable(R.mipmap.ic_launcher) 161 | ``` 162 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion '26.0.2' 6 | defaultConfig { 7 | applicationId "cc.ibooker.ztextview" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.4.0' 28 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 29 | testCompile 'junit:junit:4.12' 30 | compile project(':ztextviewlib') 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\Android_Stadio\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/cc/ibooker/ztextview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package cc.ibooker.ztextview; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("cc.ibooker.ztextview", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/cc/ibooker/ztextview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package cc.ibooker.ztextview; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.text.Html; 7 | import android.widget.TextView; 8 | import android.widget.Toast; 9 | 10 | import java.util.ArrayList; 11 | 12 | import cc.ibooker.ztextviewlib.AutoVerticalScrollTextView; 13 | import cc.ibooker.ztextviewlib.AutoVerticalScrollTextViewUtil; 14 | import cc.ibooker.ztextviewlib.SpannableStringTextViewUtil; 15 | 16 | public class MainActivity extends AppCompatActivity implements AutoVerticalScrollTextViewUtil.OnMyClickListener { 17 | private ArrayList list; 18 | private AutoVerticalScrollTextViewUtil aUtil; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_main); 24 | 25 | AutoVerticalScrollTextView textView = (AutoVerticalScrollTextView) findViewById(R.id.autoVerticalScrollTextView); 26 | 27 | list = new ArrayList<>(); 28 | for (int i = 0; i < 5; i++) { 29 | if (i == 0 || i == 2 || i == 4) { 30 | list.add(Html.fromHtml("" + "测试垂直滚动" + "" + i + "特殊")); 31 | } else { 32 | list.add("测试垂直滚动" + i); 33 | } 34 | } 35 | 36 | // 初始化 37 | aUtil = new AutoVerticalScrollTextViewUtil(textView, list); 38 | 39 | aUtil.setDuration(5000)// 设置上下滚动事件间隔 40 | .setTextColor(Color.parseColor("#40aff2")) 41 | .setTextSize(12) 42 | .start(); 43 | 44 | // 点击事件监听 45 | aUtil.setOnMyClickListener(this); 46 | 47 | 48 | TextView testTv = (TextView) findViewById(R.id.tv_test); 49 | 50 | // testTv.setText("测试修改颜色"); 51 | // SpannableStringTextViewUtil.updateForeColorSpan(testTv, 1, 3, "#40aff2"); 52 | 53 | // testTv.setText("测试添加颜色"); 54 | // SpannableStringTextViewUtil.addForeColorSpan(testTv, "TEST", 1, 3 , "#40aff2"); 55 | 56 | // testTv.setText("测试修改颜色"); 57 | // SpannableStringTextViewUtil.updateBackColorSpan(testTv, 1, 3, "#40aff2"); 58 | 59 | // testTv.setText("测试添加颜色"); 60 | // SpannableStringTextViewUtil.addBackColorSpan(testTv, "TEST", 1, 3 , "#40aff2"); 61 | 62 | // testTv.setText("测试添加文本大小"); 63 | // SpannableStringTextViewUtil.addFontSizeSpan(testTv, "TEST", 1, 3, 60); 64 | 65 | // testTv.setText("测试添加超链接"); 66 | // SpannableStringTextViewUtil.addUrlSpan(testTv, "超链接", 0, 3, "http://www.baidu.com"); 67 | 68 | // testTv.setText("测试添加点击"); 69 | // SpannableStringTextViewUtil.addClickableSpan(testTv, "点击", 0, 2, new SpannableStringTextViewUtil.OnClickSpanListener() { 70 | // @Override 71 | // public void onClickSpan() { 72 | // Toast.makeText(MainActivity.this, "点击", Toast.LENGTH_SHORT).show(); 73 | // } 74 | // }); 75 | 76 | // testTv.setText("测试添加粗体+斜体"); 77 | // SpannableStringTextViewUtil.addStyleSpan(testTv, "TEST", 0, 3); 78 | 79 | // testTv.setText("测试添加粗体"); 80 | // SpannableStringTextViewUtil.addStyleBoldSpan(testTv, "TEST", 0, 3); 81 | 82 | // testTv.setText("测试添加斜体"); 83 | // SpannableStringTextViewUtil.addStyleItalicSpan(testTv, "TEST", 0, 3); 84 | 85 | // testTv.setText("测试添加删除线"); 86 | // SpannableStringTextViewUtil.addStrikeSpan(testTv, "TEST", 0 , 3); 87 | 88 | // testTv.setText("测试修改删除线"); 89 | // SpannableStringTextViewUtil.updateStrikeMySelfSpan(testTv, 0 , 3); 90 | 91 | // testTv.setText("测试添加下划线"); 92 | // SpannableStringTextViewUtil.addUnderLineSpan(testTv, "下划线", 0, 3); 93 | 94 | testTv.setText("测试添加图片"); 95 | SpannableStringTextViewUtil.addImageSpan(testTv, getResources().getDrawable(R.mipmap.ic_launcher)); 96 | } 97 | 98 | // autoVerticalScrollTextView点击事件监听 99 | @Override 100 | public void onMyClickListener(int position, CharSequence title) { 101 | Toast.makeText(this, list.get(position) + " --- " + title, Toast.LENGTH_SHORT).show(); 102 | if (aUtil.getIsRunning()) 103 | // 停止滚动 104 | aUtil.stop(); 105 | else 106 | // 开启滚动 107 | aUtil.start(); 108 | } 109 | 110 | @Override 111 | protected void onDestroy() { 112 | super.onDestroy(); 113 | aUtil.stop(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 19 | 20 | 21 | 25 | 26 | 27 | 39 | 40 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrunker/ZTextView/aeb5210e8be33ca2a4c63adcb170070b4dbd553a/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrunker/ZTextView/aeb5210e8be33ca2a4c63adcb170070b4dbd553a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrunker/ZTextView/aeb5210e8be33ca2a4c63adcb170070b4dbd553a/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrunker/ZTextView/aeb5210e8be33ca2a4c63adcb170070b4dbd553a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrunker/ZTextView/aeb5210e8be33ca2a4c63adcb170070b4dbd553a/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrunker/ZTextView/aeb5210e8be33ca2a4c63adcb170070b4dbd553a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrunker/ZTextView/aeb5210e8be33ca2a4c63adcb170070b4dbd553a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrunker/ZTextView/aeb5210e8be33ca2a4c63adcb170070b4dbd553a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrunker/ZTextView/aeb5210e8be33ca2a4c63adcb170070b4dbd553a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zrunker/ZTextView/aeb5210e8be33ca2a4c63adcb170070b4dbd553a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ZTextView 3 | 案例,通过在XML中进行TextView属性设置来实现跑马灯!这里需要三个方面,简单,文本长度,单行显示。 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/cc/ibooker/ztextview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package cc.ibooker.ztextview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | google() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.0.1' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | jcenter() 19 | google() 20 | } 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } 26 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':ztextviewlib' 2 | -------------------------------------------------------------------------------- /ztextviewlib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /ztextviewlib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile fileTree(dir: 'libs', include: ['*.jar']) 26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 27 | exclude group: 'com.android.support', module: 'support-annotations' 28 | }) 29 | compile 'com.android.support:appcompat-v7:25.3.1' 30 | testCompile 'junit:junit:4.12' 31 | } 32 | -------------------------------------------------------------------------------- /ztextviewlib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\Android_Stadio\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /ztextviewlib/src/androidTest/java/cc/ibooker/ztextviewlib/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package cc.ibooker.ztextviewlib; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("cc.ibooker.ztextviewlib.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ztextviewlib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ztextviewlib/src/main/java/cc/ibooker/ztextviewlib/AutoVerticalScrollTextView.java: -------------------------------------------------------------------------------- 1 | package cc.ibooker.ztextviewlib; 2 | 3 | import android.content.Context; 4 | import android.graphics.Camera; 5 | import android.graphics.Color; 6 | import android.graphics.Matrix; 7 | import android.text.TextUtils; 8 | import android.util.AttributeSet; 9 | import android.view.Gravity; 10 | import android.view.View; 11 | import android.view.animation.AccelerateInterpolator; 12 | import android.view.animation.Animation; 13 | import android.view.animation.Transformation; 14 | import android.widget.TextSwitcher; 15 | import android.widget.TextView; 16 | import android.widget.ViewSwitcher; 17 | 18 | /** 19 | * 自动垂直滚动的TextView 20 | */ 21 | public class AutoVerticalScrollTextView extends TextSwitcher implements ViewSwitcher.ViewFactory { 22 | private Context mContext; 23 | // mInUp,mOutUp分别构成向下翻页的进出动画 24 | private Rotate3dAnimation mInUp; 25 | private Rotate3dAnimation mOutUp; 26 | 27 | private float textSize = 13; // 设置字体大小 28 | private int textColor = Color.parseColor("#555555");// 设置字体颜色 29 | 30 | float getTextSize() { 31 | return textSize; 32 | } 33 | 34 | void setTextSize(float textSize) { 35 | for (int i = 0; i < getChildCount(); i++) { 36 | ((TextView) getChildAt(i)).setTextSize(textSize); 37 | } 38 | this.textSize = textSize; 39 | } 40 | 41 | int getTextColor() { 42 | return textColor; 43 | } 44 | 45 | protected void setTextColor(int textColor) { 46 | for (int i = 0; i < getChildCount(); i++) { 47 | ((TextView) getChildAt(i)).setTextColor(textColor); 48 | } 49 | this.textColor = textColor; 50 | } 51 | 52 | // 构造方法 53 | public AutoVerticalScrollTextView(Context context) { 54 | this(context, null); 55 | } 56 | 57 | public AutoVerticalScrollTextView(Context context, AttributeSet attrs) { 58 | super(context, attrs); 59 | 60 | mContext = context; 61 | init(); 62 | } 63 | 64 | // 初始化 65 | private void init() { 66 | setFactory(this); 67 | 68 | mInUp = createAnim(true, true); 69 | mOutUp = createAnim(false, true); 70 | 71 | setInAnimation(mInUp);//当View显示时动画资源ID 72 | setOutAnimation(mOutUp);//当View隐藏是动画资源ID。 73 | } 74 | 75 | // 创建Rotate3dAnimation 76 | private Rotate3dAnimation createAnim(boolean turnIn, boolean turnUp) { 77 | Rotate3dAnimation rotation = new Rotate3dAnimation(turnIn, turnUp); 78 | rotation.setDuration(1000);//执行动画的时间 79 | rotation.setFillAfter(false);//是否保持动画完毕之后的状态 80 | rotation.setInterpolator(new AccelerateInterpolator());//设置加速模式 81 | return rotation; 82 | } 83 | 84 | // 这里返回的TextView,就是我们看到的View,可以设置自己想要的效果 85 | @Override 86 | public View makeView() { 87 | TextView textView = new TextView(mContext); 88 | textView.setGravity(Gravity.START); 89 | textView.setTextSize(textSize); 90 | textView.setSingleLine(true); 91 | textView.setGravity(Gravity.CENTER_VERTICAL); 92 | textView.setEllipsize(TextUtils.TruncateAt.END); 93 | textView.setTextColor(textColor); 94 | return textView; 95 | } 96 | 97 | // 定义动作,向上滚动翻页 98 | public void next() { 99 | //显示动画 100 | if (getInAnimation() != mInUp) 101 | setInAnimation(mInUp); 102 | //隐藏动画 103 | if (getOutAnimation() != mOutUp) 104 | setOutAnimation(mOutUp); 105 | } 106 | 107 | private class Rotate3dAnimation extends Animation { 108 | private float mCenterX; 109 | private float mCenterY; 110 | private final boolean mTurnIn; 111 | private final boolean mTurnUp; 112 | private Camera mCamera;// 用来保存初始Camera 113 | 114 | Rotate3dAnimation(boolean turnIn, boolean turnUp) { 115 | mTurnIn = turnIn; 116 | mTurnUp = turnUp; 117 | } 118 | 119 | @Override 120 | public void initialize(int width, int height, int parentWidth, int parentHeight) { 121 | super.initialize(width, height, parentWidth, parentHeight); 122 | // 用来记录,初始Camera 高度 宽度 123 | mCamera = new Camera(); 124 | mCenterY = getHeight(); 125 | mCenterX = getWidth(); 126 | } 127 | 128 | /** 129 | * interpolatedTime 0~1 130 | * t 转换 131 | */ 132 | @Override 133 | protected void applyTransformation(float interpolatedTime, Transformation t) { 134 | final float centerX = mCenterX; 135 | final float centerY = mCenterY; 136 | final Camera camera = mCamera; 137 | // 标记是进入还是退出,-1进入,1推送 138 | final int derection = mTurnUp ? 1 : -1; 139 | // 获取转换矩阵 140 | final Matrix matrix = t.getMatrix(); 141 | 142 | camera.save(); 143 | if (mTurnIn) { 144 | // 进入时候,0 -> (derection * mCenterY * (interpolatedTime - 1.0f))[负值] -> 0 145 | camera.translate(0.0f, derection * mCenterY * (interpolatedTime - 1.0f), 0.0f); 146 | } else { 147 | // 退出时候,0 -> (derection * mCenterY * (interpolatedTime - 1.0f))[正值] -> 0 148 | camera.translate(0.0f, derection * mCenterY * (interpolatedTime), 0.0f); 149 | } 150 | camera.getMatrix(matrix); 151 | camera.restore(); 152 | 153 | matrix.preTranslate(-centerX, -centerY); 154 | matrix.postTranslate(centerX, centerY); 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /ztextviewlib/src/main/java/cc/ibooker/ztextviewlib/AutoVerticalScrollTextViewUtil.java: -------------------------------------------------------------------------------- 1 | package cc.ibooker.ztextviewlib; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | import android.support.annotation.ColorInt; 6 | import android.text.TextUtils; 7 | import android.view.View; 8 | 9 | import java.lang.ref.WeakReference; 10 | import java.util.ArrayList; 11 | import java.util.concurrent.ExecutorService; 12 | import java.util.concurrent.Executors; 13 | 14 | /** 15 | * 用来管理AutoVerticalScrollTextView 16 | * Created by 邹峰立 on 2017/6/30. 17 | */ 18 | public class AutoVerticalScrollTextViewUtil { 19 | private static final int MESSAGE_CODE = 200; 20 | 21 | private long duration = 1000;// 停顿时间毫秒(ms)-默认1s 22 | 23 | private MyHandler handler = new MyHandler(this); 24 | 25 | private AutoVerticalScrollTextView textView;// 目标TextView 26 | 27 | private ExecutorService executorService;// 线程池 28 | 29 | private boolean isRunning;// 标记是否为滚动状态 30 | 31 | private int number = 0;// 用来记录滚动次数 32 | private int currentPos = 0;// 标记当前显示哪一项 33 | 34 | private ArrayList mDatas = new ArrayList<>();// 需要轮播的数据源 35 | 36 | private CharSequence title;// 需要改变TextView上面的文本内容 37 | 38 | // 构造方法 39 | public AutoVerticalScrollTextViewUtil(final AutoVerticalScrollTextView textView, ArrayList datas) { 40 | this.mDatas = datas; 41 | this.textView = textView; 42 | // 控件点击事件监听 43 | this.textView.setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View v) { 46 | if (ZTextViewClickUtil.isFastClick()) 47 | return; 48 | if (onMyClickListener != null) 49 | onMyClickListener.onMyClickListener(currentPos, title); 50 | } 51 | }); 52 | } 53 | 54 | // 设置停顿时间ms 55 | public AutoVerticalScrollTextViewUtil setDuration(long duration) { 56 | this.duration = duration; 57 | return this; 58 | } 59 | 60 | // 开始轮播 61 | public void start() { 62 | isRunning = true; 63 | // 开启线程 64 | startThread(); 65 | } 66 | 67 | // 关闭轮播 68 | public void stop() { 69 | isRunning = false; 70 | if (executorService != null) 71 | executorService.shutdownNow(); 72 | } 73 | 74 | // 获取当前运行状态 75 | public boolean getIsRunning() { 76 | return isRunning; 77 | } 78 | 79 | // 设置字体大小 80 | public AutoVerticalScrollTextViewUtil setTextSize(float textSize) { 81 | textView.setTextSize(textSize); 82 | return this; 83 | } 84 | 85 | // 设置字体颜色 86 | public AutoVerticalScrollTextViewUtil setTextColor(@ColorInt int textColor) { 87 | textView.setTextColor(textColor); 88 | return this; 89 | } 90 | 91 | // 开启线程 92 | private void startThread() { 93 | // 定义一个执行线程 94 | Thread thread = new Thread(new Runnable() { 95 | @Override 96 | public void run() { 97 | try { 98 | if (mDatas == null || mDatas.size() <= 0) { 99 | // 当数据源为空的时候,什么都不做 100 | isRunning = false; 101 | } else { 102 | while (isRunning) { 103 | // 获取要显示的数据 104 | currentPos = number % mDatas.size(); 105 | title = mDatas.get(currentPos); 106 | number++; 107 | // 改变文本显示 108 | handler.sendEmptyMessage(MESSAGE_CODE); 109 | // 停顿 110 | Thread.sleep(duration); 111 | } 112 | } 113 | } catch (InterruptedException e) { 114 | e.printStackTrace(); 115 | } 116 | } 117 | }); 118 | // 线程池进行管理 119 | if (executorService == null || executorService.isShutdown()) 120 | executorService = Executors.newSingleThreadScheduledExecutor(); 121 | executorService.execute(thread); 122 | } 123 | 124 | // 定义Handler修改主线程 125 | private static class MyHandler extends Handler { 126 | // 软引用 127 | private final WeakReference mUtil; 128 | 129 | MyHandler(AutoVerticalScrollTextViewUtil util) { 130 | mUtil = new WeakReference<>(util); 131 | } 132 | 133 | @Override 134 | public void handleMessage(Message msg) { 135 | AutoVerticalScrollTextViewUtil currentUtil = mUtil.get(); 136 | if (msg.what == MESSAGE_CODE) { 137 | currentUtil.textView.next(); 138 | if (!TextUtils.isEmpty(currentUtil.title)) 139 | currentUtil.textView.setText(currentUtil.title); 140 | } 141 | } 142 | } 143 | 144 | // 点击事件监听 145 | public interface OnMyClickListener { 146 | void onMyClickListener(int position, CharSequence title); 147 | } 148 | 149 | private OnMyClickListener onMyClickListener; 150 | 151 | public void setOnMyClickListener(OnMyClickListener onMyClickListener) { 152 | this.onMyClickListener = onMyClickListener; 153 | } 154 | } -------------------------------------------------------------------------------- /ztextviewlib/src/main/java/cc/ibooker/ztextviewlib/MarqueeTextView.java: -------------------------------------------------------------------------------- 1 | package cc.ibooker.ztextviewlib; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import android.util.AttributeSet; 6 | 7 | /** 8 | * 跑马灯TextView-自动聚焦 9 | * Created by 邹峰立 on 2017/6/12. 10 | */ 11 | public class MarqueeTextView extends android.support.v7.widget.AppCompatTextView { 12 | 13 | public MarqueeTextView(Context context) { 14 | this(context, null); 15 | } 16 | 17 | public MarqueeTextView(Context context, AttributeSet attrs) { 18 | this(context, attrs, 0); 19 | } 20 | 21 | public MarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) { 22 | super(context, attrs, defStyleAttr); 23 | init(); 24 | } 25 | 26 | // 初始化 27 | private void init() { 28 | // 设置文本超出部分模式 29 | this.setEllipsize(TextUtils.TruncateAt.MARQUEE); 30 | // 设置跑马灯重复次数,-1为无限重复 31 | this.setMarqueeRepeatLimit(-1); 32 | // 单行显示 33 | this.setSingleLine(true); 34 | this.setMaxLines(1); 35 | } 36 | 37 | // 焦点 聚焦 38 | @Override 39 | public boolean isFocused() { 40 | return true; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ztextviewlib/src/main/java/cc/ibooker/ztextviewlib/SpannableStringTextViewUtil.java: -------------------------------------------------------------------------------- 1 | package cc.ibooker.ztextviewlib; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.Typeface; 5 | import android.graphics.drawable.Drawable; 6 | import android.text.Spannable; 7 | import android.text.SpannableString; 8 | import android.text.SpannableStringBuilder; 9 | import android.text.Spanned; 10 | import android.text.method.LinkMovementMethod; 11 | import android.text.style.AbsoluteSizeSpan; 12 | import android.text.style.BackgroundColorSpan; 13 | import android.text.style.ClickableSpan; 14 | import android.text.style.ForegroundColorSpan; 15 | import android.text.style.ImageSpan; 16 | import android.text.style.StrikethroughSpan; 17 | import android.text.style.StyleSpan; 18 | import android.text.style.URLSpan; 19 | import android.text.style.UnderlineSpan; 20 | import android.view.View; 21 | import android.widget.TextView; 22 | 23 | /** 24 | * TextView文本管理类 25 | * 注意几个属性: 26 | * Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(前后都不包括)、 27 | * Spanned.SPAN_INCLUSIVE_EXCLUSIVE(前面包括,后面不包括)、 28 | * Spanned.SPAN_EXCLUSIVE_INCLUSIVE(前面不包括,后面包括)、 29 | * Spanned.SPAN_INCLUSIVE_INCLUSIVE(前后都包括) 30 | * Created by 邹峰立 on 2017/7/10. 31 | */ 32 | public class SpannableStringTextViewUtil { 33 | /** 34 | * 修改TextView原有字体颜色 35 | * 36 | * @param tv TextView 37 | * @param start 开始位置 38 | * @param end 结束位置 39 | * @param color 颜色 16进制 40 | */ 41 | public static void updateForeColorSpan(TextView tv, int start, int end, String color) { 42 | try { 43 | String text = tv.getText().toString(); 44 | SpannableStringBuilder builder = new SpannableStringBuilder(text); 45 | // ForegroundColorSpan为文字前景色 46 | ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.parseColor(color)); 47 | builder.setSpan(colorSpan, start, end >= text.length() ? text.length() : end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 48 | tv.setText(builder); 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | 54 | /** 55 | * 在TextView文本最后添加新文本,新文本可自定义颜色 56 | * 57 | * @param tv 要修改的TextView 58 | * @param text 添加的文本 59 | * @param tStart 修改开始的位置 60 | * @param tEnd 修改结束的位置 61 | * @param color 文本颜色 16进制 62 | */ 63 | public static void addForeColorSpan(TextView tv, String text, int tStart, int tEnd, String color) { 64 | try { 65 | SpannableString spanString = new SpannableString(text); 66 | // ForegroundColorSpan为文字前景色 67 | ForegroundColorSpan span = new ForegroundColorSpan(Color.parseColor(color)); 68 | spanString.setSpan(span, tStart, tEnd >= text.length() ? text.length() : tEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 69 | tv.append(spanString); 70 | } catch (Exception e) { 71 | e.printStackTrace(); 72 | } 73 | } 74 | 75 | /** 76 | * 修改TextView原有字体背景颜色 77 | * 78 | * @param tv TextView 79 | * @param start 开始位置 80 | * @param end 结束位置 81 | * @param color 颜色 16进制 82 | */ 83 | public static void updateBackColorSpan(TextView tv, int start, int end, String color) { 84 | try { 85 | String text = tv.getText().toString(); 86 | SpannableStringBuilder builder = new SpannableStringBuilder(text); 87 | // BackgroundColorSpan为文字背景色 88 | BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.parseColor(color)); 89 | builder.setSpan(colorSpan, start, end >= text.length() ? text.length() : end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 90 | tv.setText(builder); 91 | } catch (Exception e) { 92 | e.printStackTrace(); 93 | } 94 | } 95 | 96 | /** 97 | * 在TextView文本最后添加新文本,新文本可自定义背景颜色 98 | * 99 | * @param tv 要修改的TextView 100 | * @param text 添加的文本 101 | * @param tStart 修改开始的位置 102 | * @param tEnd 修改结束的位置 103 | * @param color 文本颜色 16进制 104 | */ 105 | public static void addBackColorSpan(TextView tv, String text, int tStart, int tEnd, String color) { 106 | try { 107 | SpannableString spanString = new SpannableString(text); 108 | // BackgroundColorSpan为文字背景色 109 | BackgroundColorSpan span = new BackgroundColorSpan(Color.parseColor(color)); 110 | spanString.setSpan(span, tStart, tEnd >= text.length() ? text.length() : tEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 111 | tv.append(spanString); 112 | } catch (Exception e) { 113 | e.printStackTrace(); 114 | } 115 | } 116 | 117 | /** 118 | * 在TextView文本最后添加新文本,新文本可自定义字体大小 119 | * 120 | * @param tv 要修改的TextView 121 | * @param text 添加的文本 122 | * @param tStart 修改开始的位置 123 | * @param tEnd 修改结束的位置 124 | * @param size 文本大小 125 | */ 126 | public static void addFontSizeSpan(TextView tv, String text, int tStart, int tEnd, int size) { 127 | try { 128 | SpannableString spanString = new SpannableString(text); 129 | AbsoluteSizeSpan span = new AbsoluteSizeSpan(size); 130 | spanString.setSpan(span, tStart, tEnd >= text.length() ? text.length() : tEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 131 | tv.append(spanString); 132 | } catch (Exception e) { 133 | e.printStackTrace(); 134 | } 135 | } 136 | 137 | /** 138 | * 在TextView文本最后添加新文本,新文本可自定义超链接 139 | * 140 | * @param tv 要修改的TextView 141 | * @param text 添加的文本 142 | * @param tStart 修改开始的位置 143 | * @param tEnd 修改结束的位置 144 | * @param oper 所要进行的操作如:"http://www.baidu.com"、"tel:10086"、"sms:10086" 145 | */ 146 | public static void addUrlSpan(TextView tv, String text, int tStart, int tEnd, String oper) { 147 | try { 148 | SpannableString spanString = new SpannableString(text); 149 | URLSpan span = new URLSpan(oper); 150 | spanString.setSpan(span, tStart, tEnd >= text.length() ? text.length() : tEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 151 | tv.setMovementMethod(LinkMovementMethod.getInstance());//不设置,没有点击效果 152 | tv.append(spanString); 153 | } catch (Exception e) { 154 | e.printStackTrace(); 155 | } 156 | } 157 | 158 | /** 159 | * 在TextView文本最后添加新文本,新文本可自定义点击效果 160 | * 161 | * @param tv 要修改的TextView 162 | * @param text 添加的文本 163 | * @param tStart 修改开始的位置 164 | * @param tEnd 修改结束的位置 165 | * @param onClickSpanListener 所要进行的操作 166 | */ 167 | public static void addClickableSpan(TextView tv, String text, int tStart, int tEnd, final OnClickSpanListener onClickSpanListener) { 168 | try { 169 | SpannableStringBuilder builder = new SpannableStringBuilder(text); 170 | // 设置文字点击事件 171 | ClickableSpan clickableSpan = new ClickableSpan() { 172 | @Override 173 | public void onClick(View widget) { 174 | if (onClickSpanListener != null) 175 | onClickSpanListener.onClickSpan(); 176 | } 177 | }; 178 | builder.setSpan(clickableSpan, tStart, tEnd >= text.length() ? text.length() : tEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 179 | tv.setMovementMethod(LinkMovementMethod.getInstance());//不设置,没有点击效果 180 | tv.append(builder); 181 | } catch (Exception e) { 182 | e.printStackTrace(); 183 | } 184 | } 185 | 186 | // ClickableSpan点击监听接口 187 | public interface OnClickSpanListener { 188 | void onClickSpan(); 189 | } 190 | 191 | /** 192 | * 在TextView文本最后添加新文本,新文本可自定义粗体,斜体 193 | * 194 | * @param tv 要修改的TextView 195 | * @param text 添加的文本 196 | * @param tStart 修改开始的位置 197 | * @param tEnd 修改结束的位置 198 | */ 199 | public static void addStyleSpan(TextView tv, String text, int tStart, int tEnd) { 200 | try { 201 | SpannableString spanString = new SpannableString(text); 202 | StyleSpan span = new StyleSpan(Typeface.BOLD_ITALIC); 203 | spanString.setSpan(span, tStart, tEnd >= text.length() ? text.length() : tEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 204 | tv.append(spanString); 205 | } catch (Exception e) { 206 | e.printStackTrace(); 207 | } 208 | } 209 | 210 | /** 211 | * 在TextView文本最后添加新文本,新文本可自定义粗体 212 | * 213 | * @param tv 要修改的TextView 214 | * @param text 添加的文本 215 | * @param tStart 修改开始的位置 216 | * @param tEnd 修改结束的位置 217 | */ 218 | public static void addStyleBoldSpan(TextView tv, String text, int tStart, int tEnd) { 219 | try { 220 | SpannableString spanString = new SpannableString(text); 221 | StyleSpan span = new StyleSpan(Typeface.BOLD); 222 | spanString.setSpan(span, tStart, tEnd >= text.length() ? text.length() : tEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 223 | tv.append(spanString); 224 | } catch (Exception e) { 225 | e.printStackTrace(); 226 | } 227 | } 228 | 229 | /** 230 | * 在TextView文本最后添加新文本,新文本可自定义斜体 231 | * 232 | * @param tv 要修改的TextView 233 | * @param text 添加的文本 234 | * @param tStart 修改开始的位置 235 | * @param tEnd 修改结束的位置 236 | */ 237 | public static void addStyleItalicSpan(TextView tv, String text, int tStart, int tEnd) { 238 | try { 239 | SpannableString spanString = new SpannableString(text); 240 | StyleSpan span = new StyleSpan(Typeface.ITALIC); 241 | spanString.setSpan(span, tStart, tEnd >= text.length() ? text.length() : tEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 242 | tv.append(spanString); 243 | } catch (Exception e) { 244 | e.printStackTrace(); 245 | } 246 | } 247 | 248 | /** 249 | * 在TextView文本最后添加新文本,新文本可自定义删除线 250 | * 251 | * @param tv 要修改的TextView 252 | * @param text 添加的文本 253 | * @param tStart 修改开始的位置 254 | * @param tEnd 修改结束的位置 255 | */ 256 | public static void addStrikeSpan(TextView tv, String text, int tStart, int tEnd) { 257 | try { 258 | SpannableString spanString = new SpannableString(text); 259 | StrikethroughSpan span = new StrikethroughSpan(); 260 | spanString.setSpan(span, tStart, tEnd >= text.length() ? text.length() : tEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 261 | tv.append(spanString); 262 | } catch (Exception e) { 263 | e.printStackTrace(); 264 | } 265 | } 266 | 267 | /** 268 | * 修改原有文本删除线效果 269 | * 270 | * @param tv 要修改的TextView 271 | * @param start 修改开始的位置 272 | * @param end 修改结束的位置 273 | */ 274 | public static void updateStrikeMySelfSpan(TextView tv, int start, int end) { 275 | try { 276 | String text = tv.getText().toString().trim(); 277 | SpannableString spanString = new SpannableString(text); 278 | StrikethroughSpan span = new StrikethroughSpan(); 279 | spanString.setSpan(span, start, end >= text.length() ? text.length() : end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 280 | tv.setText(spanString); 281 | } catch (Exception e) { 282 | e.printStackTrace(); 283 | } 284 | } 285 | 286 | /** 287 | * 在TextView文本最后添加新文本,新文本可自定义下划线 288 | * 289 | * @param tv 要修改的TextView 290 | * @param text 添加的文本 291 | * @param tStart 修改开始的位置 292 | * @param tEnd 修改结束的位置 293 | */ 294 | public static void addUnderLineSpan(TextView tv, String text, int tStart, int tEnd) { 295 | try { 296 | SpannableString spanString = new SpannableString(text); 297 | UnderlineSpan span = new UnderlineSpan(); 298 | spanString.setSpan(span, tStart, tEnd >= text.length() ? text.length() : tEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 299 | tv.append(spanString); 300 | } catch (Exception e) { 301 | e.printStackTrace(); 302 | } 303 | } 304 | 305 | /** 306 | * 在TextView文本最后添加图片 307 | * 308 | * @param tv 要修改的TextView 309 | * @param d 图片 310 | */ 311 | public static void addImageSpan(TextView tv, Drawable d) { 312 | try { 313 | SpannableString spanString = new SpannableString(" "); 314 | d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); 315 | ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE); 316 | spanString.setSpan(span, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 317 | tv.append(spanString); 318 | } catch (Exception e) { 319 | e.printStackTrace(); 320 | } 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /ztextviewlib/src/main/java/cc/ibooker/ztextviewlib/ZTextViewClickUtil.java: -------------------------------------------------------------------------------- 1 | package cc.ibooker.ztextviewlib; 2 | 3 | /** 4 | * 点击事件处理 5 | */ 6 | public class ZTextViewClickUtil { 7 | private static long lastClickTime; 8 | 9 | // 判断是否为快速点击事件 10 | public synchronized static boolean isFastClick() { 11 | long time = System.currentTimeMillis(); 12 | if (time - lastClickTime < 500) 13 | return true; 14 | lastClickTime = time; 15 | return false; 16 | } 17 | } -------------------------------------------------------------------------------- /ztextviewlib/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ZTextViewLib 3 | 4 | -------------------------------------------------------------------------------- /ztextviewlib/src/test/java/cc/ibooker/ztextviewlib/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package cc.ibooker.ztextviewlib; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } --------------------------------------------------------------------------------