├── .gitignore
├── .idea
├── assetWizardSettings.xml
├── caches
│ └── build_file_checksums.ser
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── misc.xml
└── runConfigurations.xml
├── JavaTimeLine
├── .gitignore
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── github
│ │ └── rangaofei
│ │ └── javatimeline
│ │ ├── AdapterUtil.java
│ │ ├── AnnotationProcessor.java
│ │ ├── TimeLineContext.java
│ │ ├── processor
│ │ ├── AnchorProcessor.java
│ │ ├── DividerProcessor.java
│ │ ├── ImageViewProcessor.java
│ │ ├── TextViewProcessor.java
│ │ ├── TimeLineProcess.java
│ │ ├── TimeLineProcessor.java
│ │ └── ViewProcessor.java
│ │ ├── utils
│ │ └── StringUtil.java
│ │ └── viewattr
│ │ ├── AnchorInfo.java
│ │ ├── ImageViewAttr.java
│ │ └── TextViewAttr.java
│ └── test
│ └── java
│ └── io
│ └── github
│ └── rangaofei
│ └── javatimeline
│ └── utils
│ └── StringUtilTest.java
├── Pics
├── Screenshot_1532504922.png
├── SimpleStepViewUnnormal.png
├── StepViewAnim.gif
├── StepViewCustomDrawable.png
├── StepViewDiff.png
├── StepView_anim.webm
├── eight.png
├── muke.mp4
├── muke.png
├── simple_stepview_all.png
├── simple_stepview_left.png
├── taobao.png
└── wechat.jpg
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── io
│ │ └── github
│ │ └── rangaofei
│ │ └── timeline
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── io
│ │ │ └── github
│ │ │ └── rangaofei
│ │ │ └── timeline
│ │ │ ├── BaseModel.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MukeBean.java
│ │ │ ├── MukeFragment.java
│ │ │ ├── StepViewModel.java
│ │ │ ├── SwipeAdapter.java
│ │ │ ├── SwipeRecyclerViewActivity.java
│ │ │ ├── TaobaoFragment.java
│ │ │ └── TimeLineAdapter.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── bg_rect.xml
│ │ ├── dot_grey.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_offline_pin_black_24dp.xml
│ │ ├── ic_order.xml
│ │ └── withpadding.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_swipe_recycler_view.xml
│ │ ├── fragment_blank.xml
│ │ ├── fragment_muke.xml
│ │ ├── item.xml
│ │ ├── item_key.xml
│ │ ├── item_muke.xml
│ │ ├── item_swipe.xml
│ │ └── item_value.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.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
│ └── io
│ └── github
│ └── rangaofei
│ └── timeline
│ └── ExampleUnitTest.java
├── build.gradle
├── config.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── libannotations
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── github
│ └── rangaofei
│ └── libannotations
│ ├── TimeConfig.java
│ ├── TimeLine.java
│ ├── TimeLineAnchor.java
│ ├── TimeLineDividerAdapter.java
│ ├── TimeLineImageView.java
│ ├── TimeLineTextView.java
│ └── TimeLineView.java
├── sakatimeline
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── io
│ │ └── github
│ │ └── rangaofei
│ │ └── sakatimeline
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── io
│ │ │ └── github
│ │ │ └── rangaofei
│ │ │ └── sakatimeline
│ │ │ ├── TimeLineView.java
│ │ │ ├── adapter
│ │ │ ├── AbstractTimeLineAdapter.java
│ │ │ ├── BaseViewHolder.java
│ │ │ ├── ItemClickListener.java
│ │ │ └── ItemTypeStrategy.java
│ │ │ ├── config
│ │ │ ├── IndexTextConfig.java
│ │ │ ├── StepViewConfig.java
│ │ │ ├── StrokeType.java
│ │ │ └── TimeLineConfig.java
│ │ │ ├── customlayoutmanager
│ │ │ ├── PerfectLinearLayoutManager.java
│ │ │ ├── ScrollbarHelper.java
│ │ │ ├── TimeLineGridLayoutManager.java
│ │ │ ├── TimeLineLayoutManager.java
│ │ │ └── ViewBoundsCheck.java
│ │ │ ├── divider
│ │ │ ├── BaseDivider.java
│ │ │ ├── DividerLayoutAdapter.java
│ │ │ ├── ItemTouchUIUtilImpl.java
│ │ │ ├── LeftOnlyDivider.java
│ │ │ ├── LeftRightDivider.java
│ │ │ ├── RightOnlyDivider.java
│ │ │ ├── SakaItemTouchHelper.java
│ │ │ ├── SingleStepViewDivider.java
│ │ │ ├── SlideTouchHelperCallBack.java
│ │ │ ├── SwipeBehavior.java
│ │ │ ├── TimeLineDivider.java
│ │ │ └── TimeLineType.java
│ │ │ ├── exception
│ │ │ ├── BaseException.java
│ │ │ ├── ExceptionMessage.java
│ │ │ ├── TimeLineException.java
│ │ │ └── TimeLineViewException.java
│ │ │ ├── indexdecoration
│ │ │ └── IndexDecoration.java
│ │ │ ├── proxy
│ │ │ ├── TextViewInterface.java
│ │ │ ├── TextViewProxy.java
│ │ │ ├── TextViewProxyHandler.java
│ │ │ ├── ViewInterface.java
│ │ │ ├── ViewProxy.java
│ │ │ └── ViewProxyHandler.java
│ │ │ ├── snaphelper
│ │ │ └── ScaleSnapHelper.java
│ │ │ ├── timelineedgeeffect
│ │ │ ├── CustomEdgeEffectFactory.java
│ │ │ └── SakaEffectEdge.java
│ │ │ └── util
│ │ │ ├── AndroidUtil.java
│ │ │ ├── ExceptionUtil.java
│ │ │ └── ProxyUtil.java
│ └── res
│ │ ├── drawable
│ │ ├── drawable_null.xml
│ │ ├── ic_order.xml
│ │ └── order.png
│ │ ├── layout
│ │ └── null_view.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── io
│ └── github
│ └── rangaofei
│ └── sakatimeline
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 | /.idea
12 |
--------------------------------------------------------------------------------
/.idea/assetWizardSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/JavaTimeLine/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/JavaTimeLine/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | apply plugin: 'com.jfrog.bintray'
4 |
5 |
6 |
7 | version = project.ext.version
8 |
9 | dependencies {
10 | implementation fileTree(include: ['*.jar'], dir: 'libs')
11 | // implementation 'com.google.auto:auto-common:0.10'
12 | implementation 'com.google.auto.service:auto-service:1.0-rc3'
13 | implementation 'com.squareup:javapoet:1.9.0'
14 | testImplementation 'junit:junit:4.12'
15 | implementation 'com.rangaofei:libannotations:0.2.1'
16 | }
17 |
18 | //sourceCompatibility = "1.8"
19 | //targetCompatibility = "1.8"
20 |
21 |
22 |
23 | def siteUrl = 'https://github.com/rangaofei/TimeLine'
24 | def gitUrl = 'https://github.com/rangaofei/TimeLine'
25 | group = "com.rangaofei"
26 |
27 | install {
28 | repositories.mavenInstaller {
29 | // This generates POM.xml with proper parameters
30 | pom {
31 | project {
32 | packaging 'jar'
33 | name 'JavaTimeLine'
34 | // #CONFIG# // project title
35 | url siteUrl
36 | // Set your license
37 | licenses {
38 | license {
39 | name 'The Apache Software License, Version 2.0'
40 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
41 | }
42 | }
43 | developers {
44 | developer {
45 | id 'tudou'
46 | // #CONFIG# // your user id (you can write your nickname)
47 | name 'rangaofei'
48 | // #CONFIG# // your user name
49 | email '876038559@qq.com'
50 | // #CONFIG# // your email
51 | }
52 | }
53 | scm {
54 | connection gitUrl
55 | developerConnection gitUrl
56 | url siteUrl
57 | }
58 | }
59 | }
60 | }
61 | }
62 |
63 | task sourcesJar(type: Jar) {
64 | classifier = 'sources'
65 | from sourceSets.main.allSource
66 | }
67 |
68 |
69 |
70 | task javadocJar(type: Jar, dependsOn: javadoc) {
71 | classifier = 'javadoc'
72 | from javadoc.destinationDir
73 | }
74 |
75 | artifacts {
76 | archives sourcesJar
77 | }
78 |
79 | Properties properties = new Properties()
80 | boolean isHasFile = false
81 | if (project.rootProject.file('local.properties') != null) {
82 | isHasFile = true
83 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
84 | }
85 | bintray {
86 | user = isHasFile ? properties.getProperty("bintray.user") : System.getenv("bintray.user")
87 | key = isHasFile ? properties.getProperty("bintray.apikey") : System.getenv("bintray.apikey")
88 | configurations = ['archives']
89 | pkg {
90 | repo = "maven"
91 | name = "JavaTimeLine"
92 | websiteUrl = siteUrl
93 | vcsUrl = gitUrl
94 | licenses = ["Apache-2.0"]
95 | publish = true
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/AdapterUtil.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline;
2 |
3 | import com.squareup.javapoet.ClassName;
4 | import com.squareup.javapoet.CodeBlock;
5 | import com.squareup.javapoet.MethodSpec;
6 | import com.squareup.javapoet.ParameterSpec;
7 | import com.squareup.javapoet.ParameterizedTypeName;
8 | import com.squareup.javapoet.TypeName;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Arrays;
12 | import java.util.List;
13 |
14 | import javax.lang.model.element.Element;
15 | import javax.lang.model.element.Modifier;
16 |
17 | import io.github.rangaofei.javatimeline.viewattr.ImageViewAttr;
18 | import io.github.rangaofei.libannotations.TimeLine;
19 | import io.github.rangaofei.libannotations.TimeLineDividerAdapter;
20 |
21 | public class AdapterUtil {
22 |
23 | public static String generateAdapterName(Element element, String className) {
24 | String generatedName = element.getAnnotation(TimeLine.class).name().trim();
25 | if (generatedName.equals("")) {
26 | generatedName = className.trim() + "Adapter";
27 | }
28 |
29 | return generatedName;
30 | }
31 |
32 | public static String generateDividerAdapterName(Element element, String className) {
33 | String generatedName = element.getAnnotation(TimeLineDividerAdapter.class).value().trim();
34 | if (generatedName.equals("")) {
35 | generatedName = className.trim() + "DividerAdapter";
36 | }
37 | return generatedName;
38 | }
39 |
40 | public static MethodSpec constructorMethod(String fullClassName) {
41 | ClassName list = ClassName.get(java.util.List.class);
42 | TypeName listT = ParameterizedTypeName.get(list, ClassName.bestGuess(fullClassName));
43 | ParameterSpec constructorParameter = ParameterSpec.builder(listT, "list")
44 | .build();
45 | return MethodSpec.constructorBuilder()
46 | .addModifiers(Modifier.PUBLIC)
47 | .addParameter(constructorParameter)
48 | .addStatement("super(list)")
49 | .build();
50 | }
51 |
52 | public static MethodSpec generateOverRideIdMethod(String layoutId, String methodName) {
53 | return MethodSpec.methodBuilder(methodName)
54 | .addModifiers(Modifier.PUBLIC)
55 | .addAnnotation(Override.class)
56 | .returns(int.class)
57 | .addStatement("return $L", layoutId)
58 | .build();
59 |
60 | }
61 |
62 | public static MethodSpec generateBindMethod(String methodName,
63 | String fullClassName,
64 | CodeBlock... codeBlocks) {
65 | ParameterSpec one = ParameterSpec
66 | .builder(ClassName.bestGuess("io.github.rangaofei.sakatimeline.adapter.BaseViewHolder"), "holder")
67 | .build();
68 | ParameterSpec two = ParameterSpec
69 | .builder(ClassName.bestGuess(fullClassName), "data")
70 | .build();
71 |
72 | MethodSpec.Builder bindItemMethod = MethodSpec.methodBuilder(methodName)
73 | .addModifiers(Modifier.PUBLIC)
74 | .addAnnotation(Override.class)
75 | .addParameters(Arrays.asList(one, two));
76 | for (CodeBlock codeBlock : codeBlocks) {
77 | bindItemMethod.addCode(codeBlock);
78 | }
79 | return bindItemMethod.build();
80 |
81 | }
82 |
83 |
84 | public static List getImageViewAttr(List imageViewAttrList, String holderName) {
85 | List codeBlockList = new ArrayList<>();
86 | ClassName imageView = ClassName.bestGuess("android.widget.ImageView");
87 | for (int i = 0; i < imageViewAttrList.size(); i++) {
88 | ImageViewAttr imageViewAttr = imageViewAttrList.get(i);
89 | String filedName = "imageView_" + i;
90 | CodeBlock codeBlock = CodeBlock.builder()
91 | .addStatement("$T $L = (($L)holder).itemView.findViewById($L)",
92 | imageView, filedName, holderName, imageViewAttr.getImageViewId())
93 | .addStatement("$L.setImageResource(data.$L)",
94 | filedName, imageViewAttr.getImageSrc())
95 | .build();
96 | codeBlockList.add(codeBlock);
97 | }
98 |
99 | return codeBlockList;
100 |
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/AnnotationProcessor.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline;
2 |
3 | import com.google.auto.service.AutoService;
4 |
5 | import java.util.HashSet;
6 | import java.util.Set;
7 |
8 | import javax.annotation.processing.AbstractProcessor;
9 | import javax.annotation.processing.Completion;
10 | import javax.annotation.processing.ProcessingEnvironment;
11 | import javax.annotation.processing.Processor;
12 | import javax.annotation.processing.RoundEnvironment;
13 | import javax.lang.model.SourceVersion;
14 | import javax.lang.model.element.AnnotationMirror;
15 | import javax.lang.model.element.Element;
16 | import javax.lang.model.element.ElementKind;
17 | import javax.lang.model.element.ExecutableElement;
18 | import javax.lang.model.element.TypeElement;
19 |
20 | import io.github.rangaofei.javatimeline.TimeLineContext;
21 | import io.github.rangaofei.javatimeline.processor.DividerProcessor;
22 | import io.github.rangaofei.javatimeline.processor.TimeLineProcess;
23 | import io.github.rangaofei.javatimeline.processor.TimeLineProcessor;
24 | import io.github.rangaofei.libannotations.TimeLine;
25 | import io.github.rangaofei.libannotations.TimeLineDividerAdapter;
26 |
27 | /**
28 | * 注解处理入口类
29 | */
30 | @AutoService(Processor.class)
31 | public class AnnotationProcessor extends AbstractProcessor {
32 |
33 |
34 | @Override
35 | public Set getSupportedOptions() {
36 | return super.getSupportedOptions();
37 | }
38 |
39 | @Override
40 | public Set getSupportedAnnotationTypes() {
41 | Set s = new HashSet<>();
42 | s.add(TimeLine.class.getCanonicalName());
43 | return s;
44 | }
45 |
46 | @Override
47 | public SourceVersion getSupportedSourceVersion() {
48 | return super.getSupportedSourceVersion();
49 | }
50 |
51 | @Override
52 | public synchronized void init(ProcessingEnvironment processingEnvironment) {
53 | super.init(processingEnvironment);
54 | TimeLineContext.filter = processingEnvironment.getFiler();
55 | TimeLineContext.messager = processingEnvironment.getMessager();
56 | TimeLineContext.elementUtil = processingEnvironment.getElementUtils();
57 | TimeLineContext.typeUtil = processingEnvironment.getTypeUtils();
58 | }
59 |
60 | @Override
61 | public Iterable extends Completion> getCompletions(Element element, AnnotationMirror annotationMirror, ExecutableElement executableElement, String s) {
62 | return super.getCompletions(element, annotationMirror, executableElement, s);
63 | }
64 |
65 | @Override
66 | public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
67 | Set extends Element> timeLineElements = roundEnvironment.getElementsAnnotatedWith(TimeLine.class);
68 | for (Element element : timeLineElements) {
69 | TimeLineContext.note(element.getSimpleName().toString());
70 | if (element.getKind() != ElementKind.CLASS) {
71 | TimeLineContext.error("%s can not annotated with other than class", TimeLine.class.getName());
72 | throw new RuntimeException("this element is not annotated with class");
73 | }
74 |
75 | createTimeLineAdapter(element);
76 | }
77 |
78 | Set extends Element> dividerElements = roundEnvironment.getElementsAnnotatedWith(TimeLineDividerAdapter.class);
79 | for (Element element : dividerElements) {
80 | TimeLineContext.note(element.getSimpleName().toString());
81 | if (element.getKind() != ElementKind.FIELD) {
82 | throw new RuntimeException("not field");
83 | }
84 | createDividerAdapter(element);
85 | }
86 | return true;
87 | }
88 |
89 |
90 | private void createTimeLineAdapter(Element element) {
91 | TimeLineProcess adapterProcessor = new TimeLineProcessor(element);
92 | adapterProcessor.processAnnotation();
93 | }
94 |
95 | private void createDividerAdapter(Element element) {
96 | TimeLineProcess dividerProcessor = new DividerProcessor(element);
97 | dividerProcessor.processAnnotation();
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/TimeLineContext.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline;
2 |
3 |
4 | import javax.annotation.processing.Filer;
5 | import javax.annotation.processing.Messager;
6 | import javax.lang.model.util.Elements;
7 | import javax.lang.model.util.Types;
8 | import javax.tools.Diagnostic;
9 |
10 | /**
11 | * 上下文的一个类。
12 | * 1. 打印日志
13 | */
14 | public class TimeLineContext {
15 |
16 | public static final String TAG = "TimeLine";
17 | private static final boolean DEBUG = true;
18 | public static Filer filter;
19 |
20 | public static Messager messager;
21 |
22 | public static Elements elementUtil;
23 |
24 | public static Types typeUtil;
25 |
26 |
27 | public static Filer getFilter() {
28 | if (filter == null) {
29 | throw new RuntimeException("filter is null");
30 | }
31 | return filter;
32 | }
33 |
34 |
35 | public static Messager getMessager() {
36 | if (messager == null) {
37 | throw new RuntimeException("messager is null");
38 | }
39 | return messager;
40 | }
41 |
42 |
43 | public static Elements getElementUtil() {
44 | if (elementUtil == null) {
45 | throw new RuntimeException("elementutil is null");
46 | }
47 | return elementUtil;
48 | }
49 |
50 |
51 | public static void note(String msg, Object... args) {
52 | logMessage(Diagnostic.Kind.NOTE, msg, args);
53 | }
54 |
55 | public static void error(String msg, Object... args) {
56 | logMessage(Diagnostic.Kind.ERROR, msg, args);
57 | }
58 |
59 | public static void warning(String msg, Object... args) {
60 | logMessage(Diagnostic.Kind.WARNING, msg, args);
61 | }
62 |
63 | public static void other(String msg, Object... args) {
64 | logMessage(Diagnostic.Kind.OTHER, msg, args);
65 | }
66 |
67 | private static void logMessage(Diagnostic.Kind kind, String msg, Object... args) {
68 | if (DEBUG) {
69 | if (messager == null) {
70 | throw new RuntimeException("Messager is NULL");
71 | }
72 | messager.printMessage(kind, String.format(msg, args));
73 | }
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/processor/AnchorProcessor.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.processor;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import javax.lang.model.element.Element;
7 | import javax.lang.model.util.ElementFilter;
8 |
9 | import io.github.rangaofei.javatimeline.TimeLineContext;
10 | import io.github.rangaofei.javatimeline.viewattr.AnchorInfo;
11 | import io.github.rangaofei.libannotations.TimeLineAnchor;
12 |
13 | public class AnchorProcessor implements TimeLineProcess {
14 | private Element element;
15 | private List anchorInfos;
16 |
17 |
18 | AnchorProcessor(Element element) {
19 | this.element = element;
20 | anchorInfos = new ArrayList<>();
21 | }
22 |
23 | public List getAnchorInfos() {
24 | return anchorInfos;
25 | }
26 |
27 | @Override
28 | public void processAnnotation() {
29 | fillAnchorList();
30 | }
31 |
32 | private void fillAnchorList() {
33 | if (this.element == null) {
34 | return;
35 | }
36 | for (Element e : ElementFilter.fieldsIn(element.getEnclosedElements())) {
37 | if (e.getAnnotation(TimeLineAnchor.class) != null) {
38 | AnchorInfo anchorInfo = new AnchorInfo();
39 | TimeLineAnchor timeLineAnchor = e.getAnnotation(TimeLineAnchor.class);
40 | String filedName = e.getSimpleName().toString();
41 | anchorInfo.setFieldName(filedName);
42 | for (String s : timeLineAnchor.value()) {
43 | anchorInfo.getAnchorIds().add(s);
44 | }
45 | anchorInfos.add(anchorInfo);
46 | }
47 | }
48 |
49 | if (anchorInfos.size() > 1) {
50 | throw new RuntimeException("one TimeLine Annotation class must not have more than one anchor");
51 | }
52 | noteAnchorInfo();
53 | }
54 |
55 | private void noteAnchorInfo() {
56 | if (this.anchorInfos.size() < 1) {
57 | return;
58 | }
59 | StringBuilder sb = new StringBuilder();
60 | for (AnchorInfo anchorInfo : anchorInfos) {
61 | sb.append(anchorInfo.toString());
62 | }
63 | TimeLineContext.note(sb.toString());
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/processor/DividerProcessor.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.processor;
2 |
3 | import com.squareup.javapoet.ClassName;
4 | import com.squareup.javapoet.JavaFile;
5 | import com.squareup.javapoet.MethodSpec;
6 | import com.squareup.javapoet.ParameterSpec;
7 | import com.squareup.javapoet.ParameterizedTypeName;
8 | import com.squareup.javapoet.TypeName;
9 | import com.squareup.javapoet.TypeSpec;
10 |
11 | import java.io.IOException;
12 | import java.util.Arrays;
13 |
14 | import javax.lang.model.element.Element;
15 | import javax.lang.model.element.Modifier;
16 |
17 | import io.github.rangaofei.javatimeline.AdapterUtil;
18 | import io.github.rangaofei.javatimeline.TimeLineContext;
19 |
20 | public class DividerProcessor implements TimeLineProcess {
21 | private Element element;
22 |
23 | private String packageName;
24 | private String className;
25 | private String fullClassName;
26 | private String adapterName;
27 |
28 | private MethodSpec constructorMethod;
29 |
30 | public DividerProcessor(Element element) {
31 | this.element = element;
32 | }
33 |
34 | @Override
35 | public void processAnnotation() {
36 | getBasicField();
37 | generateConstructor();
38 | try {
39 | generateAdapter();
40 | } catch (IOException e) {
41 | e.printStackTrace();
42 | }
43 | }
44 |
45 | private void getBasicField() {
46 | if (this.element == null) {
47 | throw new RuntimeException("element is null");
48 | }
49 | TimeLineContext.note("---1");
50 | packageName = TimeLineContext.elementUtil.getPackageOf(element).getQualifiedName().toString();
51 | TimeLineContext.note("---2");
52 | className = element.getSimpleName().toString();
53 | TimeLineContext.note("---3");
54 | fullClassName = packageName + "." + className;
55 | adapterName = AdapterUtil.generateDividerAdapterName(element, className);
56 | TimeLineContext.note("---4");
57 | noteBasicInfo();
58 | }
59 |
60 | private void generateConstructor() {
61 | ClassName list = ClassName.get(java.util.List.class);
62 | TypeName listT = ParameterizedTypeName.get(list, ClassName.bestGuess("android.graphics.drawable.Drawable"));
63 | ParameterSpec constructorParameter = ParameterSpec.builder(listT, "list")
64 | .build();
65 | constructorMethod = MethodSpec.constructorBuilder()
66 | .addModifiers(Modifier.PUBLIC)
67 | .addParameter(constructorParameter)
68 | .addStatement("super(list)").build();
69 | }
70 |
71 | private void generateAdapter() throws IOException {
72 | if (this.element == null) {
73 | return;
74 | }
75 | TypeSpec adapter = TypeSpec.classBuilder(adapterName)
76 | .superclass(ClassName.bestGuess("io.github.rangaofei.sakatimeline.divider.DividerLayoutAdapter"))
77 | .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
78 | .addMethods(Arrays.asList(constructorMethod))
79 | .build();
80 | JavaFile javaFile = JavaFile.builder(packageName, adapter)
81 | .build();
82 | javaFile.writeTo(TimeLineContext.filter);
83 | }
84 |
85 | /**
86 | * 日志输出标注的类的基本信息
87 | */
88 | private void noteBasicInfo() {
89 | TimeLineContext.note(">>>>packageName=%s", packageName);
90 | TimeLineContext.note(">>>>className=%s", className);
91 | TimeLineContext.note(">>>>fullClassName=%s", fullClassName);
92 | TimeLineContext.note(">>>>adapterName=%s", adapterName);
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/processor/ImageViewProcessor.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.processor;
2 |
3 | import com.squareup.javapoet.ClassName;
4 | import com.squareup.javapoet.CodeBlock;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | import javax.lang.model.element.Element;
10 | import javax.lang.model.util.ElementFilter;
11 |
12 | import io.github.rangaofei.javatimeline.TimeLineContext;
13 | import io.github.rangaofei.javatimeline.utils.StringUtil;
14 | import io.github.rangaofei.javatimeline.viewattr.AnchorInfo;
15 | import io.github.rangaofei.javatimeline.viewattr.ImageViewAttr;
16 | import io.github.rangaofei.libannotations.TimeLineImageView;
17 |
18 | public class ImageViewProcessor implements TimeLineProcess {
19 | private Element element;
20 | private List anchorInfoList;
21 | private CodeBlock keyCodeBlock;
22 | private CodeBlock valueCodeBlock;
23 | private List imageViewAttrList;
24 | private ClassName imageView;
25 |
26 | public ImageViewProcessor(Element element, List anchorInfoList) {
27 | this.element = element;
28 | this.anchorInfoList = anchorInfoList;
29 | imageViewAttrList = new ArrayList<>();
30 | imageView = ClassName.bestGuess("android.widget.ImageView");
31 | }
32 |
33 |
34 | public CodeBlock getKeyCodeBlock() {
35 | return keyCodeBlock;
36 | }
37 |
38 | public CodeBlock getValueCodeBlock() {
39 | return valueCodeBlock;
40 | }
41 |
42 | @Override
43 | public void processAnnotation() {
44 | getImageViewAttr();
45 | keyCodeBlock = generateImageViewCode(true);
46 | valueCodeBlock = generateImageViewCode(false);
47 | }
48 |
49 | private void getImageViewAttr() {
50 | if (this.element == null) {
51 | return;
52 | }
53 | for (Element e : ElementFilter.fieldsIn(element.getEnclosedElements())) {
54 | if (e.getAnnotation(TimeLineImageView.class) != null) {
55 | TimeLineImageView imageView = e.getAnnotation(TimeLineImageView.class);
56 | String filedName = e.getSimpleName().toString();
57 | ImageViewAttr imageViewAttr = new ImageViewAttr(imageView.id(), filedName, imageView.key());
58 | imageViewAttrList.add(imageViewAttr);
59 |
60 | }
61 | }
62 | }
63 |
64 | private CodeBlock generateImageViewCode(boolean isKey) {
65 | String holderName = null;
66 | if (isKey) {
67 | holderName = "KeyViewHolder";
68 | } else {
69 | holderName = "ValueViewHolder";
70 | }
71 | CodeBlock.Builder builder = CodeBlock.builder();
72 | for (int i = 0; i < imageViewAttrList.size(); i++) {
73 | ImageViewAttr imageViewAttr = imageViewAttrList.get(i);
74 | String filedName = "imageView_" + i;
75 | if (isKey && !imageViewAttr.isKey()) {
76 | continue;
77 | }
78 | if (!isKey && imageViewAttr.isKey()) {
79 | continue;
80 | }
81 | if (!StringUtil.isResId(imageViewAttr.getImageViewId())) {
82 | logError("%s is not a standard resId format", imageViewAttr.getImageViewId());
83 | }
84 | builder.addStatement("$T $L = (($L)holder).itemView.findViewById($L)",
85 | imageView, filedName, holderName, imageViewAttr.getImageViewId());
86 | builder.addStatement("$L.setImageResource(data.$L)", filedName, imageViewAttr.getImageSrc());
87 | // if (anchorInfoList.size() < 1 ||
88 | // !anchorInfoList.get(0).getAnchorIds().contains(imageViewAttr.getImageViewId())) {
89 | // if (!imageViewAttr.getImageSrc().equals(TimeConfig.ID_NULL)) {
90 | //
91 | // }
92 | //
93 | // } else {
94 | // builder.beginControlFlow("if (data.$L)", anchorInfoList.get(0).getFieldName());
95 | // if (!imageViewAttr.getStyleAnchorId().equals(TimeConfig.ID_NULL)) {
96 | // generateTextViewProxyCode(builder, filedName, imageViewAttr.getStyleAnchorId());
97 | // }
98 | // builder.nextControlFlow("else ");
99 | // if (!imageViewAttr.getStyleId().equals(TimeConfig.ID_NULL)) {
100 | // generateTextViewProxyCode(builder, filedName, imageViewAttr.getStyleId());
101 | // }
102 | // builder.endControlFlow();
103 | // if (imageViewAttr.getTextString() != null) {
104 | // builder.addStatement("$L.setText(data.$L)", filedName, imageViewAttr.getTextString());
105 | // }
106 | // }
107 | }
108 | return builder.build();
109 | }
110 |
111 | private void logError(String msg, Object... args) {
112 | TimeLineContext.error(msg, args);
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/processor/TextViewProcessor.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.processor;
2 |
3 | import com.squareup.javapoet.ClassName;
4 | import com.squareup.javapoet.CodeBlock;
5 | import com.squareup.javapoet.ParameterizedTypeName;
6 | import com.squareup.javapoet.TypeName;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | import javax.lang.model.element.Element;
12 | import javax.lang.model.util.ElementFilter;
13 |
14 | import io.github.rangaofei.javatimeline.viewattr.AnchorInfo;
15 | import io.github.rangaofei.javatimeline.viewattr.TextViewAttr;
16 | import io.github.rangaofei.libannotations.TimeConfig;
17 | import io.github.rangaofei.libannotations.TimeLineTextView;
18 |
19 | public class TextViewProcessor implements TimeLineProcess {
20 |
21 | private Element element;
22 | private List textViewAttrList;
23 | private CodeBlock keyCodeBlock;
24 | private CodeBlock valueCodeBlock;
25 | private ClassName textView;
26 | private List anchorInfoList;
27 |
28 | public TextViewProcessor(Element element, List anchorInfoList) {
29 | this.element = element;
30 | this.anchorInfoList = anchorInfoList;
31 | textViewAttrList = new ArrayList<>();
32 | textView = ClassName.bestGuess("android.widget.TextView");
33 | }
34 |
35 | public CodeBlock getKeyCodeBlock() {
36 | return keyCodeBlock;
37 | }
38 |
39 | public CodeBlock getValueCodeBlock() {
40 | return valueCodeBlock;
41 | }
42 |
43 | @Override
44 | public void processAnnotation() {
45 | getTextViewAttr();
46 | keyCodeBlock = generateTextViewCodeBlock(true);
47 | valueCodeBlock = generateTextViewCodeBlock(false);
48 | }
49 |
50 | private void getTextViewAttr() {
51 | if (this.element == null) {
52 | return;
53 | }
54 | for (Element e : ElementFilter.fieldsIn(element.getEnclosedElements())) {
55 | if (e.getAnnotation(TimeLineTextView.class) != null) {
56 | TimeLineTextView textView = e.getAnnotation(TimeLineTextView.class);
57 | String filedName = e.getSimpleName().toString();
58 | TextViewAttr textViewAttr = new TextViewAttr(filedName, textView);
59 | textViewAttrList.add(textViewAttr);
60 |
61 | }
62 | }
63 |
64 | }
65 |
66 | private CodeBlock generateTextViewCodeBlock(boolean isKey) {
67 | ClassName proxyUtil = ClassName.bestGuess("io.github.rangaofei.sakatimeline.util.ProxyUtil");
68 | ClassName viewInterface = ClassName.get("io.github.rangaofei.sakatimeline.proxy", "ViewInterface");
69 | TypeName viewInterfaceOfTextView = ParameterizedTypeName.get(viewInterface, textView);
70 | String holderName = null;
71 | if (isKey) {
72 | holderName = "KeyViewHolder";
73 | } else {
74 | holderName = "ValueViewHolder";
75 | }
76 | CodeBlock.Builder builder = CodeBlock.builder();
77 | for (int i = 0; i < textViewAttrList.size(); i++) {
78 | TextViewAttr textViewAttr = textViewAttrList.get(i);
79 | String filedName = "textView_" + i;
80 | if (isKey && !textViewAttr.isKey()) {
81 | continue;
82 | }
83 | if (!isKey && textViewAttr.isKey()) {
84 | continue;
85 | }
86 | // builder.addStatement("$T $L = (($L)holder).itemView.findViewById($L)",
87 | // textView, filedName, holderName, textViewAttr.getTextViewId());
88 | builder.addStatement("$T $L = $T.createView(($L)holder,$L)",
89 | viewInterfaceOfTextView, filedName, proxyUtil, holderName, textViewAttr.getTextViewId());
90 | if (anchorInfoList.size() < 1 ||
91 | !anchorInfoList.get(0).getAnchorIds().contains(textViewAttr.getTextViewId())) {
92 | if (!textViewAttr.getStyleId().equals(TimeConfig.ID_NULL)) {
93 | generateTextViewProxyCode(builder, filedName, textViewAttr.getStyleId());
94 | }
95 | if (textViewAttr.getTextString() != null) {
96 | builder.addStatement("$L.getView().setText(data.$L)", filedName, textViewAttr.getTextString());
97 | }
98 | } else {
99 | builder.beginControlFlow("if (data.$L)", anchorInfoList.get(0).getFieldName());
100 | if (!textViewAttr.getStyleAnchorId().equals(TimeConfig.ID_NULL)) {
101 | generateTextViewProxyCode(builder, filedName, textViewAttr.getStyleAnchorId());
102 | }
103 | builder.nextControlFlow("else ");
104 | if (!textViewAttr.getStyleId().equals(TimeConfig.ID_NULL)) {
105 | generateTextViewProxyCode(builder, filedName, textViewAttr.getStyleId());
106 | } else {
107 | generateTextViewProxyCode(builder, filedName, "R.style.DefaultViewAttr");
108 | }
109 | builder.endControlFlow();
110 | if (textViewAttr.getTextString() != null) {
111 | builder.addStatement("$L.getView().setText(data.$L)", filedName, textViewAttr.getTextString());
112 | }
113 | }
114 | }
115 | return builder.build();
116 | }
117 |
118 | private void generateTextViewProxyCode(CodeBlock.Builder builder, String fieldName, String styleId) {
119 | // ClassName textViewInterface =
120 | // ClassName.bestGuess("io.github.rangaofei.sakatimeline.proxy.TextViewInterface");
121 | // ClassName textViewProxy =
122 | // ClassName.bestGuess("io.github.rangaofei.sakatimeline.proxy.TextViewProxy");
123 | // ClassName textViewProxyHandler =
124 | // ClassName.bestGuess("io.github.rangaofei.sakatimeline.proxy.TextViewProxyHandler");
125 | // ClassName proxy =
126 | // ClassName.bestGuess("java.lang.reflect.Proxy");
127 | // builder.addStatement("$T textProxy=($T)$T.newProxyInstance(\n" +
128 | // " TextViewInterface.class.getClassLoader(),\n" +
129 | // " new Class[]{TextViewInterface.class},\n" +
130 | // " new $T($L))",
131 | // textViewInterface, textViewInterface, proxy, textViewProxyHandler,fieldName);
132 | // builder.addStatement("textProxy.setTextAppearance($L.getContext(), $L)",
133 | // fieldName, styleId);
134 |
135 | builder.addStatement("$L.setStyle($L)", fieldName, styleId);
136 |
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/processor/TimeLineProcess.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.processor;
2 |
3 | public interface TimeLineProcess {
4 | void processAnnotation();
5 | }
6 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/processor/TimeLineProcessor.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.processor;
2 |
3 | import com.squareup.javapoet.ClassName;
4 | import com.squareup.javapoet.CodeBlock;
5 | import com.squareup.javapoet.JavaFile;
6 | import com.squareup.javapoet.MethodSpec;
7 | import com.squareup.javapoet.ParameterizedTypeName;
8 | import com.squareup.javapoet.TypeName;
9 | import com.squareup.javapoet.TypeSpec;
10 |
11 | import java.io.IOException;
12 | import java.util.Arrays;
13 | import java.util.List;
14 |
15 | import javax.lang.model.element.Element;
16 | import javax.lang.model.element.Modifier;
17 |
18 | import io.github.rangaofei.javatimeline.AdapterUtil;
19 | import io.github.rangaofei.javatimeline.TimeLineContext;
20 | import io.github.rangaofei.javatimeline.viewattr.AnchorInfo;
21 | import io.github.rangaofei.libannotations.TimeLine;
22 |
23 | /**
24 | * 处理TimeLine注解
25 | */
26 | public class TimeLineProcessor implements TimeLineProcess {
27 | private Element element;
28 | private String adapterName;
29 | private String packageName;
30 | private String className;
31 | private String fullClassName;
32 | private String keyLayoutId;
33 | private String valueLayoutId;
34 | private MethodSpec getKeyLayoutIdMethod;
35 | private MethodSpec getValueLayoutIdMethod;
36 | private MethodSpec bindKeyItemMethod;
37 | private MethodSpec bindValueItemMethod;
38 | private MethodSpec constructorMethod;
39 |
40 | private AnchorProcessor anchorProcessor;
41 | private List anchorInfoList;
42 |
43 | public TimeLineProcessor(Element element) {
44 | this.element = element;
45 | }
46 |
47 | @Override
48 | public void processAnnotation() {
49 | getBasicField();
50 | generateConstructorMethod();
51 | processAnchor();
52 | generateLayoutIdMethod();
53 | generateBindMethod();
54 | try {
55 | generateAdapter();
56 | } catch (IOException e) {
57 | e.printStackTrace();
58 | }
59 | }
60 |
61 | /**
62 | * 获取TimeLine标注的类的基本信息
63 | * 包名
64 | * 类名
65 | * 类的全路径名
66 | * 适配器名
67 | */
68 | private void getBasicField() {
69 | if (this.element == null) {
70 | throw new RuntimeException("element is null");
71 | }
72 | packageName = TimeLineContext.elementUtil.getPackageOf(element).getQualifiedName().toString();
73 | className = element.getSimpleName().toString();
74 | fullClassName = packageName + "." + className;
75 | adapterName = AdapterUtil.generateAdapterName(element, className);
76 | noteBasicInfo();
77 | }
78 |
79 | private void generateConstructorMethod() {
80 | constructorMethod = AdapterUtil.constructorMethod(fullClassName);
81 | TimeLineContext.note(constructorMethod.toString());
82 | }
83 |
84 | /**
85 | * 获取布局文件的id,并生成对应的复写方法
86 | */
87 | private void generateLayoutIdMethod() {
88 | keyLayoutId = element.getAnnotation(TimeLine.class).keyLayoutId();
89 | getKeyLayoutIdMethod = AdapterUtil.generateOverRideIdMethod(keyLayoutId,
90 | "getKeyLayoutId");
91 | valueLayoutId = element.getAnnotation(TimeLine.class).valueLayoutId();
92 | getValueLayoutIdMethod = AdapterUtil.generateOverRideIdMethod(valueLayoutId,
93 | "getValueLayoutId");
94 | noteLayoutIdMethod();
95 | }
96 |
97 | private void processAnchor() {
98 | anchorProcessor = new AnchorProcessor(element);
99 | anchorProcessor.processAnnotation();
100 | anchorInfoList = anchorProcessor.getAnchorInfos();
101 | }
102 |
103 | private void generateBindMethod() {
104 |
105 | TextViewProcessor textViewProcessor = new TextViewProcessor(element, anchorInfoList);
106 | textViewProcessor.processAnnotation();
107 | CodeBlock keyTextViewCode = textViewProcessor.getKeyCodeBlock();
108 | CodeBlock valueTextCode = textViewProcessor.getValueCodeBlock();
109 |
110 | ImageViewProcessor imageViewProcessor = new ImageViewProcessor(element, anchorInfoList);
111 | imageViewProcessor.processAnnotation();
112 | CodeBlock keyImageViewCode = imageViewProcessor.getKeyCodeBlock();
113 | CodeBlock valueImageViewCode = imageViewProcessor.getValueCodeBlock();
114 |
115 | bindKeyItemMethod = AdapterUtil.generateBindMethod("bindKeyItem",
116 | fullClassName, keyTextViewCode, keyImageViewCode);
117 |
118 | bindValueItemMethod = AdapterUtil.generateBindMethod("bindValueItem",
119 | fullClassName, valueTextCode, valueImageViewCode);
120 | }
121 |
122 | private void generateAdapter() throws IOException {
123 | TypeName superClass = ParameterizedTypeName
124 | .get(ClassName.bestGuess("io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter"),
125 | ClassName.bestGuess(element.getSimpleName().toString()));
126 | TypeSpec adapter = TypeSpec.classBuilder(adapterName)
127 | .superclass(superClass)
128 | .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
129 | .addMethods(Arrays.asList(constructorMethod, getKeyLayoutIdMethod, getValueLayoutIdMethod,
130 | bindKeyItemMethod, bindValueItemMethod))
131 | .build();
132 | JavaFile javaFile = JavaFile.builder(packageName, adapter)
133 | .build();
134 | javaFile.writeTo(TimeLineContext.filter);
135 | }
136 |
137 | /**
138 | * 日志输出标注的类的基本信息
139 | */
140 | private void noteBasicInfo() {
141 | TimeLineContext.note(">>>>packageName=%s", packageName);
142 | TimeLineContext.note(">>>>className=%s", className);
143 | TimeLineContext.note(">>>>fullClassName=%s", fullClassName);
144 | TimeLineContext.note(">>>>adapterName=%s", adapterName);
145 | }
146 |
147 | private void noteLayoutIdMethod() {
148 | TimeLineContext.note(">>>>keyLayoutId:%s", getKeyLayoutIdMethod.toString());
149 | TimeLineContext.note(">>>>valueLayoutId:%s", getValueLayoutIdMethod.toString());
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/processor/ViewProcessor.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.processor;
2 |
3 | import java.util.List;
4 |
5 | import javax.lang.model.element.Element;
6 |
7 | import io.github.rangaofei.javatimeline.viewattr.AnchorInfo;
8 |
9 | public class ViewProcessor implements TimeLineProcess {
10 | private Element element;
11 | private List anchorInfoList;
12 |
13 | public ViewProcessor(Element element, List anchorInfoList) {
14 | this.element = element;
15 | this.anchorInfoList = anchorInfoList;
16 | }
17 |
18 | @Override
19 | public void processAnnotation() {
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/utils/StringUtil.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.utils;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 |
6 | public final class StringUtil {
7 |
8 | private static String layoutIdRegex = "^R\\.layout\\.[a-z_]+$";
9 | private static String resIdRegex = "^R\\.id\\.[A-Za-z1-9_-]+$";
10 |
11 | public static boolean isLayoutId(String src) {
12 | return isMatch(layoutIdRegex, src);
13 | }
14 |
15 | public static boolean isResId(String src) {
16 | return isMatch(resIdRegex, src);
17 | }
18 |
19 | private static boolean isMatch(String regex, String src) {
20 | Pattern pattern = Pattern.compile(regex);
21 | Matcher matcher = pattern.matcher(src);
22 | return matcher.matches();
23 | }
24 |
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/viewattr/AnchorInfo.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.viewattr;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.List;
6 |
7 | public class AnchorInfo {
8 | private String fieldName;
9 | private List anchorIds;
10 |
11 | public AnchorInfo() {
12 | anchorIds = new ArrayList<>();
13 | }
14 |
15 | public AnchorInfo(String fieldName, List anchorIds) {
16 | this.fieldName = fieldName;
17 | this.anchorIds = anchorIds;
18 | }
19 |
20 | public String getFieldName() {
21 | return fieldName;
22 | }
23 |
24 | public void setFieldName(String fieldName) {
25 | this.fieldName = fieldName;
26 | }
27 |
28 | public List getAnchorIds() {
29 | return anchorIds;
30 | }
31 |
32 | public void setAnchorIds(List anchorIds) {
33 | this.anchorIds = anchorIds;
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "AnchorInfo{" +
39 | "fieldName='" + fieldName + '\'' +
40 | ", anchorIds=" + Arrays.toString(anchorIds.toArray()) +
41 | '}';
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/viewattr/ImageViewAttr.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.viewattr;
2 |
3 | public class ImageViewAttr {
4 | private String imageViewId;
5 | private String imageSrc;
6 | private boolean isKey;
7 |
8 | public ImageViewAttr(String imageViewId, String imageSrc, boolean isKey) {
9 | this.imageViewId = imageViewId;
10 | this.imageSrc = imageSrc;
11 | this.isKey = isKey;
12 | }
13 |
14 | public String getImageViewId() {
15 | return imageViewId;
16 | }
17 |
18 | public void setImageViewId(String imageViewId) {
19 | this.imageViewId = imageViewId;
20 | }
21 |
22 | public String getImageSrc() {
23 | return imageSrc;
24 | }
25 |
26 | public void setImageSrc(String imageSrc) {
27 | this.imageSrc = imageSrc;
28 | }
29 |
30 | public boolean isKey() {
31 | return isKey;
32 | }
33 |
34 | public void setKey(boolean key) {
35 | isKey = key;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/main/java/io/github/rangaofei/javatimeline/viewattr/TextViewAttr.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.viewattr;
2 |
3 |
4 | import io.github.rangaofei.libannotations.TimeLineTextView;
5 |
6 | public class TextViewAttr {
7 | private String textViewId;
8 | private String textString;
9 | private boolean isKey;
10 | private String styleId;
11 | private String styleAnchorId;
12 |
13 | public TextViewAttr(String textString, TimeLineTextView textView) {
14 | this.textViewId = textView.id();
15 | this.textString = textString;
16 | this.isKey = textView.key();
17 | this.styleId = textView.style();
18 | this.styleAnchorId = textView.styleAnchor();
19 | }
20 |
21 | public String getTextViewId() {
22 | return textViewId;
23 | }
24 |
25 | public void setTextViewId(String textViewId) {
26 | this.textViewId = textViewId;
27 | }
28 |
29 | public String getTextString() {
30 | return textString;
31 | }
32 |
33 | public void setTextString(String textString) {
34 | this.textString = textString;
35 | }
36 |
37 |
38 | public boolean isKey() {
39 | return isKey;
40 | }
41 |
42 | public void setKey(boolean key) {
43 | isKey = key;
44 | }
45 |
46 | public String getStyleId() {
47 | return styleId;
48 | }
49 |
50 | public void setStyleId(String styleId) {
51 | this.styleId = styleId;
52 | }
53 |
54 | public String getStyleAnchorId() {
55 | return styleAnchorId;
56 | }
57 |
58 | public void setStyleAnchorId(String styleAnchorId) {
59 | this.styleAnchorId = styleAnchorId;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/JavaTimeLine/src/test/java/io/github/rangaofei/javatimeline/utils/StringUtilTest.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.javatimeline.utils;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | public class StringUtilTest {
8 | private String test1 = "R.layout.txt";
9 | private String test2 = "R.ll.123";
10 |
11 | private String test3 = "R.id.ttt";
12 | private String test4 = "R.ii.123";
13 |
14 | @Test
15 | public void isLayoutId() {
16 | boolean b = StringUtil.isLayoutId(test1);
17 | assertTrue(b);
18 |
19 | boolean b1 = StringUtil.isLayoutId(test2);
20 | assertFalse(b1);
21 | }
22 |
23 | @Test
24 | public void isResId() {
25 | boolean b = StringUtil.isResId(test3);
26 | assertTrue(b);
27 |
28 | boolean b1 = StringUtil.isResId(test4);
29 | assertFalse(b1);
30 | }
31 | }
--------------------------------------------------------------------------------
/Pics/Screenshot_1532504922.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/Screenshot_1532504922.png
--------------------------------------------------------------------------------
/Pics/SimpleStepViewUnnormal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/SimpleStepViewUnnormal.png
--------------------------------------------------------------------------------
/Pics/StepViewAnim.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/StepViewAnim.gif
--------------------------------------------------------------------------------
/Pics/StepViewCustomDrawable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/StepViewCustomDrawable.png
--------------------------------------------------------------------------------
/Pics/StepViewDiff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/StepViewDiff.png
--------------------------------------------------------------------------------
/Pics/StepView_anim.webm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/StepView_anim.webm
--------------------------------------------------------------------------------
/Pics/eight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/eight.png
--------------------------------------------------------------------------------
/Pics/muke.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/muke.mp4
--------------------------------------------------------------------------------
/Pics/muke.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/muke.png
--------------------------------------------------------------------------------
/Pics/simple_stepview_all.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/simple_stepview_all.png
--------------------------------------------------------------------------------
/Pics/simple_stepview_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/simple_stepview_left.png
--------------------------------------------------------------------------------
/Pics/taobao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/taobao.png
--------------------------------------------------------------------------------
/Pics/wechat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/Pics/wechat.jpg
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 | applicationId "io.github.rangaofei.timeline"
7 | minSdkVersion 19
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 |
13 | javaCompileOptions {
14 | annotationProcessorOptions.includeCompileClasspath = true
15 | }
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | dataBinding {
25 | enabled = true
26 | }
27 |
28 |
29 | }
30 |
31 | dependencies {
32 | implementation fileTree(include: ['*.jar'], dir: 'libs')
33 | implementation 'com.android.support:appcompat-v7:27.1.1'
34 | implementation 'com.android.support.constraint:constraint-layout:1.1.2'
35 | implementation 'com.android.support:support-v4:27.1.1'
36 | testImplementation 'junit:junit:4.12'
37 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
38 | implementation 'com.android.support:recyclerview-v7:27.1.1'
39 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
40 | implementation project(path: ':sakatimeline')
41 | annotationProcessor project(path: ':JavaTimeLine')
42 | // implementation 'com.rangaofei:sakatimeline:0.2.4'
43 | // annotationProcessor 'com.rangaofei:JavaTimeLine:0.2.4'
44 | implementation 'com.android.support:cardview-v7:27.1.1'
45 | }
46 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/github/rangaofei/timeline/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
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 | * Instrumented 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() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("io.github.rangaofei.timeline", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/io/github/rangaofei/timeline/BaseModel.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 | import android.support.annotation.DrawableRes;
6 | import android.support.annotation.NonNull;
7 |
8 | import io.github.rangaofei.libannotations.TimeLine;
9 | import io.github.rangaofei.libannotations.TimeLineImageView;
10 | import io.github.rangaofei.libannotations.TimeLineTextView;
11 |
12 |
13 | @TimeLine(name = "BaseModelAdapter", keyLayoutId = "R.layout.item_key", valueLayoutId = "R.layout.item_value")
14 | public class BaseModel implements Parcelable, Comparable {
15 |
16 | @TimeLineTextView(id = "R.id.key")
17 | public String key;
18 |
19 | @TimeLineTextView(key = false, id = "R.id.value")
20 | public String value;
21 |
22 | @DrawableRes
23 | @TimeLineImageView(key = false, id = "R.id.iv")
24 | public int imageViewId;
25 |
26 | public BaseModel() {
27 | }
28 |
29 | public BaseModel(String key, String value, int imageViewId) {
30 | this.key = key;
31 | this.value = value;
32 | this.imageViewId = imageViewId;
33 | }
34 |
35 | public String getKey() {
36 | return key;
37 | }
38 |
39 | public void setKey(String key) {
40 | this.key = key;
41 | }
42 |
43 | public String getValue() {
44 | return value;
45 | }
46 |
47 | public void setValue(String value) {
48 | this.value = value;
49 | }
50 |
51 |
52 | @Override
53 | public String toString() {
54 | return "BaseModel{" +
55 | "key='" + key + '\'' +
56 | ", value='" + value + '\'' +
57 | '}';
58 | }
59 |
60 |
61 | @Override
62 | public int describeContents() {
63 | return 0;
64 | }
65 |
66 | @Override
67 | public void writeToParcel(Parcel dest, int flags) {
68 | dest.writeString(this.key);
69 | dest.writeString(this.value);
70 | }
71 |
72 | protected BaseModel(Parcel in) {
73 | this.key = in.readString();
74 | this.value = in.readString();
75 | }
76 |
77 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
78 | @Override
79 | public BaseModel createFromParcel(Parcel source) {
80 | return new BaseModel(source);
81 | }
82 |
83 | @Override
84 | public BaseModel[] newArray(int size) {
85 | return new BaseModel[size];
86 | }
87 | };
88 |
89 | @Override
90 | public int compareTo(@NonNull BaseModel o) {
91 | if (o.key == null) {
92 | return 1;
93 | } else if (this.key == null) {
94 | return -1;
95 | } else {
96 | return this.key.compareToIgnoreCase(o.key);
97 | }
98 |
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/app/src/main/java/io/github/rangaofei/timeline/MainActivity.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.graphics.drawable.Drawable;
5 | import android.os.Bundle;
6 | import android.os.Handler;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.view.View;
9 | import android.widget.Toast;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | import io.github.rangaofei.libannotations.TimeLineDividerAdapter;
15 | import io.github.rangaofei.sakatimeline.TimeLineView;
16 | import io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter;
17 | import io.github.rangaofei.sakatimeline.adapter.ItemClickListener;
18 | import io.github.rangaofei.sakatimeline.divider.TimeLineType;
19 | import io.github.rangaofei.timeline.databinding.ActivityMainBinding;
20 |
21 | public class MainActivity extends AppCompatActivity {
22 | private ActivityMainBinding binding;
23 |
24 |
25 | private AbstractTimeLineAdapter secondAdapter;
26 |
27 | private List secondStepViewModels = new ArrayList<>();
28 |
29 |
30 | @Override
31 | protected void onCreate(Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
34 | binding.btn1.setOnClickListener(new View.OnClickListener() {
35 | @Override
36 | public void onClick(View v) {
37 | getSupportFragmentManager().beginTransaction()
38 | .replace(R.id.ll_container, TaobaoFragment.newInstance("1", "2"))
39 | .commit();
40 | }
41 | });
42 | binding.btn2.setOnClickListener(new View.OnClickListener() {
43 | @Override
44 | public void onClick(View v) {
45 | getSupportFragmentManager().beginTransaction()
46 | .replace(R.id.ll_container, MukeFragment.newInstance("1", "2"))
47 | .commit();
48 | }
49 | });
50 | initRecyclerView();
51 |
52 | }
53 |
54 |
55 | private void initRecyclerView() {
56 |
57 |
58 | secondStepViewModels.add(new StepViewModel("许愿日", true, "04/25"));
59 | secondStepViewModels.add(new StepViewModel("签约日", false, "04/25"));
60 | secondStepViewModels.add(new StepViewModel("签约日", false, "04/25"));
61 | secondStepViewModels.add(new StepViewModel("签约日", false, "04/25"));
62 | secondStepViewModels.add(new StepViewModel("签约日", false, "04/25"));
63 | secondStepViewModels.add(new StepViewModel("签约日", false, "04/25"));
64 | secondStepViewModels.add(new StepViewModel("签约日", false, "04/25"));
65 | secondStepViewModels.add(new StepViewModel("签约日", false, "04/25"));
66 | secondStepViewModels.add(new StepViewModel("签约日", false, "04/25"));
67 | secondStepViewModels.add(new StepViewModel("签约日", false, "04/25"));
68 |
69 |
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/io/github/rangaofei/timeline/MukeBean.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
2 |
3 |
4 | import io.github.rangaofei.libannotations.TimeLine;
5 | import io.github.rangaofei.libannotations.TimeLineTextView;
6 |
7 | @TimeLine(valueLayoutId = "R.layout.item_muke")
8 | public class MukeBean {
9 | @TimeLineTextView(key = false, id = "R.id.time")
10 | public String time;
11 | @TimeLineTextView(key = false, id = "R.id.content")
12 | public String content;
13 |
14 | public MukeBean(String time, String content) {
15 | this.time = time;
16 | this.content = content;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/io/github/rangaofei/timeline/MukeFragment.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
2 |
3 |
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | import io.github.rangaofei.sakatimeline.TimeLineView;
14 | import io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter;
15 | import io.github.rangaofei.sakatimeline.config.TimeLineConfig;
16 | import io.github.rangaofei.sakatimeline.divider.TimeLineType;
17 |
18 |
19 | /**
20 | * A simple {@link Fragment} subclass.
21 | * Use the {@link MukeFragment#newInstance} factory method to
22 | * create an instance of this fragment.
23 | */
24 | public class MukeFragment extends Fragment {
25 |
26 | private static final String ARG_PARAM1 = "param1";
27 | private static final String ARG_PARAM2 = "param2";
28 |
29 | // TODO: Rename and change types of parameters
30 | private String mParam1;
31 | private String mParam2;
32 |
33 | private TimeLineView timeLineView;
34 | private List list = new ArrayList<>();
35 | private AbstractTimeLineAdapter adapter;
36 |
37 | public MukeFragment() {
38 |
39 | }
40 |
41 | /**
42 | * Use this factory method to create a new instance of
43 | * this fragment using the provided parameters.
44 | *
45 | * @param param1 Parameter 1.
46 | * @param param2 Parameter 2.
47 | * @return A new instance of fragment MukeFragment.
48 | */
49 | // TODO: Rename and change types and number of parameters
50 | public static MukeFragment newInstance(String param1, String param2) {
51 | MukeFragment fragment = new MukeFragment();
52 | Bundle args = new Bundle();
53 | args.putString(ARG_PARAM1, param1);
54 | args.putString(ARG_PARAM2, param2);
55 | fragment.setArguments(args);
56 | return fragment;
57 | }
58 |
59 | @Override
60 | public void onCreate(Bundle savedInstanceState) {
61 | super.onCreate(savedInstanceState);
62 | if (getArguments() != null) {
63 | mParam1 = getArguments().getString(ARG_PARAM1);
64 | mParam2 = getArguments().getString(ARG_PARAM2);
65 | }
66 | }
67 |
68 | @Override
69 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
70 | Bundle savedInstanceState) {
71 | // Inflate the layout for this fragment
72 | View view = inflater.inflate(R.layout.fragment_muke, container, false);
73 | timeLineView = view.findViewById(R.id.muke_tlv);
74 | initView();
75 | return view;
76 | }
77 |
78 | private void initView() {
79 | list.add(new MukeBean("5月1日", "我开始饿"));
80 | list.add(new MukeBean("5月2日", "我吃饭了"));
81 | list.add(new MukeBean("5月3日", "我吃饱了"));
82 | list.add(new MukeBean("5月4日", "我"));
83 | list.add(new MukeBean("5月5日", "我长胖了"));
84 | list.add(new MukeBean("5月6日", "我要减肥了"));
85 | list.add(new MukeBean("5月7日", "我只吃蔬菜"));
86 | list.add(new MukeBean("5月8日", "我好想吃肉"));
87 | list.add(new MukeBean("5月9日", "我吃肉了"));
88 | adapter = new MukeBeanAdapter(list);
89 |
90 | timeLineView.setTimeLineConfig(adapter, TimeLineType.StepViewType.LEFT_STEP_PROGRESS, 0);
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/java/io/github/rangaofei/timeline/StepViewModel.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
2 |
3 |
4 | import io.github.rangaofei.libannotations.TimeLine;
5 | import io.github.rangaofei.libannotations.TimeLineAnchor;
6 | import io.github.rangaofei.libannotations.TimeLineImageView;
7 | import io.github.rangaofei.libannotations.TimeLineTextView;
8 |
9 | @TimeLine(valueLayoutId = "R.layout.item_value")
10 | public class StepViewModel {
11 |
12 | @TimeLineTextView(key = false, id = "R.id.value", style = "R.style.StepView1", styleAnchor = "R.style.StepView2")
13 | public String text;
14 | @TimeLineAnchor({"R.id.value", "R.id.time"})
15 | public boolean right;
16 |
17 | @TimeLineTextView(key = false, id = "R.id.time", style = "R.style.StepView1",styleAnchor= "R.style.StepView3")
18 | public String time;
19 |
20 | @TimeLineImageView(key = false, id = "R.id.iv")
21 | public int imgSrc;
22 |
23 | public StepViewModel(String text, boolean right, String time, int imgSrc) {
24 | this.text = text;
25 | this.right = right;
26 | this.time = time;
27 | this.imgSrc = imgSrc;
28 | }
29 |
30 | public StepViewModel(String text, boolean right, String time) {
31 | this.text = text;
32 | this.right = right;
33 | this.time = time;
34 | }
35 |
36 | public StepViewModel(String text, boolean right) {
37 | this.text = text;
38 | this.right = right;
39 | }
40 |
41 | public String getText() {
42 | return text;
43 | }
44 |
45 | public void setText(String text) {
46 | this.text = text;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/io/github/rangaofei/timeline/SwipeAdapter.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.Button;
9 | import android.widget.TextView;
10 |
11 | import java.util.List;
12 |
13 | public class SwipeAdapter extends RecyclerView.Adapter {
14 |
15 | private List data;
16 |
17 | public SwipeAdapter(List data) {
18 | this.data = data;
19 | }
20 |
21 | @NonNull
22 | @Override
23 | public SwipeAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
24 | LayoutInflater inflater = LayoutInflater.from(parent.getContext());
25 | View view = inflater.inflate(R.layout.item_swipe, parent, false);
26 | return new ViewHolder(view);
27 | }
28 |
29 | @Override
30 | public void onBindViewHolder(@NonNull SwipeAdapter.ViewHolder holder, int position) {
31 | holder.textView.setText(data.get(position));
32 | }
33 |
34 | @Override
35 | public int getItemCount() {
36 | return data.size();
37 | }
38 |
39 | public class ViewHolder extends RecyclerView.ViewHolder {
40 | private TextView textView;
41 | private TextView button;
42 |
43 | public ViewHolder(View itemView) {
44 | super(itemView);
45 | textView = itemView.findViewById(R.id.tv);
46 | button = itemView.findViewById(R.id.btn_delete);
47 |
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/io/github/rangaofei/timeline/SwipeRecyclerViewActivity.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
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.LinearSnapHelper;
7 | import android.support.v7.widget.PagerSnapHelper;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.support.v7.widget.helper.ItemTouchHelper;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | import io.github.rangaofei.sakatimeline.divider.SakaItemTouchHelper;
15 | import io.github.rangaofei.sakatimeline.divider.SlideTouchHelperCallBack;
16 |
17 | public class SwipeRecyclerViewActivity extends AppCompatActivity {
18 |
19 | private RecyclerView recyclerView;
20 | private List data = new ArrayList<>();
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(R.layout.activity_swipe_recycler_view);
26 | recyclerView = findViewById(R.id.swipe_rv);
27 | for (int i = 0; i < 20; i++) {
28 | data.add(String.valueOf(i));
29 | }
30 | recyclerView.setAdapter(new SwipeAdapter(data));
31 | recyclerView.setLayoutManager(
32 | new LinearLayoutManager(this));
33 | LinearSnapHelper snapHelper = new LinearSnapHelper();
34 | snapHelper.attachToRecyclerView(recyclerView);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/io/github/rangaofei/timeline/TaobaoFragment.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
2 |
3 |
4 | import android.graphics.drawable.Drawable;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | import io.github.rangaofei.sakatimeline.TimeLineView;
15 | import io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter;
16 | import io.github.rangaofei.sakatimeline.divider.TimeLineType;
17 |
18 |
19 | public class TaobaoFragment extends Fragment {
20 |
21 | private static final String ARG_PARAM1 = "param1";
22 | private static final String ARG_PARAM2 = "param2";
23 |
24 | private AbstractTimeLineAdapter firstAdapter;
25 |
26 | private TimeLineView timeLineView;
27 | private List list;
28 | private List firstStepViewModels = new ArrayList<>();
29 |
30 | // TODO: Rename and change types of parameters
31 | private String mParam1;
32 | private String mParam2;
33 |
34 |
35 | public TaobaoFragment() {
36 | // Required empty public constructor
37 | }
38 |
39 | public static TaobaoFragment newInstance(String param1, String param2) {
40 | TaobaoFragment fragment = new TaobaoFragment();
41 | Bundle args = new Bundle();
42 | args.putString(ARG_PARAM1, param1);
43 | args.putString(ARG_PARAM2, param2);
44 | fragment.setArguments(args);
45 | return fragment;
46 | }
47 |
48 | @Override
49 | public void onCreate(Bundle savedInstanceState) {
50 | super.onCreate(savedInstanceState);
51 | if (getArguments() != null) {
52 | mParam1 = getArguments().getString(ARG_PARAM1);
53 | mParam2 = getArguments().getString(ARG_PARAM2);
54 | }
55 | }
56 |
57 | @Override
58 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
59 | Bundle savedInstanceState) {
60 | // Inflate the layout for this fragment
61 | View view = inflater.inflate(R.layout.fragment_blank, container, false);
62 | timeLineView = view.findViewById(R.id.taobao_tlv);
63 | initView();
64 | return view;
65 | }
66 |
67 | private void initView() {
68 |
69 | firstStepViewModels.add(new StepViewModel("卖家退款", false, "2016年5月1日"));
70 | firstStepViewModels.add(new StepViewModel("银行处理", false, "2016年6月1日"));
71 | firstStepViewModels.add(new StepViewModel("退款成功", false, "2016年6月1日"));
72 | firstAdapter = new StepViewModelAdapter(firstStepViewModels);
73 | list = new ArrayList<>();
74 | list.add(getResources().getDrawable(R.drawable.withpadding));
75 | list.add(getResources().getDrawable(R.drawable.withpadding));
76 | list.add(getResources().getDrawable(R.drawable.ic_offline_pin_black_24dp));
77 | timeLineView.setTimeLineConfig(firstAdapter, TimeLineType.StepViewType.TOP_STEP_PROGRESS, 3f, list);
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/io/github/rangaofei/timeline/TimeLineAdapter.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
2 |
3 | import android.widget.TextView;
4 |
5 | import java.util.List;
6 |
7 | import io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter;
8 | import io.github.rangaofei.sakatimeline.adapter.BaseViewHolder;
9 |
10 | public class TimeLineAdapter extends AbstractTimeLineAdapter {
11 | public TimeLineAdapter(List list) {
12 | super(list);
13 | }
14 |
15 | @Override
16 | public int getKeyLayoutId() {
17 | return R.layout.item_key;
18 | }
19 |
20 | @Override
21 | public int getValueLayoutId() {
22 | return R.layout.item_value;
23 | }
24 |
25 | @Override
26 | public void bindKeyItem(BaseViewHolder holder, BaseModel baseModel) {
27 | ((TextView) (((KeyViewHolder) holder).itemView.findViewById(R.id.key))).setText(baseModel.getKey());
28 | }
29 |
30 | @Override
31 | public void bindValueItem(BaseViewHolder holder, BaseModel baseModel) {
32 | ((TextView) (((ValueViewHolder) holder).itemView.findViewById(R.id.value))).setText(baseModel.getValue());
33 | }
34 |
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/dot_grey.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_offline_pin_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_order.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/withpadding.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
13 |
19 |
20 |
23 |
24 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_swipe_recycler_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
13 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_blank.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_muke.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_key.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
16 |
17 |
18 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_muke.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
17 |
18 |
25 |
26 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_swipe.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
19 |
20 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_value.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
17 |
18 |
23 |
24 |
30 |
31 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/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 | TimeLine
3 |
4 |
5 | Hello blank fragment
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
16 |
17 |
23 |
24 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/test/java/io/github/rangaofei/timeline/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.timeline;
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() {
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 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.3'
11 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.1'
12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | jcenter()
23 | }
24 | }
25 |
26 | subprojects {
27 | apply from: "${rootDir}/config.gradle"
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/config.gradle:
--------------------------------------------------------------------------------
1 | def majorVersion = 0
2 | def minorVersion = 2
3 | def patchVersion = 5
4 |
5 | def version_code = majorVersion * 1000 + minorVersion * 10 + patchVersion
6 |
7 | def version_name = majorVersion + "." + minorVersion + "." + patchVersion
8 | ext{
9 | version=version_name
10 | versionCode=version_code
11 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 15 11:42:21 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/libannotations/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/libannotations/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | apply plugin: 'com.jfrog.bintray'
4 |
5 | dependencies {
6 | implementation fileTree(dir: 'libs', include: ['*.jar'])
7 | }
8 |
9 | sourceCompatibility = "1.7"
10 | targetCompatibility = "1.7"
11 |
12 | version = project.ext.version
13 |
14 |
15 | def siteUrl = 'https://github.com/rangaofei/TimeLine'
16 | def gitUrl = 'https://github.com/rangaofei/TimeLine'
17 | group = "com.rangaofei"
18 |
19 | install {
20 | repositories.mavenInstaller {
21 | // This generates POM.xml with proper parameters
22 | pom {
23 | project {
24 | packaging 'jar'
25 | name 'libannotations'
26 | // #CONFIG# // project title
27 | url siteUrl
28 | // Set your license
29 | licenses {
30 | license {
31 | name 'The Apache Software License, Version 2.0'
32 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
33 | }
34 | }
35 | developers {
36 | developer {
37 | id 'tudou'
38 | // #CONFIG# // your user id (you can write your nickname)
39 | name 'rangaofei'
40 | // #CONFIG# // your user name
41 | email '876038559@qq.com'
42 | // #CONFIG# // your email
43 | }
44 | }
45 | scm {
46 | connection gitUrl
47 | developerConnection gitUrl
48 | url siteUrl
49 | }
50 | }
51 | }
52 | }
53 | }
54 |
55 | task sourcesJar(type: Jar) {
56 | classifier = 'sources'
57 | from sourceSets.main.allSource
58 | }
59 |
60 |
61 |
62 | task javadocJar(type: Jar, dependsOn: javadoc) {
63 | classifier = 'javadoc'
64 | from javadoc.destinationDir
65 | }
66 |
67 | artifacts {
68 | archives sourcesJar
69 | }
70 |
71 | Properties properties = new Properties()
72 | boolean isHasFile = false
73 | if (project.rootProject.file('local.properties') != null) {
74 | isHasFile = true
75 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
76 | }
77 | bintray {
78 | user = isHasFile ? properties.getProperty("bintray.user") : System.getenv("bintray.user")
79 | key = isHasFile ? properties.getProperty("bintray.apikey") : System.getenv("bintray.apikey")
80 | configurations = ['archives']
81 | pkg {
82 | repo = "maven"
83 | name = "libannotations"
84 | websiteUrl = siteUrl
85 | vcsUrl = gitUrl
86 | licenses = ["Apache-2.0"]
87 | publish = true
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/libannotations/src/main/java/io/github/rangaofei/libannotations/TimeConfig.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.libannotations;
2 |
3 | public class TimeConfig {
4 | public static final String NULL = "not_set";
5 | public static final String ID_NULL = "-1";
6 | public static final int ID_NONE = -1;
7 | }
8 |
--------------------------------------------------------------------------------
/libannotations/src/main/java/io/github/rangaofei/libannotations/TimeLine.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.libannotations;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 表示这个类将会是用来做list元素的类
10 | */
11 | @Target(ElementType.TYPE)
12 | @Retention(RetentionPolicy.CLASS)
13 | public @interface TimeLine {
14 | String name() default "";
15 |
16 | String keyLayoutId() default TimeConfig.ID_NULL;
17 |
18 | String valueLayoutId() default TimeConfig.ID_NULL;
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/libannotations/src/main/java/io/github/rangaofei/libannotations/TimeLineAnchor.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.libannotations;
2 |
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | @Retention(RetentionPolicy.CLASS)
10 | @Target(ElementType.FIELD)
11 | public @interface TimeLineAnchor {
12 | String[] value() default {};
13 | }
14 |
--------------------------------------------------------------------------------
/libannotations/src/main/java/io/github/rangaofei/libannotations/TimeLineDividerAdapter.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.libannotations;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target(ElementType.FIELD)
10 | public @interface TimeLineDividerAdapter {
11 | String value() default "Divider";
12 | }
13 |
--------------------------------------------------------------------------------
/libannotations/src/main/java/io/github/rangaofei/libannotations/TimeLineImageView.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.libannotations;
2 |
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | @Target(ElementType.FIELD)
10 | @Retention(RetentionPolicy.CLASS)
11 | public @interface TimeLineImageView {
12 | boolean key() default true;
13 |
14 | String id() default TimeConfig.ID_NULL;
15 | }
16 |
--------------------------------------------------------------------------------
/libannotations/src/main/java/io/github/rangaofei/libannotations/TimeLineTextView.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.libannotations;
2 |
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | @Target(ElementType.FIELD)
10 | @Retention(RetentionPolicy.CLASS)
11 |
12 | public @interface TimeLineTextView {
13 | boolean key() default true;//是否显示在key布局
14 |
15 | String id() default TimeConfig.ID_NULL;
16 |
17 | String style() default TimeConfig.ID_NULL;
18 |
19 | String styleAnchor() default TimeConfig.ID_NULL;
20 | }
21 |
--------------------------------------------------------------------------------
/libannotations/src/main/java/io/github/rangaofei/libannotations/TimeLineView.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.libannotations;
2 |
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | @Retention(RetentionPolicy.CLASS)
10 | @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
11 |
12 | public @interface TimeLineView {
13 |
14 | enum ViewType {
15 | VIEW, TEXT_VIEW, IMAGE_VIEW,
16 | }
17 |
18 | ViewType value() default ViewType.VIEW;
19 |
20 | String style() default TimeConfig.ID_NULL;
21 |
22 | String styleAnchor() default TimeConfig.ID_NULL;
23 | }
24 |
--------------------------------------------------------------------------------
/sakatimeline/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sakatimeline/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | apply plugin: 'com.jfrog.bintray'
4 |
5 |
6 | version = project.ext.version
7 |
8 | android {
9 | compileSdkVersion 27
10 |
11 |
12 |
13 | defaultConfig {
14 | minSdkVersion 19
15 | targetSdkVersion 27
16 | versionCode project.ext.versionCode
17 | versionName project.ext.version
18 |
19 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
20 | vectorDrawables.useSupportLibrary = true
21 |
22 | javaCompileOptions {
23 | annotationProcessorOptions.includeCompileClasspath = true
24 | }
25 | }
26 |
27 | buildTypes {
28 | release {
29 | minifyEnabled false
30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
31 | }
32 | }
33 |
34 | dataBinding {
35 | enabled = true
36 | }
37 |
38 | }
39 |
40 | dependencies {
41 | implementation fileTree(include: ['*.jar'], dir: 'libs')
42 | implementation 'com.android.support:appcompat-v7:27.1.1'
43 | testImplementation 'junit:junit:4.12'
44 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
45 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
46 | implementation 'com.android.support:recyclerview-v7:27.1.1'
47 | implementation 'com.android.support:cardview-v7:27.1.1'
48 | api 'com.rangaofei:libannotations:0.2.1'
49 | }
50 |
51 |
52 | def siteUrl = 'https://github.com/rangaofei/TimeLine'
53 | def gitUrl = 'https://github.com/rangaofei/TimeLine'
54 | group = "com.rangaofei"
55 |
56 | install {
57 | repositories.mavenInstaller {
58 | // This generates POM.xml with proper parameters
59 | pom {
60 | project {
61 | packaging 'aar'
62 | name 'sakatimeline'
63 | // #CONFIG# // project title
64 | url siteUrl
65 | // Set your license
66 | licenses {
67 | license {
68 | name 'The Apache Software License, Version 2.0'
69 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
70 | }
71 | }
72 | developers {
73 | developer {
74 | id 'tudou'
75 | // #CONFIG# // your user id (you can write your nickname)
76 | name 'rangaofei'
77 | // #CONFIG# // your user name
78 | email '876038559@qq.com'
79 | // #CONFIG# // your email
80 | }
81 | }
82 | scm {
83 | connection gitUrl
84 | developerConnection gitUrl
85 | url siteUrl
86 | }
87 | }
88 | }
89 | }
90 | }
91 |
92 | task sourcesJar(type: Jar) {
93 | from android.sourceSets.main.java.srcDirs
94 | classifier = 'sources'
95 | }
96 |
97 | task javadoc(type: Javadoc) {
98 | source = android.sourceSets.main.java.srcDirs
99 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
100 | }
101 |
102 | task javadocJar(type: Jar, dependsOn: javadoc) {
103 | classifier = 'javadoc'
104 | from javadoc.destinationDir
105 | }
106 |
107 | artifacts {
108 | archives sourcesJar
109 | }
110 |
111 | Properties properties = new Properties()
112 | boolean isHasFile = false
113 | if (project.rootProject.file('local.properties') != null) {
114 | isHasFile = true
115 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
116 | }
117 | bintray {
118 | user = isHasFile ? properties.getProperty("bintray.user") : System.getenv("bintray.user")
119 | key = isHasFile ? properties.getProperty("bintray.apikey") : System.getenv("bintray.apikey")
120 | configurations = ['archives']
121 | pkg {
122 | repo = "maven"
123 | name = "sakatimeline"
124 | websiteUrl = siteUrl
125 | vcsUrl = gitUrl
126 | licenses = ["Apache-2.0"]
127 | publish = true
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/sakatimeline/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/sakatimeline/src/androidTest/java/io/github/rangaofei/sakatimeline/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline;
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 | * Instrumented 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() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("io.github.rangaofei.sakatimeline.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/adapter/AbstractTimeLineAdapter.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.adapter;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import java.util.List;
10 |
11 | import io.github.rangaofei.sakatimeline.R;
12 | import io.github.rangaofei.sakatimeline.divider.TimeLineType;
13 |
14 | import static io.github.rangaofei.sakatimeline.divider.TimeLineType.StepViewType.StepViewType;
15 | import static io.github.rangaofei.sakatimeline.divider.TimeLineType.StepViewType.TimeLineViewType;
16 |
17 | public abstract class AbstractTimeLineAdapter extends RecyclerView.Adapter {
18 |
19 | public static final int TYPE_KEY = 1;
20 | public static final int TYPE_VALUE = 2;
21 | public static final int TYPE_KEY_ONLY = 3;
22 | public static final int TYPE_VALUE_ONLY = 4;
23 |
24 | private ItemClickListener itemClickListener;
25 |
26 | private List datas;
27 |
28 | private TimeLineType timeLineType;
29 | private int holderCount = 0;
30 |
31 | public AbstractTimeLineAdapter(List list) {
32 | this.datas = list;
33 | }
34 |
35 |
36 | public void setItemClickListener(ItemClickListener itemClickListener) {
37 | this.itemClickListener = itemClickListener;
38 | }
39 |
40 | @NonNull
41 | @Override
42 | public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
43 | LayoutInflater inflater = LayoutInflater.from(parent.getContext());
44 | switch (viewType) {
45 | case TYPE_KEY:
46 | View keyView = inflater.inflate(getKeyLayoutId(), parent, false);
47 | return new KeyViewHolder(keyView);
48 | case TYPE_VALUE:
49 | View valueView = inflater.inflate(getValueLayoutId(), parent, false);
50 | return new ValueViewHolder(valueView);
51 | default:
52 | View nullView = inflater.inflate(R.layout.null_view, parent, false);
53 | return new BaseViewHolder(nullView) {
54 | @Override
55 | public String toString() {
56 | return super.toString();
57 | }
58 | };
59 | }
60 |
61 | }
62 |
63 | @Override
64 | public void onBindViewHolder(@NonNull final BaseViewHolder holder, int position) {
65 | T data = null;
66 | if (timeLineType instanceof StepViewType) {
67 | switch ((StepViewType) timeLineType) {
68 | case TOP_STEP_PROGRESS:
69 | case BOTTOM_STEP_PROGRESS:
70 | case LEFT_STEP_PROGRESS:
71 | case RIGHT_STEP_PROGRESS:
72 | data = datas.get(position);
73 | break;
74 | default:
75 | throw new RuntimeException("nu");
76 | }
77 | }
78 | if (timeLineType instanceof TimeLineViewType) {
79 | switch ((TimeLineViewType) timeLineType) {
80 | case ONLY_LEFT:
81 | case ONLY_RIGHT:
82 | data = datas.get(position / holderCount);
83 | break;
84 | case LEFT_TO_RIGHT:
85 | case RIGHT_TO_LEFT:
86 | data = datas.get(position / 2);
87 | break;
88 | case LEFT_KEY:
89 | case LEFT_VALUE:
90 | data = datas.get(position / 2);
91 | break;
92 | }
93 | }
94 |
95 |
96 | if (data == null) {
97 | return;
98 | }
99 |
100 | if (holder instanceof KeyViewHolder) {
101 | bindKeyItem(holder, data);
102 | ((KeyViewHolder) holder).itemView.setOnClickListener(new View.OnClickListener() {
103 | @Override
104 | public void onClick(View v) {
105 | if (itemClickListener != null) {
106 | itemClickListener.onKeyViewClick(holder.getAdapterPosition());
107 | }
108 | }
109 | });
110 | } else if (holder instanceof ValueViewHolder) {
111 | bindValueItem(holder, data);
112 | ((ValueViewHolder) holder).itemView.setOnClickListener(new View.OnClickListener() {
113 | @Override
114 | public void onClick(View v) {
115 |
116 | if (itemClickListener != null) {
117 | itemClickListener.onValueViewClick(holder.getAdapterPosition());
118 | }
119 | }
120 | });
121 | }
122 | }
123 |
124 | @Override
125 | public int getItemCount() {
126 | if (timeLineType instanceof StepViewType) {
127 | switch ((StepViewType) timeLineType) {
128 | case TOP_STEP_PROGRESS:
129 | case BOTTOM_STEP_PROGRESS:
130 | case LEFT_STEP_PROGRESS:
131 | case RIGHT_STEP_PROGRESS:
132 | return datas.size();
133 | default:
134 | throw new RuntimeException("nu");
135 | }
136 | }
137 |
138 | if (timeLineType instanceof TimeLineViewType) {
139 | switch ((TimeLineViewType) timeLineType) {
140 | case ONLY_RIGHT:
141 | case ONLY_LEFT: {
142 | if (getValueLayoutId() == -1 && getKeyLayoutId() == -1) {
143 | return 0;
144 | }
145 | if (getValueLayoutId() == -1 || getKeyLayoutId() == -1) {
146 | holderCount = 1;
147 | return datas.size();
148 | }
149 | holderCount = 2;
150 | return datas.size() * 2;
151 | }
152 | case RIGHT_TO_LEFT:
153 | case LEFT_TO_RIGHT:
154 | return datas.size() * 2;
155 | case LEFT_KEY:
156 | case LEFT_VALUE:
157 | return datas.size() * 2;
158 | default:
159 | return datas.size() * 2;
160 | }
161 | } else {
162 | return datas.size();
163 | }
164 |
165 | }
166 |
167 | public TimeLineType getTimeLineType() {
168 | return timeLineType;
169 | }
170 |
171 | public void setTimeLineType(TimeLineType timeLineType) {
172 | this.timeLineType = timeLineType;
173 |
174 | }
175 |
176 | @Override
177 | public int getItemViewType(int position) {
178 | if (getKeyLayoutId() == -1 && getValueLayoutId() != -1) {
179 | return ItemTypeStrategy.getItemTypeOnlyValue(position, timeLineType);
180 | }
181 | if (getValueLayoutId() == -1 && getKeyLayoutId() != -1) {
182 | return ItemTypeStrategy.getItemTypeOnlyKey(position, timeLineType);
183 | }
184 | if (timeLineType instanceof StepViewType) {
185 | return ItemTypeStrategy.getItemTypeOnlyValue(position, timeLineType);
186 | }
187 | return ItemTypeStrategy.getItemType(position, timeLineType);
188 | }
189 |
190 |
191 | public static class KeyViewHolder extends BaseViewHolder {
192 |
193 |
194 | public KeyViewHolder(View itemView) {
195 | super(itemView);
196 | }
197 | }
198 |
199 | public static class ValueViewHolder extends BaseViewHolder {
200 |
201 |
202 | public ValueViewHolder(View itemView) {
203 | super(itemView);
204 | }
205 | }
206 |
207 | public abstract int getKeyLayoutId();
208 |
209 | public abstract int getValueLayoutId();
210 |
211 | public abstract void bindKeyItem(BaseViewHolder holder, T t);
212 |
213 | public abstract void bindValueItem(BaseViewHolder holder, T t);
214 |
215 | }
216 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/adapter/BaseViewHolder.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.adapter;
2 |
3 | import android.databinding.ViewDataBinding;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 |
7 | public abstract class BaseViewHolder extends RecyclerView.ViewHolder {
8 |
9 | public BaseViewHolder(View itemView) {
10 | super(itemView);
11 | }
12 |
13 | @Override
14 | public String toString() {
15 | return super.toString();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/adapter/ItemClickListener.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.adapter;
2 |
3 | public interface ItemClickListener {
4 | void onKeyViewClick(int position);
5 |
6 | void onValueViewClick(int position);
7 | }
8 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/adapter/ItemTypeStrategy.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.adapter;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | import io.github.rangaofei.sakatimeline.divider.TimeLineType;
6 |
7 | import static io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter.TYPE_KEY;
8 | import static io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter.TYPE_KEY_ONLY;
9 | import static io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter.TYPE_VALUE;
10 | import static io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter.TYPE_VALUE_ONLY;
11 | import static io.github.rangaofei.sakatimeline.divider.TimeLineType.StepViewType.*;
12 | import static io.github.rangaofei.sakatimeline.divider.TimeLineType.TimeLineViewType.*;
13 |
14 | public class ItemTypeStrategy {
15 |
16 |
17 | public static int getItemType(int position, TimeLineType type) {
18 | if (type instanceof TimeLineViewType) {
19 | switch ((TimeLineViewType) type) {
20 | case LEFT_TO_RIGHT:
21 | if (position % 4 == 0 | position % 4 == 3) {
22 | return TYPE_KEY;
23 | }
24 | if (position % 4 == 1 || position % 4 == 2) {
25 | return TYPE_VALUE;
26 | }
27 | case RIGHT_TO_LEFT:
28 | if (position % 4 == 0 | position % 4 == 3) {
29 | return TYPE_VALUE;
30 | }
31 | if (position % 4 == 1 || position % 4 == 2) {
32 | return TYPE_KEY;
33 | }
34 | case LEFT_KEY:
35 | if (position % 2 == 0) {
36 | return TYPE_KEY;
37 | } else {
38 | return TYPE_VALUE;
39 | }
40 | case LEFT_VALUE:
41 | if (position % 2 == 1) {
42 | return TYPE_KEY;
43 | } else {
44 | return TYPE_VALUE;
45 | }
46 | case ONLY_LEFT:
47 | if (position % 2 == 0) {
48 | return TYPE_KEY;
49 | } else {
50 | return TYPE_VALUE;
51 | }
52 | case ONLY_RIGHT:
53 | if (position % 2 == 0) {
54 | return TYPE_KEY;
55 | } else {
56 | return TYPE_VALUE;
57 | }
58 | default:
59 | if (position % 2 == 1) {
60 | return TYPE_KEY;
61 | } else {
62 | return TYPE_VALUE;
63 | }
64 |
65 | }
66 | } else if (type instanceof StepViewType) {
67 | switch ((StepViewType) type) {
68 | case TOP_STEP_PROGRESS:
69 | case BOTTOM_STEP_PROGRESS:
70 | case LEFT_STEP_PROGRESS:
71 | case RIGHT_STEP_PROGRESS:
72 | return TYPE_VALUE;
73 | }
74 | } else {
75 | throw new RuntimeException("nu");
76 | }
77 | return TYPE_VALUE;
78 | }
79 |
80 | public static int getItemTypeOnlyKey(int position, TimeLineType type) {
81 | if (type instanceof TimeLineViewType) {
82 | switch ((TimeLineViewType) type) {
83 | case LEFT_TO_RIGHT:
84 | if (position % 4 == 0 | position % 4 == 3) {
85 | return TYPE_KEY;
86 | }
87 | if (position % 4 == 1 || position % 4 == 2) {
88 | return TYPE_KEY_ONLY;
89 | }
90 | case RIGHT_TO_LEFT:
91 | if (position % 4 == 0 | position % 4 == 3) {
92 | return TYPE_KEY_ONLY;
93 | }
94 | if (position % 4 == 1 || position % 4 == 2) {
95 | return TYPE_KEY;
96 | }
97 | case LEFT_KEY:
98 | if (position % 2 == 0) {
99 | return TYPE_KEY;
100 | } else {
101 | return TYPE_KEY_ONLY;
102 | }
103 | case LEFT_VALUE:
104 | if (position % 2 == 1) {
105 | return TYPE_KEY;
106 | } else {
107 | return TYPE_KEY_ONLY;
108 | }
109 | case ONLY_LEFT:
110 | return TYPE_KEY;
111 | case ONLY_RIGHT:
112 | return TYPE_KEY;
113 |
114 | default:
115 | if (position % 2 == 1) {
116 | return TYPE_KEY;
117 | } else {
118 | return TYPE_KEY_ONLY;
119 | }
120 |
121 | }
122 | } else if (type instanceof StepViewType) {
123 | return TYPE_KEY;
124 | } else {
125 | throw new RuntimeException("ru");
126 | }
127 | }
128 |
129 | public static int getItemTypeOnlyValue(int position, TimeLineType type) {
130 | if (type instanceof TimeLineViewType) {
131 | switch ((TimeLineViewType) type) {
132 | case LEFT_TO_RIGHT:
133 | if (position % 4 == 0 | position % 4 == 3) {
134 | return TYPE_VALUE_ONLY;
135 | }
136 | if (position % 4 == 1 || position % 4 == 2) {
137 | return TYPE_VALUE;
138 | }
139 | case RIGHT_TO_LEFT:
140 | if (position % 4 == 0 | position % 4 == 3) {
141 | return TYPE_VALUE;
142 | }
143 | if (position % 4 == 1 || position % 4 == 2) {
144 | return TYPE_VALUE_ONLY;
145 | }
146 | case LEFT_KEY:
147 | if (position % 2 == 0) {
148 | return TYPE_VALUE_ONLY;
149 | } else {
150 | return TYPE_VALUE;
151 | }
152 | case LEFT_VALUE:
153 | if (position % 2 == 1) {
154 | return TYPE_VALUE_ONLY;
155 | } else {
156 | return TYPE_VALUE;
157 | }
158 | case ONLY_LEFT:
159 | return TYPE_VALUE;
160 | case ONLY_RIGHT:
161 | return TYPE_VALUE;
162 |
163 | default:
164 | if (position % 2 == 1) {
165 | return TYPE_VALUE_ONLY;
166 | } else {
167 | return TYPE_VALUE;
168 | }
169 |
170 | }
171 | } else if (type instanceof StepViewType) {
172 | return TYPE_VALUE;
173 | } else {
174 | throw new RuntimeException("nu");
175 | }
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/config/IndexTextConfig.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.config;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.util.AttributeSet;
6 |
7 | import io.github.rangaofei.sakatimeline.R;
8 |
9 | /**
10 | * 用于配置序号的显示样式
11 | */
12 | public class IndexTextConfig {
13 | private int textColor;
14 | private int textSize;
15 |
16 | public int getTextColor() {
17 | return textColor;
18 | }
19 |
20 | public void setTextColor(int textColor) {
21 | this.textColor = textColor;
22 | }
23 |
24 | public int getTextSize() {
25 | return textSize;
26 | }
27 |
28 | public void setTextSize(int textSize) {
29 | this.textSize = textSize;
30 | }
31 |
32 | public IndexTextConfig getIndexTextAttr(AttributeSet as, Context context) {
33 | final IndexTextConfig indexTextConfig = new IndexTextConfig();
34 | final TypedArray ta = context.obtainStyledAttributes(as, R.styleable.IndexText);
35 | if (ta == null) {
36 | return indexTextConfig;
37 | }
38 | final int textSize = ta.getDimensionPixelSize(R.styleable.IndexText_timeIndexSize,
39 | context.getResources().getDimensionPixelSize(R.dimen.default_text_size));
40 | final int textColor = ta.getColor(R.styleable.IndexText_timeIndexColor,
41 | context.getResources().getColor(R.color.pink));
42 | ta.recycle();
43 | indexTextConfig.setTextColor(textColor);
44 | indexTextConfig.setTextSize(textSize);
45 | return indexTextConfig;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/config/StepViewConfig.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.config;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.drawable.Drawable;
6 | import android.util.AttributeSet;
7 |
8 | import java.util.List;
9 |
10 | import io.github.rangaofei.sakatimeline.R;
11 | import io.github.rangaofei.sakatimeline.divider.DividerLayoutAdapter;
12 |
13 | /**
14 | * 配置StepViewDivider
15 | */
16 | public class StepViewConfig {
17 | //是否显示index,序号,从1开始
18 | private boolean showStepText;
19 | //当前分割点
20 | private float dividerNum;
21 | //分割点前边线的颜色
22 | private int preColor;
23 | //分割点后边线的颜色
24 | private int afterColor;
25 | //默认的index图标是一个圆圈,圆圈的半径
26 | private int circleRadius;
27 | //用于覆盖默认的index点
28 | private DividerLayoutAdapter dividerLayoutAdapter;
29 |
30 | public boolean isShowStepText() {
31 | return showStepText;
32 | }
33 |
34 | public void setShowStepText(boolean showStepText) {
35 | this.showStepText = showStepText;
36 | }
37 |
38 |
39 | public float getDividerNum() {
40 | return dividerNum;
41 | }
42 |
43 | public void setDividerNum(float dividerNum) {
44 | this.dividerNum = dividerNum;
45 | }
46 |
47 |
48 | public int getPreColor() {
49 | return preColor;
50 | }
51 |
52 | public void setPreColor(int preColor) {
53 | this.preColor = preColor;
54 | }
55 |
56 | public int getAfterColor() {
57 | return afterColor;
58 | }
59 |
60 | public void setAfterColor(int afterColor) {
61 | this.afterColor = afterColor;
62 | }
63 |
64 | public int getCircleRadius() {
65 | return circleRadius;
66 | }
67 |
68 | public void setCircleRadius(int circleRadius) {
69 | this.circleRadius = circleRadius;
70 | }
71 |
72 | public DividerLayoutAdapter getDividerLayoutAdapter() {
73 | return dividerLayoutAdapter;
74 | }
75 |
76 | public void setDividerLayoutAdapter(DividerLayoutAdapter dividerLayoutAdapter) {
77 | this.dividerLayoutAdapter = dividerLayoutAdapter;
78 | }
79 |
80 | public void setDividerLayoutAdapter(List drawableList) {
81 | if (drawableList == null || drawableList.size() < 1) {
82 | return;
83 | }
84 |
85 | this.dividerLayoutAdapter = new DividerLayoutAdapter(drawableList) {
86 | };
87 | }
88 |
89 |
90 | public StepViewConfig getStepViewAttr(AttributeSet as, Context context) {
91 | StepViewConfig stepViewConfig = new StepViewConfig();
92 | final TypedArray ta = context.obtainStyledAttributes(as, R.styleable.StepViewDivider);
93 | if (ta == null) {
94 | return stepViewConfig;
95 | }
96 | final boolean showIndex = ta.getBoolean(R.styleable.StepViewDivider_stepShowOrder, false);
97 | final int preColor = ta.getColor(R.styleable.StepViewDivider_stepPreColor, context.getResources().getColor(R.color.teal));
98 | final int afterColor = ta.getColor(R.styleable.StepViewDivider_stepAfterColor, context.getResources().getColor(R.color.grey));
99 | ta.recycle();
100 | stepViewConfig.setShowStepText(showIndex);
101 | stepViewConfig.setPreColor(preColor);
102 | stepViewConfig.setAfterColor(afterColor);
103 | return stepViewConfig;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/config/StrokeType.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.config;
2 |
3 | public enum StrokeType {
4 | NORMAL, NO_ENDPOINT, MID_ENDPOINT
5 | }
6 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/config/TimeLineConfig.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.config;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.drawable.BitmapDrawable;
6 | import android.graphics.drawable.Drawable;
7 | import android.util.AttributeSet;
8 |
9 | import java.util.List;
10 |
11 | import io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter;
12 | import io.github.rangaofei.sakatimeline.divider.DividerLayoutAdapter;
13 | import io.github.rangaofei.sakatimeline.divider.TimeLineType;
14 | import io.github.rangaofei.sakatimeline.exception.BaseException;
15 | import io.github.rangaofei.sakatimeline.exception.ExceptionMessage;
16 |
17 | public class TimeLineConfig {
18 | private float padding;
19 | private Drawable timeDrawable;
20 |
21 | private float timeStrokeWidth;
22 | private int timeColor;
23 |
24 |
25 | private TimeLineType type;
26 | private AbstractTimeLineAdapter adapter;
27 |
28 | private StepViewConfig stepViewConfig;
29 |
30 |
31 | private IndexTextConfig indexTextConfig;
32 |
33 | private StrokeType strokeType;
34 |
35 | private int iconWidth;
36 | private int iconHeight;
37 |
38 | public IndexTextConfig getIndexTextConfig() {
39 | return indexTextConfig;
40 | }
41 |
42 | public void setIndexTextConfig(IndexTextConfig indexTextConfig) {
43 | this.indexTextConfig = indexTextConfig;
44 | }
45 |
46 | public TimeLineConfig() {
47 | }
48 |
49 | public TimeLineConfig(AbstractTimeLineAdapter adapter) {
50 | this.adapter = adapter;
51 | }
52 |
53 | public Drawable getTimeDrawable() {
54 | return timeDrawable;
55 | }
56 |
57 | public void setTimeDrawable(Drawable timeDrawable) {
58 | this.timeDrawable = timeDrawable;
59 | }
60 |
61 | public float getPadding() {
62 | return padding;
63 | }
64 |
65 | public void setPadding(float padding) {
66 | this.padding = padding;
67 | }
68 |
69 | public float getTimeStrokeWidth() {
70 | return timeStrokeWidth;
71 | }
72 |
73 | public void setTimeStrokeWidth(float timeStrokeWidth) {
74 | this.timeStrokeWidth = timeStrokeWidth;
75 | }
76 |
77 | public int getTimeColor() {
78 | return timeColor;
79 | }
80 |
81 | public void setTimeColor(int timeColor) {
82 | this.timeColor = timeColor;
83 | }
84 |
85 |
86 | public AbstractTimeLineAdapter getAdapter() {
87 | return adapter;
88 | }
89 |
90 | public void setAdapter(AbstractTimeLineAdapter adapter) {
91 | this.adapter = adapter;
92 | }
93 |
94 | public TimeLineType getType() {
95 | return type;
96 | }
97 |
98 | public void setType(TimeLineType type) {
99 | this.type = type;
100 | }
101 |
102 | public Bitmap getBitmap() {
103 | BitmapDrawable bd = (BitmapDrawable) timeDrawable;
104 | if (bd == null) {
105 | throw new BaseException(ExceptionMessage.DRAWABLE_NULL);
106 | }
107 | return bd.getBitmap();
108 | }
109 |
110 |
111 | public StepViewConfig getStepViewConfig() {
112 | return stepViewConfig;
113 | }
114 |
115 | public void setStepViewConfig(StepViewConfig stepViewConfig) {
116 | this.stepViewConfig = stepViewConfig;
117 | }
118 |
119 | public StrokeType getStrokeType() {
120 | return strokeType;
121 | }
122 |
123 | public void setStrokeType(StrokeType strokeType) {
124 | this.strokeType = strokeType;
125 | }
126 |
127 | public int getIconWidth() {
128 | return iconWidth;
129 | }
130 |
131 | public void setIconWidth(int iconWidth) {
132 | this.iconWidth = iconWidth;
133 | }
134 |
135 | public int getIconHeight() {
136 | return iconHeight;
137 | }
138 |
139 | public void setIconHeight(int iconHeight) {
140 | this.iconHeight = iconHeight;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/customlayoutmanager/ScrollbarHelper.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.customlayoutmanager;
2 |
3 | import android.support.v7.widget.OrientationHelper;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 |
7 | class ScrollbarHelper {
8 |
9 | /**
10 | * @param startChild View closest to start of the list. (top or left)
11 | * @param endChild View closest to end of the list (bottom or right)
12 | */
13 | static int computeScrollOffset(RecyclerView.State state, OrientationHelper orientation,
14 | View startChild, View endChild, RecyclerView.LayoutManager lm,
15 | boolean smoothScrollbarEnabled, boolean reverseLayout) {
16 | if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
17 | || endChild == null) {
18 | return 0;
19 | }
20 | final int minPosition = Math.min(lm.getPosition(startChild),
21 | lm.getPosition(endChild));
22 | final int maxPosition = Math.max(lm.getPosition(startChild),
23 | lm.getPosition(endChild));
24 | final int itemsBefore = reverseLayout
25 | ? Math.max(0, state.getItemCount() - maxPosition - 1)
26 | : Math.max(0, minPosition);
27 | if (!smoothScrollbarEnabled) {
28 | return itemsBefore;
29 | }
30 | final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild)
31 | - orientation.getDecoratedStart(startChild));
32 | final int itemRange = Math.abs(lm.getPosition(startChild)
33 | - lm.getPosition(endChild)) + 1;
34 | final float avgSizePerRow = (float) laidOutArea / itemRange;
35 |
36 | return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding()
37 | - orientation.getDecoratedStart(startChild)));
38 | }
39 |
40 | /**
41 | * @param startChild View closest to start of the list. (top or left)
42 | * @param endChild View closest to end of the list (bottom or right)
43 | */
44 | static int computeScrollExtent(RecyclerView.State state, OrientationHelper orientation,
45 | View startChild, View endChild, RecyclerView.LayoutManager lm,
46 | boolean smoothScrollbarEnabled) {
47 | if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
48 | || endChild == null) {
49 | return 0;
50 | }
51 | if (!smoothScrollbarEnabled) {
52 | return Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) + 1;
53 | }
54 | final int extend = orientation.getDecoratedEnd(endChild)
55 | - orientation.getDecoratedStart(startChild);
56 | return Math.min(orientation.getTotalSpace(), extend);
57 | }
58 |
59 | /**
60 | * @param startChild View closest to start of the list. (top or left)
61 | * @param endChild View closest to end of the list (bottom or right)
62 | */
63 | static int computeScrollRange(RecyclerView.State state, OrientationHelper orientation,
64 | View startChild, View endChild, RecyclerView.LayoutManager lm,
65 | boolean smoothScrollbarEnabled) {
66 | if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
67 | || endChild == null) {
68 | return 0;
69 | }
70 | if (!smoothScrollbarEnabled) {
71 | return state.getItemCount();
72 | }
73 | // smooth scrollbar enabled. try to estimate better.
74 | final int laidOutArea = orientation.getDecoratedEnd(endChild)
75 | - orientation.getDecoratedStart(startChild);
76 | final int laidOutRange = Math.abs(lm.getPosition(startChild)
77 | - lm.getPosition(endChild))
78 | + 1;
79 | // estimate a size for full list.
80 | return (int) ((float) laidOutArea / laidOutRange * state.getItemCount());
81 | }
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/customlayoutmanager/TimeLineLayoutManager.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.customlayoutmanager;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.GridLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.AttributeSet;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | public class TimeLineLayoutManager extends GridLayoutManager {
12 |
13 | private int gap = -1;
14 |
15 | public TimeLineLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
16 | super(context, attrs, defStyleAttr, defStyleRes);
17 | }
18 |
19 | public TimeLineLayoutManager(Context context, int spanCount) {
20 | super(context, spanCount);
21 | }
22 |
23 | @Override
24 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
25 | super.onLayoutChildren(recycler, state);
26 | int maxRight = 0;
27 | if (gap == -1) {
28 | for (int i = 0; i < getChildCount(); i = i + 2) {
29 | View view = getChildAt(i);
30 | if (maxRight < view.getRight()) {
31 | maxRight = view.getRight();
32 | }
33 | // view.setLeft(200);
34 | Log.d("---", "view.left=" + view.getLeft() + "view.right=" + view.getRight());
35 | Log.d("---", "view.w=" + view.getWidth() + "view.h=" + view.getHeight());
36 | }
37 | } else {
38 | int l = getChildAt(1).getLeft();
39 | maxRight = l - gap;
40 | }
41 |
42 | for (int i = 0; i < getChildCount(); i = i + 2) {
43 | View view = getChildAt(i);
44 | int w = view.getWidth();
45 | view.setRight(maxRight);
46 | view.setLeft(view.getRight() - w);
47 | view.getHeight();
48 | }
49 | }
50 |
51 | public int getGap() {
52 | return gap;
53 | }
54 |
55 | public void setGap(int gap) {
56 | this.gap = gap;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/divider/BaseDivider.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.divider;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Rect;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.View;
8 |
9 | import io.github.rangaofei.sakatimeline.config.TimeLineConfig;
10 | import io.github.rangaofei.sakatimeline.exception.BaseException;
11 | import io.github.rangaofei.sakatimeline.exception.ExceptionMessage;
12 |
13 | public abstract class BaseDivider extends RecyclerView.ItemDecoration {
14 | protected Context context;
15 | protected float padding;
16 | protected TimeLineConfig timeLineConfig;
17 | protected Rect globalRect = new Rect();
18 | protected static final int DEFAULT_LEFT_DIVIDER_GAP = 10;
19 | protected static final int DEFAULT_RIGHT_DIVIDER_GAP = 10;
20 | protected static final int DEFAULT_TOP_DIVIDER_GAP = 10;
21 | protected static final int DEFAULT_BOTTOM_DIVIDER_GAP = 10;
22 |
23 |
24 | public BaseDivider(RecyclerView recyclerView, TimeLineConfig timeLineConfig) {
25 | this.context = recyclerView.getContext();
26 | this.timeLineConfig = timeLineConfig;
27 | this.padding = timeLineConfig.getPadding();
28 | }
29 |
30 | @Override
31 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
32 |
33 | onChildDraw(c, parent, state);
34 | }
35 |
36 | @Override
37 | public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
38 |
39 | onChildDrawOver(c, parent, state);
40 | }
41 |
42 | @Override
43 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
44 | outRect.set(DEFAULT_LEFT_DIVIDER_GAP, DEFAULT_TOP_DIVIDER_GAP,
45 | DEFAULT_RIGHT_DIVIDER_GAP, DEFAULT_BOTTOM_DIVIDER_GAP);
46 | globalRect.set(outRect);
47 |
48 | }
49 |
50 | public void getHorizontalItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
51 |
52 | }
53 |
54 | public void getVerticalItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
55 |
56 | }
57 |
58 | protected void throwException(ExceptionMessage message) {
59 | throw new BaseException(message);
60 |
61 | }
62 |
63 | public abstract void onChildDraw(Canvas c, RecyclerView parent, RecyclerView.State state);
64 |
65 | public abstract void onChildDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state);
66 | }
67 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/divider/DividerLayoutAdapter.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.divider;
2 |
3 | import android.graphics.drawable.Drawable;
4 |
5 | import java.util.List;
6 |
7 | public abstract class DividerLayoutAdapter {
8 | private List list;
9 |
10 | public DividerLayoutAdapter(List list) {
11 | this.list = list;
12 | }
13 |
14 | public int getItemSize() {
15 | if (list == null) {
16 | throw new RuntimeException("list is null");
17 | }
18 | return list.size();
19 | }
20 |
21 | public Drawable getDrawable(int position) {
22 | if (this.list == null) {
23 | throw new RuntimeException("list is null");
24 | }
25 | if (position >= list.size()) {
26 | return list.get(position % list.size());
27 | }
28 | return list.get(position);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/divider/ItemTouchUIUtilImpl.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.divider;
2 |
3 | import android.graphics.Canvas;
4 | import android.support.v4.view.ViewCompat;
5 | import android.support.v7.recyclerview.R;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.support.v7.widget.helper.ItemTouchUIUtil;
8 | import android.view.View;
9 |
10 | /**
11 | * Package private class to keep implementations. Putting them inside ItemTouchUIUtil makes them
12 | * public API, which is not desired in this case.
13 | */
14 | class ItemTouchUIUtilImpl {
15 | static class Api21Impl extends ItemTouchUIUtilImpl.BaseImpl {
16 | @Override
17 | public void onDraw(Canvas c, RecyclerView recyclerView, View view,
18 | float dX, float dY, int actionState, boolean isCurrentlyActive) {
19 | if (isCurrentlyActive) {
20 | Object originalElevation = view.getTag(R.id.item_touch_helper_previous_elevation);
21 | if (originalElevation == null) {
22 | originalElevation = ViewCompat.getElevation(view);
23 | float newElevation = 1f + findMaxElevation(recyclerView, view);
24 | ViewCompat.setElevation(view, newElevation);
25 | view.setTag(R.id.item_touch_helper_previous_elevation, originalElevation);
26 | }
27 | }
28 | super.onDraw(c, recyclerView, view, dX, dY, actionState, isCurrentlyActive);
29 | }
30 |
31 | private float findMaxElevation(RecyclerView recyclerView, View itemView) {
32 | final int childCount = recyclerView.getChildCount();
33 | float max = 0;
34 | for (int i = 0; i < childCount; i++) {
35 | final View child = recyclerView.getChildAt(i);
36 | if (child == itemView) {
37 | continue;
38 | }
39 | final float elevation = ViewCompat.getElevation(child);
40 | if (elevation > max) {
41 | max = elevation;
42 | }
43 | }
44 | return max;
45 | }
46 |
47 | @Override
48 | public void clearView(View view) {
49 | final Object tag = view.getTag(R.id.item_touch_helper_previous_elevation);
50 | if (tag != null && tag instanceof Float) {
51 | ViewCompat.setElevation(view, (Float) tag);
52 | }
53 | view.setTag(R.id.item_touch_helper_previous_elevation, null);
54 | super.clearView(view);
55 | }
56 | }
57 |
58 | static class BaseImpl implements ItemTouchUIUtil {
59 |
60 | @Override
61 | public void clearView(View view) {
62 | view.setTranslationX(0f);
63 | view.setTranslationY(0f);
64 | }
65 |
66 | @Override
67 | public void onSelected(View view) {
68 |
69 | }
70 |
71 | @Override
72 | public void onDraw(Canvas c, RecyclerView recyclerView, View view,
73 | float dX, float dY, int actionState, boolean isCurrentlyActive) {
74 | view.setTranslationX(dX);
75 | view.setTranslationY(dY);
76 | }
77 |
78 | @Override
79 | public void onDrawOver(Canvas c, RecyclerView recyclerView,
80 | View view, float dX, float dY, int actionState, boolean isCurrentlyActive) {
81 |
82 | }
83 | }
84 | }
85 |
86 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/divider/LeftOnlyDivider.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.divider;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Rect;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.view.View;
10 |
11 | import io.github.rangaofei.sakatimeline.config.TimeLineConfig;
12 | import io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter;
13 |
14 | public class LeftOnlyDivider extends BaseDivider {
15 | private Paint drawPaint;
16 |
17 | private Paint linePaint;
18 | private Rect drawRect = new Rect();
19 |
20 | public LeftOnlyDivider(RecyclerView recyclerView, TimeLineConfig timeLineConfig) {
21 | super(recyclerView, timeLineConfig);
22 | drawPaint = new Paint();
23 | drawPaint.setColor(Color.parseColor("#259b24"));
24 | drawPaint.setStrokeWidth(timeLineConfig.getTimeStrokeWidth());
25 | linePaint = new Paint();
26 | linePaint.setColor(Color.parseColor("#259b24"));
27 | linePaint.setStrokeWidth(timeLineConfig.getTimeStrokeWidth());
28 | }
29 |
30 | @Override
31 | public void onChildDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
32 |
33 | }
34 |
35 | @Override
36 | public void onChildDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
37 | float x = 0;
38 | for (int i = 0; i < parent.getChildCount(); i++) {
39 | final View view = parent.getChildAt(i);
40 | if (parent.getChildViewHolder(view) instanceof AbstractTimeLineAdapter.KeyViewHolder) {
41 | drawPaint.setColor(Color.RED);
42 | x = view.getLeft() - padding / 2;
43 | } else if (parent.getChildViewHolder(view) instanceof AbstractTimeLineAdapter.ValueViewHolder) {
44 | drawPaint.setColor(Color.GREEN);
45 |
46 | x = view.getLeft() - padding - padding / 2;
47 | }
48 | //画垂直的线
49 | linePaint.setStrokeWidth(timeLineConfig.getTimeStrokeWidth());
50 | if (i != 0 && i != parent.getChildCount() - 1) {
51 | c.drawLine(x, view.getTop() - 10,
52 | x, view.getBottom() + 10, linePaint);
53 | } else if (i == 0) {
54 | c.drawLine(x, view.getTop() + view.getHeight() / 2 + padding / 5 + 5,
55 | x, view.getBottom() + 10, linePaint);
56 | } else if (i == parent.getChildCount() - 1) {
57 | c.drawLine(x, view.getTop() - 10,
58 | x, view.getBottom() - view.getHeight() / 2 - padding / 5 - 5, linePaint);
59 | }
60 |
61 |
62 | //画横线
63 | // c.drawLine(x + padding / 4 + 10, view.getTop() + view.getHeight() / 2,
64 | // view.getLeft() + 20, view.getTop() + view.getHeight() / 2, linePaint);
65 |
66 | //画圆圈
67 | drawPaint.setStyle(Paint.Style.FILL);
68 | c.drawCircle(x, view.getTop() + view.getHeight() / 2, padding / 5, drawPaint);
69 | drawPaint.setStyle(Paint.Style.STROKE);
70 | drawPaint.setStrokeWidth(5);
71 | c.drawCircle(x, view.getTop() + view.getHeight() / 2, padding / 5 + 5, drawPaint);
72 | if (timeLineConfig.getTimeDrawable() != null) {
73 | drawRect.set((int) x - timeLineConfig.getBitmap().getWidth() / 4,
74 | view.getTop() + view.getHeight() / 2 - timeLineConfig.getBitmap().getHeight() / 4,
75 | (int) x + timeLineConfig.getBitmap().getWidth() / 4,
76 | view.getTop() + view.getHeight() / 2 + timeLineConfig.getBitmap().getHeight() / 4);
77 | c.drawBitmap(timeLineConfig.getBitmap(), null, drawRect, null);
78 | }
79 |
80 | }
81 | drawPaint.setColor(Color.parseColor("#259b24"));
82 |
83 | }
84 |
85 | @Override
86 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
87 | int realPadding = (int) padding;
88 | if (parent.getChildViewHolder(view) instanceof AbstractTimeLineAdapter.KeyViewHolder) {
89 |
90 | } else if (parent.getChildViewHolder(view) instanceof AbstractTimeLineAdapter.ValueViewHolder) {
91 | realPadding = 2 * realPadding;
92 | }
93 | outRect.set(realPadding, 10, 0, 10);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/divider/LeftRightDivider.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.divider;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Rect;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.View;
8 |
9 | import io.github.rangaofei.sakatimeline.config.TimeLineConfig;
10 | import io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter;
11 |
12 | public class LeftRightDivider extends BaseDivider {
13 | public LeftRightDivider(RecyclerView recyclerView, TimeLineConfig timeLineConfig) {
14 | super(recyclerView, timeLineConfig);
15 | }
16 |
17 | @Override
18 | public void onChildDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
19 |
20 | }
21 |
22 | @Override
23 | public void onChildDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
24 |
25 | }
26 |
27 | @Override
28 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
29 | int realLeftPadding = 0;
30 | int realRightPadding = 0;
31 | if (parent.getChildViewHolder(view) instanceof AbstractTimeLineAdapter.KeyViewHolder) {
32 | realRightPadding = (int) padding;
33 | } else if (parent.getChildViewHolder(view) instanceof AbstractTimeLineAdapter.ValueViewHolder) {
34 | realLeftPadding = (int) padding;
35 | }
36 | outRect.set(realLeftPadding, 10, realRightPadding, 10);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/divider/RightOnlyDivider.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.divider;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Rect;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.view.View;
10 |
11 | import io.github.rangaofei.sakatimeline.config.TimeLineConfig;
12 | import io.github.rangaofei.sakatimeline.adapter.AbstractTimeLineAdapter;
13 |
14 | public class RightOnlyDivider extends BaseDivider {
15 |
16 |
17 | private Paint drawPaint;
18 |
19 | private Paint linePaint;
20 |
21 | public RightOnlyDivider(RecyclerView recyclerView, TimeLineConfig timeLineConfig) {
22 | super(recyclerView, timeLineConfig);
23 | drawPaint = new Paint();
24 | drawPaint.setColor(Color.parseColor("#259b24"));
25 | drawPaint.setStrokeWidth(timeLineConfig.getTimeStrokeWidth());
26 | linePaint = new Paint();
27 | linePaint.setColor(Color.parseColor("#259b24"));
28 | linePaint.setStrokeWidth(timeLineConfig.getTimeStrokeWidth());
29 | }
30 |
31 | @Override
32 | public void onChildDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
33 |
34 | }
35 |
36 | @Override
37 | public void onChildDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
38 | float x = 0;
39 | for (int i = 0; i < parent.getChildCount(); i++) {
40 | final View view = parent.getChildAt(i);
41 | if (parent.getChildViewHolder(view) instanceof AbstractTimeLineAdapter.KeyViewHolder) {
42 | drawPaint.setColor(Color.RED);
43 | x = view.getRight() + padding / 2;
44 | } else if (parent.getChildViewHolder(view) instanceof AbstractTimeLineAdapter.ValueViewHolder) {
45 | drawPaint.setColor(Color.GREEN);
46 | x = view.getRight() + padding + padding / 2;
47 | }
48 | //画垂直的线
49 | linePaint.setStrokeWidth(timeLineConfig.getTimeStrokeWidth());
50 | if (i != 0 && i != parent.getChildCount() - 1) {
51 | c.drawLine(x, view.getTop() - 10,
52 | x, view.getBottom() + 10, linePaint);
53 | } else if (i == 0) {
54 | c.drawLine(x, view.getTop() + view.getHeight() / 2 + padding / 5 + 5,
55 | x, view.getBottom() + 10, linePaint);
56 | } else if (i == parent.getChildCount() - 1) {
57 | c.drawLine(x, view.getTop() - 10,
58 | x, view.getBottom() - view.getHeight() / 2 - padding / 5 - 5, linePaint);
59 | }
60 |
61 |
62 | //画横线
63 | c.drawLine(x - padding / 4 - 10, view.getTop() + view.getHeight() / 2,
64 | view.getRight() - 20, view.getTop() + view.getHeight() / 2, linePaint);
65 |
66 | //画圆圈
67 | drawPaint.setStyle(Paint.Style.FILL);
68 | c.drawCircle(x, view.getTop() + view.getHeight() / 2, padding / 5, drawPaint);
69 | drawPaint.setStyle(Paint.Style.STROKE);
70 | drawPaint.setStrokeWidth(5);
71 | c.drawCircle(x, view.getTop() + view.getHeight() / 2, padding / 5 + 5, drawPaint);
72 |
73 | }
74 | drawPaint.setColor(Color.parseColor("#259b24"));
75 |
76 | }
77 |
78 | @Override
79 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
80 | int realPadding = (int) padding;
81 | if (parent.getChildViewHolder(view) instanceof AbstractTimeLineAdapter.KeyViewHolder) {
82 |
83 | } else if (parent.getChildViewHolder(view) instanceof AbstractTimeLineAdapter.ValueViewHolder) {
84 | realPadding = 2 * realPadding;
85 | }
86 | outRect.set(0, 10, realPadding, 10);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/divider/SlideTouchHelperCallBack.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.divider;
2 |
3 | import android.graphics.Canvas;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.support.v7.widget.helper.ItemTouchHelper;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | public class SlideTouchHelperCallBack extends SakaItemTouchHelper.Callback {
11 |
12 | private RecyclerView.ViewHolder preViewHolder;
13 | private RecyclerView.ViewHolder curViewHolder;
14 |
15 | @Override
16 | public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
17 | int swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
18 | return makeMovementFlags(0, swipeFlag);
19 | }
20 |
21 | @Override
22 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
23 | return false;
24 | }
25 |
26 | @Override
27 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
28 | Log.d("---", "onSwiped");
29 | }
30 |
31 | @Override
32 | public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
33 | super.clearView(recyclerView, viewHolder);
34 | Log.d("---", "clearView");
35 | }
36 |
37 | @Override
38 | public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
39 | Log.d("---", "dx=" + dX);
40 | if (actionState != ItemTouchHelper.ACTION_STATE_SWIPE) {
41 | return;
42 | }
43 | if (viewHolder != null) {
44 | curViewHolder = viewHolder;
45 | }
46 | View viewShow = ((ViewGroup) viewHolder.itemView).getChildAt(1);
47 | View viewHide = ((ViewGroup) viewHolder.itemView).getChildAt(0);
48 | int maxWidth = getMaxWidth(viewHide);
49 | if (!isCurrentlyActive) {
50 | if (viewShow.getTranslationX() >= maxWidth) {
51 | viewShow.setTranslationX(maxWidth);
52 | } else if (viewShow.getTranslationX() < maxWidth) {
53 | viewShow.setTranslationX(0);
54 | }
55 | return;
56 | }
57 |
58 | viewShow.setTranslationX(dX);
59 | }
60 |
61 | @Override
62 | public boolean isItemViewSwipeEnabled() {
63 | return true;
64 | }
65 |
66 | @Override
67 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
68 | Log.d("---", "onSelectedChanged:" + actionState);
69 | if (actionState != SakaItemTouchHelper.ACTION_STATE_IDLE) {
70 | preViewHolder = curViewHolder;
71 | curViewHolder = viewHolder;
72 | if (preViewHolder != null)
73 | ((ViewGroup) preViewHolder.itemView).getChildAt(1).setTranslationX(0);
74 | }
75 | }
76 |
77 | public int getMaxWidth(View view) {
78 | return view.getWidth();
79 | }
80 |
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/divider/SwipeBehavior.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.divider;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.NonNull;
5 | import android.support.design.widget.CoordinatorLayout;
6 | import android.util.AttributeSet;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | public class SwipeBehavior extends CoordinatorLayout.Behavior {
12 |
13 | public SwipeBehavior() {
14 | }
15 |
16 | public SwipeBehavior(Context context, AttributeSet attrs) {
17 | super(context, attrs);
18 | }
19 |
20 | @Override
21 | public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
22 | if (dependency != null) {
23 | Log.d("---", "依赖成功");
24 | return true;
25 | }
26 | Log.d("---", "依赖失败");
27 | return false;
28 | }
29 |
30 | @Override
31 | public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
32 | // parent.getChildAt(1).setTranslationX(-100);
33 | return false;
34 | }
35 |
36 | @Override
37 | public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
38 | float x = dependency.getTranslationX();
39 | Log.d("---", "x=" + x);
40 | // child.setTranslationX(x / 2);
41 | return true;
42 | }
43 |
44 | @Override
45 | public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
46 | @NonNull View child,
47 | @NonNull View directTargetChild,
48 | @NonNull View target, int axes, int type) {
49 | return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type);
50 | }
51 |
52 | @Override
53 | public void onNestedScrollAccepted(@NonNull CoordinatorLayout coordinatorLayout,
54 | @NonNull View child,
55 | @NonNull View directTargetChild,
56 | @NonNull View target, int axes, int type) {
57 | super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, axes, type);
58 | }
59 |
60 | @Override
61 | public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout,
62 | @NonNull View child,
63 | @NonNull View target,
64 | int dx, int dy,
65 | @NonNull int[] consumed, int type) {
66 | super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
67 | }
68 |
69 | @Override
70 | public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
71 | @NonNull View child,
72 | @NonNull View target,
73 | int dxConsumed, int dyConsumed,
74 | int dxUnconsumed, int dyUnconsumed, int type) {
75 | super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
76 | }
77 |
78 | @Override
79 | public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout,
80 | @NonNull View child,
81 | @NonNull View target, float velocityX, float velocityY) {
82 | return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
83 | }
84 |
85 | @Override
86 | public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
87 | @NonNull View child,
88 | @NonNull View target, int type) {
89 | super.onStopNestedScroll(coordinatorLayout, child, target, type);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/divider/TimeLineDivider.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.divider;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Color;
5 | import android.graphics.Paint;
6 | import android.graphics.Rect;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.view.View;
10 |
11 | import io.github.rangaofei.sakatimeline.config.TimeLineConfig;
12 |
13 | public class TimeLineDivider extends RecyclerView.ItemDecoration {
14 | private Rect itemRect = new Rect();
15 | private Paint paint;
16 | private Paint textPaint;
17 | private TimeLineConfig timeLineConfig;
18 |
19 | public TimeLineDivider() {
20 | paint = new Paint();
21 | paint.setColor(Color.TRANSPARENT);
22 | paint.setAntiAlias(true);
23 | textPaint = new Paint(paint);
24 | textPaint.setColor(Color.BLACK);
25 | textPaint.setAntiAlias(true);
26 | textPaint.setTextSize(50);
27 | textPaint.setStrokeWidth(20);
28 | }
29 |
30 | public void setTimeLineConfig(TimeLineConfig timeLineConfig) {
31 | this.timeLineConfig = timeLineConfig;
32 | textPaint.setStrokeWidth(timeLineConfig.getTimeStrokeWidth());
33 | textPaint.setColor(timeLineConfig.getTimeColor());
34 | }
35 |
36 | @Override
37 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
38 |
39 |
40 | }
41 |
42 | @Override
43 | public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
44 | for (int i = 0; i < parent.getLayoutManager().getChildCount(); i++) {
45 | final View view = parent.getChildAt(i);
46 | if (i % 2 == 1) {
47 |
48 | }
49 | }
50 | }
51 |
52 | @Override
53 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
54 | if (!(parent.getLayoutManager() instanceof LinearLayoutManager)) {
55 | throw new RuntimeException("do not support");
56 |
57 | }
58 |
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/divider/TimeLineType.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.divider;
2 |
3 | public interface TimeLineType {
4 |
5 | //stepview的枚举类
6 | enum StepViewType implements TimeLineType {
7 | LEFT_STEP_PROGRESS,//左侧显示当前的步骤,右侧显示内容
8 | RIGHT_STEP_PROGRESS,//右侧显示当前的步骤,左侧显示内容
9 | TOP_STEP_PROGRESS,//上侧显示当前的步骤,下侧显示内容
10 | BOTTOM_STEP_PROGRESS,//下侧显示当前的步骤,上侧显示内容
11 | }
12 |
13 | enum TimeLineViewType implements TimeLineType {
14 | ONLY_RIGHT,//key和value在左侧侧显示,右侧显示时间轴
15 | ONLY_LEFT,//key和value在右侧显示,左侧显示时间轴
16 | LEFT_TO_RIGHT,//先左侧显示key,右侧显示value,中间显示时间轴,然后右侧显示key,左侧显示value,交替
17 | RIGHT_TO_LEFT,//先右侧显示key,左侧显示value,中间显示时间轴,然后左侧显示key,右侧显示value,交替
18 | LEFT_KEY,//左侧显示key,右侧显示value,中间显示时间轴
19 | LEFT_VALUE,//左侧显示value,右侧显示key,中间显示时间轴
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/exception/BaseException.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.exception;
2 |
3 | public class BaseException extends RuntimeException {
4 | private int exceptionCode;
5 |
6 | public BaseException(ExceptionMessage message) {
7 | super(message.getMessage());
8 | this.exceptionCode = message.getCode();
9 | }
10 |
11 | public BaseException(TimeLineException exception) {
12 | super(exception.getMessage());
13 | this.exceptionCode = exception.getCode();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/exception/ExceptionMessage.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.exception;
2 |
3 | public enum ExceptionMessage {
4 | LAYOUT_MANAGER_NULL(0x01, "the recyclerView's layoutManager is null"),
5 | UNKNOWN_ORIENTATION(0x02, "the recyclerView's layoutManager's orientation unknown"),
6 | NOT_LINEAR_LAYOUT_MANAGER(0x03, "the recyclerView's layoutManager is not LinearLayoutManager"),
7 | NOT_VERTICAL_ORIENTATION(0x04, "the recyclerView's layoutManager is not Vertical orientation"),
8 | NOT_HORIZONTAL_ORIENTATION(0x04, "the recyclerView's layoutManager is not Vertical orientation"),
9 | ADAPTER_NULL(0x05, "the adapter is null"),
10 | DRAWABLE_NULL(0x06, "the drawable is not correct!");
11 |
12 | ExceptionMessage(int code, String message) {
13 | this.code = code;
14 | this.message = message;
15 | }
16 |
17 | private int code;
18 | private String message;
19 |
20 | public int getCode() {
21 | return code;
22 | }
23 |
24 | public void setCode(int code) {
25 | this.code = code;
26 | }
27 |
28 | public String getMessage() {
29 | return message;
30 | }
31 |
32 | public void setMessage(String message) {
33 | this.message = message;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/exception/TimeLineException.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.exception;
2 |
3 | public interface TimeLineException {
4 | int getCode();
5 |
6 | String getMessage();
7 | }
8 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/exception/TimeLineViewException.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.exception;
2 |
3 | public enum TimeLineViewException implements TimeLineException {
4 | NULL_CONFIG(0x11, "TimeLineConfigure is null"),;
5 |
6 | TimeLineViewException(int code, String message) {
7 | this.code = code;
8 | this.message = message;
9 | }
10 |
11 | private int code;
12 | private String message;
13 |
14 | public int getCode() {
15 | return code;
16 | }
17 |
18 | public void setCode(int code) {
19 | this.code = code;
20 | }
21 |
22 | public String getMessage() {
23 | return message;
24 | }
25 |
26 | public void setMessage(String message) {
27 | this.message = message;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/indexdecoration/IndexDecoration.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.indexdecoration;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Rect;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.View;
7 |
8 | public class IndexDecoration extends RecyclerView.ItemDecoration {
9 |
10 | private RecyclerView recyclerView;
11 | private RecyclerView.LayoutManager layoutManager;
12 | private int indexPadding;
13 |
14 |
15 | @Override
16 | public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
17 | View view = parent.getLayoutManager().getChildAt(0);
18 | }
19 |
20 | @Override
21 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
22 | super.onDraw(c, parent, state);
23 | }
24 |
25 | @Override
26 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
27 | super.getItemOffsets(outRect, view, parent, state);
28 | }
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/proxy/TextViewInterface.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.proxy;
2 |
3 | import android.content.Context;
4 |
5 | public interface TextViewInterface {
6 | void setTextAppearance(Context context, int id);
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/proxy/TextViewProxy.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.proxy;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Color;
6 | import android.graphics.drawable.Drawable;
7 | import android.util.AttributeSet;
8 | import android.util.Log;
9 | import android.util.TypedValue;
10 | import android.util.Xml;
11 | import android.view.View;
12 | import android.widget.ImageView;
13 | import android.widget.TextView;
14 |
15 | import org.xmlpull.v1.XmlPullParser;
16 |
17 | import java.lang.reflect.Type;
18 | import java.lang.reflect.TypeVariable;
19 |
20 | import io.github.rangaofei.sakatimeline.R;
21 |
22 |
23 | public class TextViewProxy implements TextViewInterface {
24 | private TextView textView;
25 |
26 |
27 | public TextViewProxy(TextView textView) {
28 | this.textView = textView;
29 | }
30 |
31 | @Override
32 | public void setTextAppearance(Context context, int id) {
33 | textView.setTextAppearance(textView.getContext(), id);
34 | ViewProxy viewProxy = new ViewProxy<>(textView);
35 | viewProxy.setStyle(id);
36 |
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/proxy/TextViewProxyHandler.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.proxy;
2 |
3 | import android.util.Log;
4 | import android.widget.TextView;
5 |
6 | import java.lang.reflect.InvocationHandler;
7 | import java.lang.reflect.Method;
8 |
9 | public class TextViewProxyHandler implements InvocationHandler {
10 | private TextView textView;
11 |
12 | public TextViewProxyHandler(TextView textView) {
13 | this.textView = textView;
14 | }
15 |
16 | @Override
17 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
18 | Log.d("+++", method.getName());
19 | if (method.getName().equals("setTextAppearance")) {
20 | Log.d("+++", proxy.getClass().getName());
21 | return method.invoke(new TextViewProxy(textView), args);
22 | }
23 | return method.invoke(this, args);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/proxy/ViewInterface.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.proxy;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 |
6 | public interface ViewInterface {
7 |
8 | T setStyle(int id);
9 |
10 | T getView();
11 | }
12 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/proxy/ViewProxy.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.proxy;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.drawable.Drawable;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.widget.TextView;
9 |
10 | import io.github.rangaofei.sakatimeline.R;
11 |
12 | /**
13 | * 一个基本的view
14 | */
15 | public class ViewProxy implements ViewInterface {
16 | private T t;
17 |
18 | public ViewProxy(T t) {
19 | this.t = t;
20 | }
21 |
22 | @Override
23 | public T setStyle(int id) {
24 | TypedArray ta = t.getContext().obtainStyledAttributes(id, R.styleable.TimeLineViewProxy);
25 | Drawable drawable = ta.getDrawable(R.styleable.TimeLineViewProxy_backgroundProxy);
26 | int v = ta.getInt(R.styleable.TimeLineViewProxy_visibleProxy, -1);
27 | boolean clickable = ta.getBoolean(R.styleable.TimeLineViewProxy_clickProxy, true);
28 | setBackground(drawable);
29 | setClickAble(clickable);
30 | setVisibility(v);
31 | ta.recycle();
32 | return this.t;
33 | }
34 |
35 | @Override
36 | public T getView() {
37 | return this.t;
38 | }
39 |
40 | /**
41 | * 设置view的可见性
42 | */
43 | private void setVisibility(int v) {
44 | if (v == -1) {
45 | return;
46 | }
47 | switch (v) {
48 | case 0:
49 | t.setVisibility(View.VISIBLE);
50 | break;
51 | case 1:
52 | t.setVisibility(View.INVISIBLE);
53 | break;
54 | case 2:
55 | t.setVisibility(View.GONE);
56 | break;
57 | }
58 | }
59 |
60 | private void setBackground(Drawable drawable) {
61 | Log.d("+++", "presetBackground");
62 | if (drawable == null) {
63 | Log.d("+++", "setBackground");
64 | return;
65 | }
66 |
67 | t.setBackground(drawable);
68 | }
69 |
70 | private void setClickAble(boolean clickAble) {
71 | t.setClickable(clickAble);
72 | }
73 |
74 |
75 | private void setSpecialView(int id) {
76 | if (this.t instanceof TextView) {
77 | ((TextView) this.t).setTextAppearance(this.t.getContext(), id);
78 | }
79 | }
80 | }
81 |
82 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/proxy/ViewProxyHandler.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.proxy;
2 |
3 | import android.widget.TextView;
4 |
5 | import java.lang.reflect.InvocationHandler;
6 | import java.lang.reflect.Method;
7 |
8 | public class ViewProxyHandler implements InvocationHandler {
9 | private ViewInterface viewInterface;
10 |
11 | public ViewProxyHandler(ViewInterface viewInterface) {
12 | this.viewInterface = viewInterface;
13 | }
14 |
15 | @Override
16 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
17 | if (method.getName().equals("setStyle")) {
18 | if (this.viewInterface.getView() instanceof TextView) {
19 | ((TextView) this.viewInterface.getView()).
20 | setTextAppearance(((TextView) this.viewInterface.getView()).getContext(),
21 | (int) args[0]);
22 | }
23 | return method.invoke(viewInterface, args);
24 | }
25 | return method.invoke(viewInterface, args);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/snaphelper/ScaleSnapHelper.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.snaphelper;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.support.v7.widget.SnapHelper;
7 | import android.view.View;
8 |
9 | public class ScaleSnapHelper extends SnapHelper {
10 | @Nullable
11 | @Override
12 | public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
13 | return new int[0];
14 | }
15 |
16 | @Nullable
17 | @Override
18 | public View findSnapView(RecyclerView.LayoutManager layoutManager) {
19 | return null;
20 | }
21 |
22 | @Override
23 | public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
24 | return 0;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/timelineedgeeffect/CustomEdgeEffectFactory.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.timelineedgeeffect;
2 |
3 | import android.os.HandlerThread;
4 | import android.support.annotation.NonNull;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.widget.EdgeEffect;
7 |
8 | public class CustomEdgeEffectFactory extends RecyclerView.EdgeEffectFactory{
9 | // HandlerThread
10 | @NonNull
11 | @Override
12 | protected EdgeEffect createEdgeEffect(RecyclerView view, int direction) {
13 | return super.createEdgeEffect(view, direction);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/timelineedgeeffect/SakaEffectEdge.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.timelineedgeeffect;
2 |
3 | import android.content.Context;
4 | import android.widget.EdgeEffect;
5 |
6 | public class SakaEffectEdge extends EdgeEffect {
7 | /**
8 | * Construct a new EdgeEffect with a theme appropriate for the provided context.
9 | *
10 | * @param context Context used to provide theming and resource information for the EdgeEffect
11 | */
12 | public SakaEffectEdge(Context context) {
13 | super(context);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/util/AndroidUtil.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.util;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.Canvas;
6 | import android.graphics.drawable.BitmapDrawable;
7 | import android.graphics.drawable.Drawable;
8 | import android.graphics.drawable.VectorDrawable;
9 | import android.support.annotation.DrawableRes;
10 | import android.support.graphics.drawable.VectorDrawableCompat;
11 | import android.support.v4.content.ContextCompat;
12 |
13 | public class AndroidUtil {
14 | /**
15 | * dp转换成px
16 | */
17 | public static int dp2px(Context context, float dpValue) {
18 | float scale = context.getResources().getDisplayMetrics().density;
19 | return (int) (dpValue * scale + 0.5f);
20 | }
21 |
22 |
23 | /**
24 | * px转换成dp
25 | */
26 | public static int px2dp(Context context, float pxValue) {
27 | float scale = context.getResources().getDisplayMetrics().density;
28 | return (int) (pxValue / scale + 0.5f);
29 | }
30 |
31 | /**
32 | * sp转换成px
33 | */
34 | public static int sp2px(Context context, float spValue) {
35 | float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
36 | return (int) (spValue * fontScale + 0.5f);
37 | }
38 |
39 | /**
40 | * px转换成sp
41 | */
42 | public static int px2sp(Context context, float pxValue) {
43 | float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
44 | return (int) (pxValue / fontScale + 0.5f);
45 | }
46 |
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/util/ExceptionUtil.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.util;
2 |
3 | import io.github.rangaofei.sakatimeline.exception.BaseException;
4 | import io.github.rangaofei.sakatimeline.exception.TimeLineException;
5 |
6 | public class ExceptionUtil {
7 |
8 | public static void checkIfNull(Object o, String name) {
9 | if (o == null) {
10 | thrException(new NullPointerException(name));
11 | }
12 | }
13 |
14 | public static void thrException(TimeLineException exception) {
15 | throw new BaseException(exception);
16 |
17 | }
18 |
19 | public static void thrException(RuntimeException e) {
20 | throw e;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/java/io/github/rangaofei/sakatimeline/util/ProxyUtil.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline.util;
2 |
3 | import android.support.annotation.IdRes;
4 | import android.view.View;
5 |
6 | import java.lang.reflect.Proxy;
7 |
8 | import io.github.rangaofei.sakatimeline.adapter.BaseViewHolder;
9 | import io.github.rangaofei.sakatimeline.proxy.ViewInterface;
10 | import io.github.rangaofei.sakatimeline.proxy.ViewProxy;
11 | import io.github.rangaofei.sakatimeline.proxy.ViewProxyHandler;
12 |
13 | public class ProxyUtil {
14 |
15 | @SuppressWarnings("unchecked")
16 | public static ViewInterface createView(final BaseViewHolder viewHolder,
17 | @IdRes final int id) {
18 | T result = viewHolder.itemView.findViewById(id);
19 |
20 | return (ViewInterface) Proxy.newProxyInstance(
21 | ViewInterface.class.getClassLoader(),
22 | new Class[]{ViewInterface.class},
23 | new ViewProxyHandler(new ViewProxy(result)));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/res/drawable/drawable_null.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/res/drawable/ic_order.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/res/drawable/order.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rangaofei/TimeLine/3a21f5b3b72d1f4f0764b66b5006d8596e0e1138/sakatimeline/src/main/res/drawable/order.png
--------------------------------------------------------------------------------
/sakatimeline/src/main/res/layout/null_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFFFF
4 | #FF000000
5 |
6 |
7 | #259b24
8 | #9e9e9e
9 | #e51c23
10 | #e91e63
11 | #9c27b0
12 | #673abc
13 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 30dp
4 | 10dp
5 | 15sp
6 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SakaTimeLine
3 |
4 |
--------------------------------------------------------------------------------
/sakatimeline/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
56 |
--------------------------------------------------------------------------------
/sakatimeline/src/test/java/io/github/rangaofei/sakatimeline/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package io.github.rangaofei.sakatimeline;
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() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':sakatimeline', ':JavaTimeLine', ':libannotations'
2 |
--------------------------------------------------------------------------------