├── .gitignore ├── README-zh-rCN.md ├── README.md ├── app ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── chenenyu │ │ └── ftldemo │ │ ├── CustomActivity.java │ │ ├── DemoActivity.java │ │ ├── MainActivity.java │ │ └── MockData.java │ └── res │ ├── layout │ ├── activity_custom.xml │ ├── activity_demo.xml │ └── activity_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ ├── ic_github.png │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-en │ └── strings.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── arts ├── ftl-cn.gif └── ftl-en.gif ├── build.gradle ├── demo.apk ├── ftl ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── chenenyu │ │ └── freetimeline │ │ ├── FreeTimeLine.java │ │ ├── FreeTimeLineConfig.java │ │ ├── FreeTimeLineElement.java │ │ └── internal │ │ ├── ConnectorView.java │ │ ├── FreeTimeLineAdapter.java │ │ ├── FreeTimeLineUI.java │ │ └── ToggleView.java │ └── res │ ├── layout │ └── __ftl_node_row.xml │ └── values │ └── ftl_attrs.xml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .gradle 3 | gradle.properties 4 | local.properties 5 | .idea 6 | build 7 | *.iml 8 | # /gradle 9 | androidTest 10 | bintray.gradle 11 | test -------------------------------------------------------------------------------- /README-zh-rCN.md: -------------------------------------------------------------------------------- 1 | ![Download](https://api.bintray.com/packages/chenenyu/maven/FreeTimeLine/images/download.svg) 2 | # FreeTimeLine 3 | *美观灵活强大的时间轴组件.* 4 | 5 | [示例apk](demo.apk) 6 | 7 | ![gif](arts/ftl-cn.gif) 8 | 9 | ### Android Studio: 10 | 11 | `compile 'com.chenenyu.freetimeline:ftl:2.1'` 12 | 13 | ### Eclipse: 14 | 呵呵... 15 | 16 | ## 可用属性: 17 | 18 | |属性|类型|描述| 19 | |:---:|:---:|:---:| 20 | |top_type|enum|顶部结点的样式(sucker/solid/hollow)| 21 | |node_type|enum|中间节点的样式(solid/hollow)| 22 | |bottom_type|enum|底部结点的样式(solid/hollow)| 23 | |line_color|color|轴线的颜色| 24 | |solid_color|color|实心圆的颜色| 25 | |hollow_color|color|空心圆的颜色| 26 | |sucker_color|color|吸盘(sucker)样式的颜色| 27 | |toggle_color|color|折叠按钮的颜色| 28 | |left_color|color|左侧文本的颜色| 29 | |left_size|dimension|左侧文本的大小(默认13sp)| 30 | |parent_color|color|中间标题文本的颜色| 31 | |parent_size|dimension|中间标题文本的大小(默认14sp)| 32 | |child_color|color|中间详细文本的颜色| 33 | |child_size|dimension|中间详细文本的大小(默认12sp)| 34 | |show_toggle|boolean|是否显示折叠按钮| 35 | 36 | 上述所有属性都可在xml或者代码中配置 37 | 38 | 39 | ***其他的自定义属性将会陆续的添加进来!*** 40 | 41 | ## 使用: 42 | xml中: 43 | 44 | 57 | 58 | 然后设置内容元素: 59 | 60 | `ftl.setElements(List);` 61 | 62 | 同样可以在代码中改变配置: 63 | 64 | `ftl.setConfig(FreeTimeLineConfig config);` 65 | 66 | 67 | **欢迎提交代码、bug和讨论 : )** 68 | 69 | ## License 70 | 71 | 请确保你已知晓该[开源协议](http://www.apache.org/licenses/LICENSE-2.0)! 72 | 73 | ``` 74 | Copyright 2016 chenenyu. 75 | 76 | Licensed under the Apache License, Version 2.0 (the "License"); 77 | you may not use this file except in compliance with the License. 78 | You may obtain a copy of the License at 79 | 80 | http://www.apache.org/licenses/LICENSE-2.0 81 | 82 | Unless required by applicable law or agreed to in writing, software 83 | distributed under the License is distributed on an "AS IS" BASIS, 84 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 85 | See the License for the specific language governing permissions and 86 | limitations under the License. 87 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Download](https://api.bintray.com/packages/chenenyu/maven/FreeTimeLine/images/download.svg) 2 | ## [Chinese Version 中文版](README-zh-rCN.md) 3 | # FreeTimeLine 4 | *Beautiful and powerful time-line component for android.* 5 | 6 | [Demo apk](demo.apk) 7 | 8 | ![gif](arts/ftl-en.gif) 9 | 10 | ### Android Studio: 11 | `compile 'com.chenenyu.freetimeline:ftl:2.1'` 12 | ### Eclipse: 13 | Hehe... 14 | 15 | ## Avaliable attrs: 16 | 17 | |attr|format|description| 18 | |:---:|:---:|:---:| 19 | |top_type|enum|Top type(sucker/solid/hollow)| 20 | |node_type|enum|Node type(solid/hollow)| 21 | |bottom_type|enum|Bottom type(solid/hollow)| 22 | |line_color|color|Vertival axes color| 23 | |solid_color|color|Solid circle color| 24 | |hollow_color|color|Hollow circle color| 25 | |sucker_color|color|Sucker type color| 26 | |toggle_color|color|Toggle button color| 27 | |left_color|color|Left text color| 28 | |left_size|dimension|Left text size(default 13sp)| 29 | |parent_color|color|Title text color| 30 | |parent_size|dimension|Title text size(default 14sp)| 31 | |child_color|color|Detail text color| 32 | |child_size|dimension|Detail text size(default 12sp)| 33 | |show_toggle|boolean|Whether to show toggle button| 34 | 35 | All of above can be configed in xml or code. 36 | 37 | 38 | ***Other features and custom attrs will be added one after another!*** 39 | 40 | ## How to use? 41 | in xml: 42 | 43 | 56 | 57 | Then set elements: 58 | 59 | `ftl.setElements(List);` 60 | 61 | You also can change defalut config in code: 62 | 63 | `ftl.setConfig(FreeTimeLineConfig);` 64 | 65 | 66 | **Welcome to submit pull requests and open iusses! : )** 67 | 68 | ## License 69 | 70 | Please make sure you know about this [license](http://www.apache.org/licenses/LICENSE-2.0)! 71 | 72 | ``` 73 | Copyright 2016 chenenyu. 74 | 75 | Licensed under the Apache License, Version 2.0 (the "License"); 76 | you may not use this file except in compliance with the License. 77 | You may obtain a copy of the License at 78 | 79 | http://www.apache.org/licenses/LICENSE-2.0 80 | 81 | Unless required by applicable law or agreed to in writing, software 82 | distributed under the License is distributed on an "AS IS" BASIS, 83 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 84 | See the License for the specific language governing permissions and 85 | limitations under the License. 86 | ``` -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.chenenyu.ftldemo" 9 | minSdkVersion 15 10 | targetSdkVersion 23 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 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile project(':ftl') 25 | compile 'com.android.support:appcompat-v7:23.1.1' 26 | compile 'com.android.support:design:23.1.1' 27 | compile 'com.github.danielnilsson9:color-picker-view:1.4.0' 28 | compile 'com.jakewharton:butterknife:7.0.1' 29 | } 30 | -------------------------------------------------------------------------------- /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/Cheney/workspace/AndroidSDK/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 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/chenenyu/ftldemo/CustomActivity.java: -------------------------------------------------------------------------------- 1 | package com.chenenyu.ftldemo; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.MenuItem; 7 | 8 | import com.chenenyu.freetimeline.FreeTimeLine; 9 | import com.chenenyu.freetimeline.FreeTimeLineConfig; 10 | 11 | import butterknife.Bind; 12 | import butterknife.ButterKnife; 13 | 14 | public class CustomActivity extends AppCompatActivity { 15 | 16 | @Bind(R.id.ftl) 17 | FreeTimeLine mFtl; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_custom); 23 | ButterKnife.bind(this); 24 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 25 | Intent intent = getIntent(); 26 | FreeTimeLineConfig config = (FreeTimeLineConfig) intent.getSerializableExtra("config"); 27 | mFtl.setConfig(config); 28 | mFtl.setElements(MockData.getCustomData()); 29 | } 30 | 31 | @Override 32 | public boolean onOptionsItemSelected(MenuItem item) { 33 | int id = item.getItemId(); 34 | if (id == android.R.id.home) { 35 | finish(); 36 | return true; 37 | } 38 | return super.onOptionsItemSelected(item); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/chenenyu/ftldemo/DemoActivity.java: -------------------------------------------------------------------------------- 1 | package com.chenenyu.ftldemo; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.MenuItem; 6 | 7 | import com.chenenyu.freetimeline.FreeTimeLine; 8 | 9 | public class DemoActivity extends AppCompatActivity { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_demo); 15 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 16 | FreeTimeLine ftl = (FreeTimeLine) findViewById(R.id.ftl); 17 | ftl.setElements(MockData.getCustomData()); 18 | } 19 | 20 | @Override 21 | public boolean onOptionsItemSelected(MenuItem item) { 22 | int id = item.getItemId(); 23 | if (id == android.R.id.home) { 24 | finish(); 25 | return true; 26 | } 27 | return super.onOptionsItemSelected(item); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/chenenyu/ftldemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.chenenyu.ftldemo; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.support.design.widget.FloatingActionButton; 7 | import android.support.design.widget.Snackbar; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.widget.Button; 12 | import android.widget.RadioButton; 13 | import android.widget.RadioGroup; 14 | 15 | import com.chenenyu.freetimeline.FreeTimeLineConfig; 16 | import com.chenenyu.freetimeline.internal.FreeTimeLineUI; 17 | import com.github.danielnilsson9.colorpickerview.dialog.ColorPickerDialogFragment; 18 | import com.github.danielnilsson9.colorpickerview.dialog.ColorPickerDialogFragment.ColorPickerDialogListener; 19 | 20 | import butterknife.Bind; 21 | import butterknife.ButterKnife; 22 | 23 | public class MainActivity extends AppCompatActivity implements ColorPickerDialogListener, View.OnClickListener, RadioGroup.OnCheckedChangeListener { 24 | private ColorPickerDialogFragment lineColorFragment, solidColorFragment, hollowColorFragment; 25 | private int lineColor = FreeTimeLineUI.DEFAULT_LINE_COLOR; 26 | private int solidColor = FreeTimeLineUI.DEFAULT_SOLID_COLOR; 27 | private int hollowColor = FreeTimeLineUI.DEFAULT_HOLLOW_COLOR; 28 | private int topType = FreeTimeLineUI.TOP_HOLLOW; 29 | private int nodeType = FreeTimeLineUI.NODE_HOLLOW; 30 | private int bottomType = FreeTimeLineUI.BOTTOM_SOLID; 31 | private boolean showToggle = true; 32 | 33 | @Bind(R.id.rg_top_type) 34 | RadioGroup mRgTopType; 35 | 36 | @Bind(R.id.rg_node_type) 37 | RadioGroup mRgNodeType; 38 | 39 | @Bind(R.id.rg_bottom_type) 40 | RadioGroup mRgBottomType; 41 | 42 | @Bind(R.id.rg_show_toggle) 43 | RadioGroup mRgShowToggle; 44 | 45 | @Bind(R.id.btn_line_color) 46 | Button mBtnLineColor; 47 | @Bind(R.id.btn_solid_color) 48 | Button mBtnSolidColor; 49 | @Bind(R.id.btn_hollow_color) 50 | Button mBtnHollowColor; 51 | 52 | @Bind(R.id.fab) 53 | FloatingActionButton mFab; 54 | @Bind(R.id.btn_ok) 55 | Button mBtnOk; 56 | @Bind(R.id.btn_demo) 57 | Button mBtnDemo; 58 | 59 | @Override 60 | protected void onCreate(Bundle savedInstanceState) { 61 | super.onCreate(savedInstanceState); 62 | setContentView(R.layout.activity_main); 63 | ButterKnife.bind(this); 64 | 65 | lineColorFragment = ColorPickerDialogFragment.newInstance(0, getString(R.string.line_color), null, Color.WHITE, true); 66 | solidColorFragment = ColorPickerDialogFragment.newInstance(1, getString(R.string.solid_color), null, Color.WHITE, true); 67 | hollowColorFragment = ColorPickerDialogFragment.newInstance(2, getString(R.string.hollow_color), null, Color.WHITE, true); 68 | 69 | mRgTopType.setOnCheckedChangeListener(this); 70 | mRgNodeType.setOnCheckedChangeListener(this); 71 | mRgBottomType.setOnCheckedChangeListener(this); 72 | mRgShowToggle.setOnCheckedChangeListener(this); 73 | 74 | mFab.setOnClickListener(this); 75 | mBtnLineColor.setOnClickListener(this); 76 | mBtnSolidColor.setOnClickListener(this); 77 | mBtnHollowColor.setOnClickListener(this); 78 | mBtnOk.setOnClickListener(this); 79 | mBtnDemo.setOnClickListener(this); 80 | } 81 | 82 | @Override 83 | public void onColorSelected(int dialogId, int color) { 84 | switch (dialogId) { 85 | case 0: 86 | lineColor = color; 87 | mBtnLineColor.setTextColor(lineColor); 88 | break; 89 | case 1: 90 | solidColor = color; 91 | mBtnSolidColor.setTextColor(solidColor); 92 | break; 93 | case 2: 94 | hollowColor = color; 95 | mBtnHollowColor.setTextColor(hollowColor); 96 | break; 97 | } 98 | } 99 | 100 | @Override 101 | public void onDialogDismissed(int dialogId) { 102 | // Log.d("onDialogDismissed", dialogId + ""); 103 | } 104 | 105 | @Override 106 | public void onClick(View v) { 107 | if (v == mFab) { 108 | Snackbar.make(v, getString(R.string.snack_info), Snackbar.LENGTH_LONG).show(); 109 | } else if (v == mBtnLineColor) { 110 | lineColorFragment.show(getFragmentManager(), "lineColorFragment"); 111 | } else if (v == mBtnSolidColor) { 112 | solidColorFragment.show(getFragmentManager(), "solidColorFragment"); 113 | } else if (v == mBtnHollowColor) { 114 | hollowColorFragment.show(getFragmentManager(), "hollowColorFragment"); 115 | } else if (v == mBtnOk) { 116 | FreeTimeLineConfig config = new FreeTimeLineConfig(); 117 | config.setTopType(topType) 118 | .setNodeType(nodeType) 119 | .setBottomType(bottomType) 120 | .setLineColor(lineColor) 121 | .setHollowColor(hollowColor) 122 | .setSolidColor(solidColor) 123 | .setShowToggle(showToggle); 124 | Intent intent = new Intent(MainActivity.this, CustomActivity.class); 125 | intent.putExtra("config", config); 126 | startActivity(intent); 127 | } else if (v == mBtnDemo) { 128 | Intent intent = new Intent(MainActivity.this, DemoActivity.class); 129 | startActivity(intent); 130 | } 131 | } 132 | 133 | @Override 134 | public void onCheckedChanged(RadioGroup group, int checkedId) { 135 | if (group == mRgTopType) { 136 | switch (checkedId) { 137 | case R.id.rb_top_sucker: 138 | topType = FreeTimeLineUI.TOP_SUCKER; 139 | break; 140 | case R.id.rb_top_solid: 141 | topType = FreeTimeLineUI.TOP_SOLID; 142 | break; 143 | case R.id.rb_top_hollow: 144 | topType = FreeTimeLineUI.TOP_HOLLOW; 145 | break; 146 | } 147 | } else if (group == mRgNodeType) { 148 | switch (checkedId) { 149 | case R.id.rb_node_hollow: 150 | nodeType = FreeTimeLineUI.NODE_HOLLOW; 151 | break; 152 | case R.id.rb_node_solid: 153 | nodeType = FreeTimeLineUI.NODE_SOLID; 154 | break; 155 | } 156 | } else if (group == mRgBottomType) { 157 | switch (checkedId) { 158 | case R.id.rb_bottom_hollow: 159 | bottomType = FreeTimeLineUI.BOTTOM_HOLLOW; 160 | break; 161 | case R.id.rb_bottom_solid: 162 | bottomType = FreeTimeLineUI.BOTTOM_SOLID; 163 | break; 164 | } 165 | } else if (group == mRgShowToggle) { 166 | switch (checkedId) { 167 | case R.id.rb_show_toggle: 168 | showToggle = true; 169 | break; 170 | case R.id.rb_hide_toggle: 171 | showToggle = false; 172 | break; 173 | } 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /app/src/main/java/com/chenenyu/ftldemo/MockData.java: -------------------------------------------------------------------------------- 1 | package com.chenenyu.ftldemo; 2 | 3 | import com.chenenyu.freetimeline.FreeTimeLineElement; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Mock 10 | * Created by Cheney on 16/1/11. 11 | */ 12 | public class MockData { 13 | public static List getCustomData() { 14 | List elements = new ArrayList<>(); 15 | FreeTimeLineElement element; 16 | element = new FreeTimeLineElement("Init FreeTimeLine", "init", "2016/01/06"); 17 | elements.add(element); 18 | element = new FreeTimeLineElement("v1.0", "1.top_type \n2.line_color \n3.solid_color \n4.hollow_color \n5.toggle_color", "2016/01/08"); 19 | elements.add(element); 20 | element = new FreeTimeLineElement("add type", "1:node type\n2:bottom type", "2016/01/09"); 21 | elements.add(element); 22 | element = new FreeTimeLineElement("v2.0-alpha大量更新", "吸盘样式及字体大小和颜色的自定义", "2016/01/10"); 23 | elements.add(element); 24 | element = new FreeTimeLineElement("v2.1", "大量重构及自定义显示隐藏折叠按钮", "2016/01/11"); 25 | elements.add(element); 26 | return elements; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_custom.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 20 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 13 | 19 | 24 | 29 | 34 | 35 | 36 | 42 | 47 | 52 | 53 | 54 | 60 | 65 | 70 | 71 | 72 | 78 | 83 | 88 | 89 | 90 |