├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── lcodecore │ │ └── expandtextview │ │ ├── BaseActivity.java │ │ └── MainActivity.java │ └── res │ ├── drawable-xxhdpi │ └── ic_create_white_36dp.png │ ├── layout │ ├── activity_main.xml │ ├── content_main.xml │ └── item_extext.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── art ├── 20161005.gif └── app-debug.apk ├── build.gradle ├── extextview ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── lcodecore │ │ └── extextview │ │ ├── DensityUtil.java │ │ └── ExpandTextView.java │ └── res │ ├── drawable-xhdpi │ ├── ic_collapse_small_holo_light.png │ └── ic_expand_small_holo_light.png │ └── values │ ├── attrs.xml │ └── strings.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 支持展开的TextView----ExpandTextView 2 | 3 | 参考开源项目[ExpendableTextView](https://github.com/Manabu-GT/ExpandableTextView), 4 | 原项目使用LinearLayout包装TextView和Button的做法,需要保证id的一致,文本内容需要在代码中设置,操作较为复杂,笔者的做法则更加简单简洁一些, 5 | 直接继承自TextView,保留TextView完整特性,且简化了操作,核心思想就是动态的设定TextView的padding值。 6 | 本控件解决了不同分辨率下适配的问题,增加了一些新的属性,优化了像setMaxLine()/setMaxHeight()会导致的多次requestLayout的问题,解决了在列表控件中使用会出现的展开/折叠错位的问题。 7 | 同样也良好的支持了列表控件,RecyclerView,ScrollView,AbsListView等。 8 | 9 | ### Demo演示 10 | [下载Demo](art/app-debug.apk) 11 | 12 | ![](./art/20161005.gif) 13 | 14 | ### 属性 15 | - maxCollapsedLines 设置开始折叠的行数 16 | - animDuration 展开/折叠动画时长 17 | - animAlphaStart 透明度渐变起始值 18 | - expandDrawable 指示展开状态的图标 19 | - collapseDrawable 指示折叠状态的图标 20 | - **arrowAlign** 指示状态的图标的对齐方式,有左/上,居中,右/下可选 21 | - **arrowPosition** 指示状态的图标位置,两种可选,在text的右边和在text的下面 22 | - **arrowPadding** 可以设置图标离文字的间距 23 | 24 | ### 使用 25 | ### 添加gradle依赖 26 | ``` 27 | compile 'com.lcodecorex:extextview:1.0.2' 28 | ``` 29 | 30 | ### layout文件中添加配置 31 | ```xml 32 | 43 | ``` 44 | 45 | 其它按TextView的使用方法使用即可。 46 | 47 | ### 事件监听 48 | et.setOnExpandStateChangeListener() 可以监听展开和折叠状态的变化。 49 | ```java 50 | void onChangeStateStart(boolean willExpanded); 51 | void onExpandStateChanged(TextView textView, boolean isExpanded); 52 | ``` 53 | 54 | ### 更新日志 55 | #### v1.02 56 | - 修复在列表控件中滚动的高度计算问题 57 | - 去除多余的依赖 58 | - 解决展开/折叠在列表控件中使用的错位问题 59 | - 性能优化,减少了requestLayout的次数 60 | 61 | #### v1.01 62 | - 解决不同分辨率的适配问题 63 | - 支持个性化展开图标 64 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.lcodecore.expandtextview" 9 | minSdkVersion 14 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | lintOptions { 21 | abortOnError false 22 | } 23 | } 24 | 25 | dependencies { 26 | compile fileTree(dir: 'libs', include: ['*.jar']) 27 | compile project(':extextview') 28 | compile 'com.android.support:design:25.2.0' 29 | compile 'com.android.support:appcompat-v7:25.2.0' 30 | } 31 | -------------------------------------------------------------------------------- /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 /Users/lcodecore/Documents/android_sdk_macosx/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 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/lcodecore/expandtextview/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.lcodecore.expandtextview; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.Toolbar; 8 | import android.view.View; 9 | 10 | /** 11 | * Created by lcodecore on 16/3/2. 12 | */ 13 | public abstract class BaseActivity extends AppCompatActivity { 14 | 15 | @Override 16 | protected void onCreate(@Nullable Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(setInflateId()); 19 | init(); 20 | initAcition(); 21 | } 22 | 23 | //设置布局id 24 | public abstract int setInflateId(); 25 | 26 | //视图,组件,数据的初始化 27 | public abstract void init(); 28 | 29 | //事件监听 30 | public void initAcition(){} 31 | 32 | //Activity设置带返回按钮的Toolbar 33 | public void setupBackToolbar(String title){ 34 | setupBackToolbar(R.id.toolbar,title); 35 | } 36 | 37 | public void setupBackToolbar(int toolbarId,String title){ 38 | Toolbar mToolbar = (Toolbar) findViewById(toolbarId); 39 | setSupportActionBar(mToolbar); 40 | getSupportActionBar().setHomeButtonEnabled(true); //显示小箭头 41 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 42 | mToolbar.setNavigationOnClickListener(new View.OnClickListener() { 43 | @Override 44 | public void onClick(View v) { 45 | onBackPressed(); 46 | } 47 | }); 48 | setTitle(title); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/lcodecore/expandtextview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.lcodecore.expandtextview; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.Toolbar; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ArrayAdapter; 11 | import android.widget.ListView; 12 | 13 | import com.lcodecore.extextview.ExpandTextView; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public class MainActivity extends BaseActivity { 19 | 20 | @Override 21 | public int setInflateId() { 22 | return R.layout.activity_main; 23 | } 24 | 25 | @Override 26 | public void init() { 27 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 28 | setSupportActionBar(toolbar); 29 | 30 | // ListView lv = (ListView) findViewById(R.id.lv); 31 | // List data = new ArrayList<>(); 32 | String test = getString(R.string.test); 33 | data.add(test); 34 | data.add(test); 35 | data.add(test); 36 | data.add(test); 37 | data.add(test); 38 | data.add(test); 39 | data.add(test); 40 | data.add(test); 41 | data.add(test); 42 | data.add(test); 43 | data.add(test); 44 | data.add(test); 45 | data.add(test); 46 | data.add(test); 47 | // 48 | // lv.setAdapter(new ArrayAdapter(this, R.layout.item_extext, R.id.tv_expand, data)); 49 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); 50 | recyclerView.setLayoutManager(new LinearLayoutManager(this)); 51 | recyclerView.setAdapter(new RecyclerAdapter()); 52 | } 53 | 54 | private List data = new ArrayList<>(); 55 | 56 | private class RecyclerAdapter extends RecyclerView.Adapter { 57 | 58 | 59 | @Override 60 | public Holder onCreateViewHolder(ViewGroup parent, int viewType) { 61 | return new Holder(View.inflate(MainActivity.this, R.layout.item_extext, null)); 62 | } 63 | 64 | @Override 65 | public void onBindViewHolder(Holder holder, int position) { 66 | holder.tv.setText(data.get(position)); 67 | } 68 | 69 | @Override 70 | public int getItemCount() { 71 | return data.size(); 72 | } 73 | } 74 | 75 | class Holder extends RecyclerView.ViewHolder { 76 | ExpandTextView tv; 77 | 78 | public Holder(View itemView) { 79 | super(itemView); 80 | tv = (ExpandTextView) itemView.findViewById(R.id.tv_expand); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_create_white_36dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcodecorex/ExpandTextView/c50ab3bba30969994a470bd75063ec6a8f705737/app/src/main/res/drawable-xxhdpi/ic_create_white_36dp.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 23 | 24 | 34 | 35 | 45 | 46 | 57 | 58 | 69 | 70 | 81 | 82 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_extext.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcodecorex/ExpandTextView/c50ab3bba30969994a470bd75063ec6a8f705737/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcodecorex/ExpandTextView/c50ab3bba30969994a470bd75063ec6a8f705737/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcodecorex/ExpandTextView/c50ab3bba30969994a470bd75063ec6a8f705737/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcodecorex/ExpandTextView/c50ab3bba30969994a470bd75063ec6a8f705737/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcodecorex/ExpandTextView/c50ab3bba30969994a470bd75063ec6a8f705737/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #353536 4 | #262626 5 | #e75946 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ExpandTextView 3 | Java 是一种跨平台的、解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中。Java 字节码中包括了很多源代码信息,如变量名、方法名,很容易被反编译成 Java 源代码。所以需要对java代码进行混淆。混淆就是对发布出去的程序进行重新组织和处理,混淆器将代码中的所有变量、函数、类的名称变为简短的英文字母代号,反编译后将难以阅读。 4 | 5 | 同时混淆的时候会遍历代码以发现没有被调用的代码,从而将其在打包成apk时剔除,最终一定程度上降低了apk的大小,比如编译后 jar 文件体积大约能减少25% 。 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 14 | 15 |