├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── lin │ │ └── timeline │ │ └── example │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── lin │ │ │ └── timeline │ │ │ └── example │ │ │ ├── AbsOrderDelegate.java │ │ │ ├── Analog.java │ │ │ ├── AnalogAdapter.java │ │ │ ├── BaseViewHolder.java │ │ │ ├── ButtonDelegate.java │ │ │ ├── ImageDelegate.java │ │ │ ├── InfoOrder.java │ │ │ ├── InfoOrderDelegate.java │ │ │ ├── LocationOrder.java │ │ │ ├── LocationOrderDelegate.java │ │ │ ├── MainActivity.java │ │ │ ├── MarkerDelegate.java │ │ │ ├── Order.java │ │ │ ├── OrderActivity.java │ │ │ ├── OrderAdapter.java │ │ │ ├── Picture.java │ │ │ ├── RatingDelegate.java │ │ │ ├── TextDelegate.java │ │ │ ├── TextOrder.java │ │ │ ├── TextOrderDelegate.java │ │ │ ├── TimeDelegate.java │ │ │ ├── TimeLineActivity.java │ │ │ ├── Trace.java │ │ │ ├── TraceActivity.java │ │ │ └── TraceAdapter.java │ └── res │ │ ├── drawable │ │ ├── begin_marker.xml │ │ ├── begin_up.xml │ │ ├── marker.xml │ │ ├── up.xml │ │ └── vector_default_image.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_timeline.xml │ │ ├── activity_trace.xml │ │ ├── analog_item.xml │ │ ├── order_info.xml │ │ ├── order_location.xml │ │ ├── order_text.xml │ │ ├── trace_button.xml │ │ ├── trace_image.xml │ │ ├── trace_marker_text.xml │ │ ├── trace_rating.xml │ │ ├── trace_text.xml │ │ └── trace_time.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 │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── lin │ └── timeline │ └── example │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ └── gradle-wrapper.jar ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── bintray.gradle ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── lin │ └── timeline │ └── TimeLineDecoration.java ├── screenshots ├── 20170821160031.png ├── 20170821160048.png └── 20170821160103.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TimeLine 2 | Android Timeline View is used to display views like Tracking of shipment/order, steppers etc. 3 | 4 |
![](https://github.com/lin18/TimeLine/blob/master/screenshots/20170821160031.png?raw=true) 5 | ![](https://github.com/lin18/TimeLine/blob/master/screenshots/20170821160048.png?raw=true) 6 | ![](https://github.com/lin18/TimeLine/blob/master/screenshots/20170821160103.png?raw=true) 7 | 8 | # Use 9 | ```gradle 10 | compile 'com.lin:timeline:1.1@aar' 11 | ``` 12 | 13 | ``` Java 14 | final TimeLineDecoration decoration = new TimeLineDecoration(this) 15 | .setLineColor(android.R.color.black) 16 | .setLineWidth(1) 17 | .setLeftDistance(16) 18 | .setTopDistance(16) 19 | .setBeginMarker(R.drawable.begin_marker) 20 | .setMarkerRadius(4) 21 | .setMarkerColor(R.color.colorAccent) 22 | .setCallback(new TimeLineDecoration.TimeLineAdapter() {//or new TimeLineDecoration.TimeLineCallback 23 | @Override 24 | public int getTimeLineType(int position) { 25 | if (position == 0) return BEGIN; 26 | else if (position == adapter.getItemCount() - 1) return END_FULL; 27 | else return NORMAL; 28 | } 29 | }); 30 | recyclerView.addItemDecoration(decoration); 31 | ``` 32 |
如果要把时间轴写到item中,建议使用 33 |
[Timeline-View](https://github.com/vipulasri/Timeline-View) 34 |
瀑布流可以使用 35 |
[TimeLine](https://github.com/vivian8725118/TimeLine) 36 | 37 |
ps:demo中adpter使用的库来自[PowerAdapter](https://github.com/lin18/PowerAdapter) 38 | 39 | # License 40 | ``` 41 | Copyright 2017 lin18 42 | 43 | Licensed under the Apache License, Version 2.0 (the "License"); 44 | you may not use this file except in compliance with the License. 45 | You may obtain a copy of the License at 46 | 47 | http://www.apache.org/licenses/LICENSE-2.0 48 | 49 | Unless required by applicable law or agreed to in writing, software 50 | distributed under the License is distributed on an "AS IS" BASIS, 51 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 52 | See the License for the specific language governing permissions and 53 | limitations under the License. 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.jakewharton.butterknife' 3 | 4 | android { 5 | compileSdkVersion rootProject.ext.compileSdkVersion 6 | buildToolsVersion rootProject.ext.buildToolsVersion 7 | defaultConfig { 8 | applicationId "com.lin.timeline.example" 9 | minSdkVersion rootProject.ext.minSdk 10 | targetSdkVersion rootProject.ext.targetSdk 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | vectorDrawables.useSupportLibrary = true 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile fileTree(dir: 'libs', include: ['*.jar']) 26 | compile project(':library') 27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 28 | exclude group: 'com.android.support', module: 'support-annotations' 29 | }) 30 | testCompile 'junit:junit:4.12' 31 | 32 | compile supportDependencies.appcompat 33 | compile supportDependencies.design 34 | compile supportDependencies.cardview 35 | 36 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 37 | 38 | compile "com.jakewharton:butterknife:$rootProject.butterknifeVersion" 39 | annotationProcessor "com.jakewharton:butterknife-compiler:$rootProject.butterknifeVersion" 40 | 41 | compile 'com.google.code.gson:gson:2.8.1' 42 | 43 | compile 'com.lin:poweradapter:1.3@aar' 44 | 45 | compile 'com.github.bumptech.glide:glide:4.0.0' 46 | annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0' 47 | } 48 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\soft\android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/lin/timeline/example/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.lin.timeline.example", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/AbsOrderDelegate.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.CallSuper; 5 | import android.support.annotation.LayoutRes; 6 | import android.support.annotation.NonNull; 7 | import android.support.v4.content.ContextCompat; 8 | import android.text.TextUtils; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | 13 | import com.lin.poweradapter.AdapterDelegate; 14 | import com.lin.poweradapter.PowerViewHolder; 15 | 16 | import java.util.List; 17 | 18 | import butterknife.BindView; 19 | 20 | /** 21 | * 22 | * Created by lin18 on 2017/8/23. 23 | */ 24 | 25 | public abstract class AbsOrderDelegate extends AdapterDelegate { 26 | 27 | @CallSuper 28 | @Override 29 | protected void onBindViewHolder(@NonNull Order item, int position, @NonNull PowerViewHolder holder, @NonNull List payloads) { 30 | final Context context = holder.itemView.getContext(); 31 | final AbsChildViewHolder vh = (AbsChildViewHolder) holder; 32 | final int color = ContextCompat.getColor(context, item.isHead ? R.color.colorAccent : android.R.color.darker_gray); 33 | vh.time.setTextColor(color); 34 | vh.time.setText(item.time); 35 | vh.title.setTextColor(color); 36 | vh.title.setText(item.title); 37 | vh.subtitle.setTextColor(color); 38 | vh.subtitle.setText(item.subTitle); 39 | vh.subtitle.setVisibility(TextUtils.isEmpty(item.subTitle) ? View.GONE : View.VISIBLE); 40 | } 41 | 42 | static class AbsChildViewHolder extends BaseViewHolder { 43 | 44 | @BindView(R.id.time) 45 | TextView time; 46 | @BindView(R.id.title) 47 | TextView title; 48 | @BindView(R.id.subtitle) 49 | TextView subtitle; 50 | 51 | AbsChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 52 | super(parent, layoutResId); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/Analog.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | /** 4 | * Created by lin18 on 2017/8/23. 5 | */ 6 | 7 | public class Analog { 8 | 9 | public String text; 10 | public String time; 11 | 12 | public boolean isHead; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/AnalogAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.LayoutRes; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.content.ContextCompat; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import com.lin.poweradapter.SingleAdapter; 12 | 13 | import butterknife.BindView; 14 | 15 | /** 16 | * Created by lin18 on 2017/8/23. 17 | */ 18 | 19 | public class AnalogAdapter extends SingleAdapter { 20 | 21 | public AnalogAdapter(@Nullable Object listener) { 22 | super(listener); 23 | } 24 | 25 | @Override 26 | public ChildViewHolder onCreateVHolder(ViewGroup parent, int viewType) { 27 | return new ChildViewHolder(parent, R.layout.analog_item); 28 | } 29 | 30 | @Override 31 | public void onBindVHolder(ChildViewHolder holder, int position) { 32 | final Context context = holder.itemView.getContext(); 33 | final Analog analog = getItem(position); 34 | final int color = ContextCompat.getColor(context, 35 | analog.isHead ? android.R.color.black : android.R.color.darker_gray); 36 | holder.title.setTextColor(color); 37 | holder.title.setText(analog.text); 38 | holder.subtitle.setTextColor(color); 39 | holder.subtitle.setText(analog.time); 40 | } 41 | 42 | static class ChildViewHolder extends BaseViewHolder { 43 | 44 | @BindView(R.id.title) 45 | TextView title; 46 | @BindView(R.id.subtitle) 47 | TextView subtitle; 48 | 49 | ChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 50 | super(parent, layoutResId); 51 | } 52 | 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/BaseViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.support.annotation.LayoutRes; 4 | import android.support.annotation.NonNull; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.lin.poweradapter.PowerViewHolder; 10 | 11 | import butterknife.ButterKnife; 12 | import butterknife.Unbinder; 13 | 14 | /** 15 | * Created by lin18 on 2017/8/23. 16 | */ 17 | 18 | public class BaseViewHolder extends PowerViewHolder { 19 | 20 | Unbinder unbinder; 21 | 22 | public BaseViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 23 | this(LayoutInflater.from(parent.getContext()).inflate(layoutResId, parent, false)); 24 | } 25 | 26 | public BaseViewHolder(View itemView) { 27 | super(itemView); 28 | unbinder = ButterKnife.bind(this, itemView); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/ButtonDelegate.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.LayoutRes; 5 | import android.support.annotation.NonNull; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.Button; 9 | 10 | import com.lin.poweradapter.AdapterDelegate; 11 | import com.lin.poweradapter.PowerViewHolder; 12 | 13 | import java.util.List; 14 | 15 | import butterknife.BindView; 16 | 17 | import static com.lin.timeline.example.Trace.BUTTON_TYPE; 18 | 19 | /** 20 | * 21 | * Created by lin18 on 2017/8/23. 22 | */ 23 | 24 | public class ButtonDelegate extends AdapterDelegate { 25 | 26 | private TraceAdapter.OnTraceClickListener clickListener; 27 | 28 | public ButtonDelegate(TraceAdapter.OnTraceClickListener clickListener) { 29 | this.clickListener = clickListener; 30 | } 31 | 32 | @Override 33 | protected boolean isForViewType(@NonNull Trace item, int position) { 34 | return BUTTON_TYPE.equals(item.type); 35 | } 36 | 37 | @NonNull 38 | @Override 39 | protected PowerViewHolder onCreateViewHolder(@NonNull ViewGroup parent) { 40 | return new ChildViewHolder(parent, R.layout.trace_button); 41 | } 42 | 43 | @Override 44 | protected void onBindViewHolder(@NonNull final Trace item, final int position, @NonNull PowerViewHolder holder, @NonNull List payloads) { 45 | final Context context = holder.itemView.getContext(); 46 | final ChildViewHolder vh = (ChildViewHolder) holder; 47 | 48 | vh.button.setText(item.name); 49 | vh.button.setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View v) { 52 | if (clickListener != null) 53 | clickListener.onButtonClick(position); 54 | } 55 | }); 56 | } 57 | 58 | static class ChildViewHolder extends BaseViewHolder { 59 | 60 | @BindView(R.id.button) 61 | Button button; 62 | 63 | ChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 64 | super(parent, layoutResId); 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/ImageDelegate.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.LayoutRes; 5 | import android.support.annotation.NonNull; 6 | import android.support.v7.content.res.AppCompatResources; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | 11 | import com.bumptech.glide.Glide; 12 | import com.bumptech.glide.Priority; 13 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 14 | import com.bumptech.glide.request.RequestOptions; 15 | import com.lin.poweradapter.AdapterDelegate; 16 | import com.lin.poweradapter.PowerViewHolder; 17 | 18 | import java.util.List; 19 | 20 | import butterknife.BindView; 21 | 22 | import static com.lin.timeline.example.Trace.IMG_TYPE; 23 | 24 | /** 25 | * 26 | * Created by lin18 on 2017/8/23. 27 | */ 28 | 29 | public class ImageDelegate extends AdapterDelegate { 30 | 31 | private int width; 32 | private int height; 33 | private TraceAdapter.OnTraceClickListener clickListener; 34 | 35 | public ImageDelegate(int width, int height, TraceAdapter.OnTraceClickListener clickListener) { 36 | this.width = width; 37 | this.height = height; 38 | this.clickListener = clickListener; 39 | } 40 | 41 | @Override 42 | protected boolean isForViewType(@NonNull Trace item, int position) { 43 | return IMG_TYPE.equals(item.type); 44 | } 45 | 46 | @NonNull 47 | @Override 48 | protected PowerViewHolder onCreateViewHolder(@NonNull ViewGroup parent) { 49 | return new ChildViewHolder(parent, R.layout.trace_image); 50 | } 51 | 52 | @Override 53 | protected void onBindViewHolder(@NonNull Trace item, final int position, @NonNull PowerViewHolder holder, @NonNull List payloads) { 54 | final Context context = holder.itemView.getContext(); 55 | final ChildViewHolder vh = (ChildViewHolder) holder; 56 | 57 | Glide.with(context).load(((Picture)item.value).thumb) 58 | .apply(new RequestOptions() 59 | .override(width, height) 60 | .placeholder(AppCompatResources.getDrawable(context, R.drawable.vector_default_image)) 61 | .error(AppCompatResources.getDrawable(context, R.drawable.vector_default_image)) 62 | .centerCrop() 63 | .priority(Priority.HIGH) 64 | .diskCacheStrategy(DiskCacheStrategy.NONE)) 65 | .into(vh.imageView); 66 | 67 | vh.imageView.setOnClickListener(new View.OnClickListener() { 68 | @Override 69 | public void onClick(View v) { 70 | if (clickListener != null) 71 | clickListener.onImageClick(position); 72 | } 73 | }); 74 | } 75 | 76 | static class ChildViewHolder extends BaseViewHolder { 77 | 78 | @BindView(R.id.imageView) 79 | ImageView imageView; 80 | 81 | ChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 82 | super(parent, layoutResId); 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/InfoOrder.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | /** 4 | * Created by lin18 on 2017/8/23. 5 | */ 6 | 7 | public class InfoOrder extends Order { 8 | 9 | public String url; 10 | public String phone; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/InfoOrderDelegate.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.support.annotation.LayoutRes; 4 | import android.support.annotation.NonNull; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.Button; 8 | 9 | import com.lin.poweradapter.PowerViewHolder; 10 | 11 | import java.util.List; 12 | 13 | import butterknife.BindView; 14 | 15 | /** 16 | * 17 | * Created by lin18 on 2017/8/23. 18 | */ 19 | 20 | public class InfoOrderDelegate extends AbsOrderDelegate { 21 | 22 | private OrderAdapter.OnOrderClickListener clickListener; 23 | 24 | public InfoOrderDelegate(OrderAdapter.OnOrderClickListener clickListener) { 25 | this.clickListener = clickListener; 26 | } 27 | 28 | @Override 29 | protected boolean isForViewType(@NonNull Order item, int position) { 30 | return item instanceof InfoOrder; 31 | } 32 | 33 | @NonNull 34 | @Override 35 | protected PowerViewHolder onCreateViewHolder(@NonNull ViewGroup parent) { 36 | return new ChildViewHolder(parent, R.layout.order_info); 37 | } 38 | 39 | @Override 40 | protected void onBindViewHolder(@NonNull Order item, final int position, @NonNull PowerViewHolder holder, @NonNull List payloads) { 41 | super.onBindViewHolder(item, position, holder, payloads); 42 | final ChildViewHolder vh = (ChildViewHolder) holder; 43 | vh.look.setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View v) { 46 | clickListener.onLookClick(position); 47 | } 48 | }); 49 | vh.call.setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View v) { 52 | clickListener.onCallClick(position); 53 | } 54 | }); 55 | } 56 | 57 | static class ChildViewHolder extends AbsChildViewHolder { 58 | 59 | @BindView(R.id.look) 60 | Button look; 61 | @BindView(R.id.call) 62 | Button call; 63 | 64 | ChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 65 | super(parent, layoutResId); 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/LocationOrder.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | /** 4 | * Created by lin18 on 2017/8/23. 5 | */ 6 | 7 | public class LocationOrder extends Order { 8 | 9 | public double latitude; 10 | public double longitude; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/LocationOrderDelegate.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.support.annotation.LayoutRes; 4 | import android.support.annotation.NonNull; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.Button; 8 | 9 | import com.lin.poweradapter.PowerViewHolder; 10 | 11 | import java.util.List; 12 | 13 | import butterknife.BindView; 14 | 15 | /** 16 | * 17 | * Created by lin18 on 2017/8/23. 18 | */ 19 | 20 | public class LocationOrderDelegate extends AbsOrderDelegate { 21 | 22 | private OrderAdapter.OnOrderClickListener clickListener; 23 | 24 | public LocationOrderDelegate(OrderAdapter.OnOrderClickListener clickListener) { 25 | this.clickListener = clickListener; 26 | } 27 | 28 | @Override 29 | protected boolean isForViewType(@NonNull Order item, int position) { 30 | return item instanceof LocationOrder; 31 | } 32 | 33 | @NonNull 34 | @Override 35 | protected PowerViewHolder onCreateViewHolder(@NonNull ViewGroup parent) { 36 | return new ChildViewHolder(parent, R.layout.order_location); 37 | } 38 | 39 | @Override 40 | protected void onBindViewHolder(@NonNull Order item, final int position, @NonNull PowerViewHolder holder, @NonNull List payloads) { 41 | super.onBindViewHolder(item, position, holder, payloads); 42 | final ChildViewHolder vh = (ChildViewHolder) holder; 43 | vh.location.setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View v) { 46 | clickListener.onLocationClick(position); 47 | } 48 | }); 49 | } 50 | 51 | static class ChildViewHolder extends AbsChildViewHolder { 52 | 53 | @BindView(R.id.location) 54 | Button location; 55 | 56 | ChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 57 | super(parent, layoutResId); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.content.Intent; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | 8 | /** 9 | * Created by lin18 on 2017/8/23. 10 | */ 11 | public class MainActivity extends AppCompatActivity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_main); 17 | } 18 | 19 | public void timeline(View view) { 20 | startActivity(new Intent(this, TimeLineActivity.class)); 21 | } 22 | 23 | public void order(View view) { 24 | startActivity(new Intent(this, OrderActivity.class)); 25 | } 26 | 27 | public void trace(View view) { 28 | startActivity(new Intent(this, TraceActivity.class)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/MarkerDelegate.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.LayoutRes; 5 | import android.support.annotation.NonNull; 6 | import android.support.v4.content.ContextCompat; 7 | import android.text.TextUtils; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import com.lin.poweradapter.AdapterDelegate; 12 | import com.lin.poweradapter.PowerViewHolder; 13 | 14 | import java.util.List; 15 | 16 | import butterknife.BindView; 17 | 18 | import static com.lin.timeline.example.Trace.MARKER_TYPE; 19 | 20 | /** 21 | * 22 | * Created by lin18 on 2017/8/23. 23 | */ 24 | 25 | public class MarkerDelegate extends AdapterDelegate { 26 | 27 | @Override 28 | protected boolean isForViewType(@NonNull Trace item, int position) { 29 | return MARKER_TYPE.equals(item.type); 30 | } 31 | 32 | @NonNull 33 | @Override 34 | protected PowerViewHolder onCreateViewHolder(@NonNull ViewGroup parent) { 35 | return new ChildViewHolder(parent, R.layout.trace_marker_text); 36 | } 37 | 38 | @Override 39 | protected void onBindViewHolder(@NonNull Trace item, int position, @NonNull PowerViewHolder holder, @NonNull List payloads) { 40 | final Context context = holder.itemView.getContext(); 41 | final ChildViewHolder vh = (ChildViewHolder) holder; 42 | 43 | final String title = TextUtils.isEmpty(item.name) ? (String) item.value 44 | : (item.name + ":" + item.value); 45 | 46 | vh.textView.setTextColor(ContextCompat.getColor(context, item.isHead ? R.color.item_title_color : R.color.item_color)); 47 | vh.textView.setText(title); 48 | } 49 | 50 | static class ChildViewHolder extends BaseViewHolder { 51 | 52 | @BindView(android.R.id.title) 53 | TextView textView; 54 | 55 | ChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 56 | super(parent, layoutResId); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/Order.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | /** 4 | * Created by lin18 on 2017/8/23. 5 | */ 6 | 7 | public class Order { 8 | 9 | public boolean isHead; 10 | public boolean isCustom; 11 | 12 | public String title; 13 | public String subTitle; 14 | public String time; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/OrderActivity.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.support.v7.widget.DefaultItemAnimator; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.widget.Toast; 9 | 10 | import com.lin.timeline.TimeLineDecoration; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | import butterknife.BindView; 16 | import butterknife.ButterKnife; 17 | 18 | import static com.lin.timeline.TimeLineDecoration.BEGIN; 19 | import static com.lin.timeline.TimeLineDecoration.CUSTOM; 20 | import static com.lin.timeline.TimeLineDecoration.END; 21 | import static com.lin.timeline.TimeLineDecoration.NORMAL; 22 | 23 | /** 24 | * Created by lin18 on 2017/8/23. 25 | */ 26 | public class OrderActivity extends AppCompatActivity implements OrderAdapter.OnOrderClickListener { 27 | 28 | @BindView(R.id.recyclerView) 29 | RecyclerView recyclerView; 30 | 31 | OrderAdapter adapter; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_timeline); 37 | ButterKnife.bind(this); 38 | 39 | initView(); 40 | initData(); 41 | } 42 | 43 | private void initView() { 44 | recyclerView.setLayoutManager(new LinearLayoutManager(this)); 45 | recyclerView.setHasFixedSize(true); 46 | recyclerView.setNestedScrollingEnabled(false); 47 | recyclerView.setItemAnimator(new DefaultItemAnimator()); 48 | final TimeLineDecoration decoration = new TimeLineDecoration(this) 49 | .setLineColor(android.R.color.black) 50 | .setLineWidth(1) 51 | .setLeftDistance(93) 52 | .setTopDistance(10) 53 | .setBeginMarker(R.drawable.begin_up) 54 | .setEndMarker(R.drawable.up) 55 | .setCustomMarker(R.drawable.up) 56 | .setMarkerRadius(4) 57 | .setMarkerColor(R.color.colorAccent) 58 | .setCallback(new TimeLineDecoration.TimeLineAdapter() { 59 | 60 | @Override 61 | public int getTimeLineType(int position) { 62 | if (position == 0) return BEGIN; 63 | else if (position == adapter.getItemCount() - 1) return END; 64 | else if (adapter.getItem(position).isCustom) return CUSTOM; 65 | else return NORMAL; 66 | } 67 | }); 68 | recyclerView.addItemDecoration(decoration); 69 | 70 | adapter = new OrderAdapter(this, this); 71 | recyclerView.setAdapter(adapter); 72 | } 73 | 74 | private void initData() { 75 | final List analogs = new ArrayList<>(); 76 | 77 | LocationOrder locationOrder = new LocationOrder(); 78 | locationOrder.isHead = true; 79 | locationOrder.title = "待提货"; 80 | locationOrder.subTitle = "您的快件已由XXX代收,免费保管5天。取货码查询方式:物流详情页/短信/手机淘宝-消息-物流助手"; 81 | locationOrder.latitude = 00.00d; 82 | locationOrder.longitude = 00.000d; 83 | locationOrder.time = "2016-01-08\n10:20:19"; 84 | analogs.add(locationOrder); 85 | 86 | TextOrder textOrder0 = new TextOrder(); 87 | textOrder0.isCustom = true; 88 | textOrder0.title = "派送中"; 89 | textOrder0.subTitle = "【已签收,签收是8】"; 90 | textOrder0.time = "2016-01-07\n09:15:10"; 91 | analogs.add(textOrder0); 92 | 93 | TextOrder textOrder1 = new TextOrder(); 94 | textOrder1.title = "XX市【XX站】,【XXX】正在派件 电话:12345678910"; 95 | textOrder1.time = "2016-01-07\n07:20:45"; 96 | analogs.add(textOrder1); 97 | 98 | TextOrder textOrder2 = new TextOrder(); 99 | textOrder2.title = "XX市【XX转运中心】,正发往【XX站】"; 100 | textOrder2.time = "2016-01-06\n16:32:51"; 101 | analogs.add(textOrder2); 102 | 103 | TextOrder textOrder3 = new TextOrder(); 104 | textOrder3.title = "到XX市【XX转运中心】"; 105 | textOrder3.time = "2016-01-06\n13:56:03"; 106 | analogs.add(textOrder3); 107 | 108 | TextOrder textOrder4 = new TextOrder(); 109 | textOrder4.isCustom = true; 110 | textOrder4.title = "已揽件"; 111 | textOrder4.subTitle = "【XX】的收件员【XX】已收件"; 112 | textOrder4.time = "2016-01-05\n21:23:34"; 113 | analogs.add(textOrder4); 114 | 115 | TextOrder textOrder5 = new TextOrder(); 116 | textOrder5.isCustom = true; 117 | textOrder5.title = "已发货"; 118 | textOrder5.subTitle = "卖家已以发货"; 119 | textOrder5.time = "2016-01-05\n10:20:36"; 120 | analogs.add(textOrder5); 121 | 122 | InfoOrder infoOrder = new InfoOrder(); 123 | infoOrder.title = "已下单"; 124 | infoOrder.subTitle = "商品已经下单"; 125 | infoOrder.time = "2016-01-05\n09:10:59"; 126 | infoOrder.url = "www.xxx.com"; 127 | infoOrder.phone = "12345678901"; 128 | analogs.add(infoOrder); 129 | 130 | adapter.setItems(analogs); 131 | } 132 | 133 | @Override 134 | public void onLookClick(int position) { 135 | Toast.makeText(this, "查看订单", Toast.LENGTH_SHORT).show(); 136 | } 137 | 138 | @Override 139 | public void onCallClick(int position) { 140 | Toast.makeText(this, "联系卖家", Toast.LENGTH_SHORT).show(); 141 | } 142 | 143 | @Override 144 | public void onLocationClick(int position) { 145 | Toast.makeText(this, "查看位置", Toast.LENGTH_SHORT).show(); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/OrderAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.support.annotation.Nullable; 4 | 5 | import com.lin.poweradapter.DefaultAdapterDelegate; 6 | import com.lin.poweradapter.MultiAdapter; 7 | import com.lin.poweradapter.PowerViewHolder; 8 | 9 | /** 10 | * 11 | * Created by lin18 on 2017/8/23. 12 | */ 13 | 14 | public class OrderAdapter extends MultiAdapter { 15 | 16 | public OrderAdapter(@Nullable Object listener, @Nullable OnOrderClickListener clickListener) { 17 | super(listener); 18 | delegatesManager.addDelegate(new TextOrderDelegate()); 19 | delegatesManager.addDelegate(new InfoOrderDelegate(clickListener)); 20 | delegatesManager.addDelegate(new LocationOrderDelegate(clickListener)); 21 | delegatesManager.setFallbackDelegate(new DefaultAdapterDelegate()); 22 | } 23 | 24 | public interface OnOrderClickListener { 25 | void onLookClick(int position); 26 | 27 | void onCallClick(int position); 28 | 29 | void onLocationClick(int position); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/Picture.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | /** 4 | * Created by lin18 on 2017/8/23. 5 | */ 6 | 7 | public class Picture { 8 | 9 | public String thumb; 10 | public String original; 11 | 12 | public Picture(String thumb, String original) { 13 | this.thumb = thumb; 14 | this.original = original; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/RatingDelegate.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.support.annotation.LayoutRes; 4 | import android.support.annotation.NonNull; 5 | import android.view.ViewGroup; 6 | import android.widget.RatingBar; 7 | 8 | import com.lin.poweradapter.AdapterDelegate; 9 | import com.lin.poweradapter.PowerViewHolder; 10 | 11 | import java.util.List; 12 | 13 | import butterknife.BindView; 14 | 15 | import static com.lin.timeline.example.Trace.RATING_TYPE; 16 | 17 | /** 18 | * 19 | * Created by lin18 on 2017/8/23. 20 | */ 21 | 22 | public class RatingDelegate extends AdapterDelegate { 23 | 24 | 25 | public RatingDelegate() { 26 | } 27 | 28 | @Override 29 | protected boolean isForViewType(@NonNull Trace item, int position) { 30 | return RATING_TYPE.equals(item.type); 31 | } 32 | 33 | @NonNull 34 | @Override 35 | protected PowerViewHolder onCreateViewHolder(@NonNull ViewGroup parent) { 36 | return new ChildViewHolder(parent, R.layout.trace_rating); 37 | } 38 | 39 | @Override 40 | protected void onBindViewHolder(@NonNull final Trace item, final int position, @NonNull PowerViewHolder holder, @NonNull List payloads) { 41 | final ChildViewHolder vh = (ChildViewHolder) holder; 42 | vh.rating.setRating((Float) item.value); 43 | vh.rating.setIsIndicator(true); 44 | } 45 | 46 | static class ChildViewHolder extends BaseViewHolder { 47 | 48 | @BindView(R.id.rating) 49 | RatingBar rating; 50 | 51 | ChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 52 | super(parent, layoutResId); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/TextDelegate.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.LayoutRes; 5 | import android.support.annotation.NonNull; 6 | import android.support.v4.content.ContextCompat; 7 | import android.text.TextUtils; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import com.lin.poweradapter.AdapterDelegate; 12 | import com.lin.poweradapter.PowerViewHolder; 13 | 14 | import java.util.List; 15 | 16 | import butterknife.BindView; 17 | 18 | import static com.lin.timeline.example.Trace.TEXT_TYPE; 19 | 20 | 21 | /** 22 | * 23 | * Created by lin18 on 2017/8/23. 24 | */ 25 | 26 | public class TextDelegate extends AdapterDelegate { 27 | 28 | @Override 29 | protected boolean isForViewType(@NonNull Trace item, int position) { 30 | return TEXT_TYPE.equals(item.type); 31 | } 32 | 33 | @NonNull 34 | @Override 35 | protected PowerViewHolder onCreateViewHolder(@NonNull ViewGroup parent) { 36 | return new ChildViewHolder(parent, R.layout.trace_text); 37 | } 38 | 39 | @Override 40 | protected void onBindViewHolder(@NonNull Trace item, int position, @NonNull PowerViewHolder holder, @NonNull List payloads) { 41 | final Context context = holder.itemView.getContext(); 42 | final ChildViewHolder vh = (ChildViewHolder) holder; 43 | vh.textView.setTextColor(ContextCompat.getColor(context, item.isHead ? R.color.item_title_color : R.color.item_color)); 44 | vh.textView.setText(TextUtils.isEmpty(item.name) ? item.value.toString() : (item.name + ":" + item.value.toString())); 45 | } 46 | 47 | static class ChildViewHolder extends BaseViewHolder { 48 | 49 | @BindView(android.R.id.title) 50 | TextView textView; 51 | 52 | ChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 53 | super(parent, layoutResId); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/TextOrder.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | /** 4 | * Created by lin18 on 2017/8/23. 5 | */ 6 | 7 | public class TextOrder extends Order { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/TextOrderDelegate.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.support.annotation.LayoutRes; 4 | import android.support.annotation.NonNull; 5 | import android.view.ViewGroup; 6 | 7 | import com.lin.poweradapter.PowerViewHolder; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * 13 | * Created by lin18 on 2017/8/23. 14 | */ 15 | 16 | public class TextOrderDelegate extends AbsOrderDelegate { 17 | 18 | @Override 19 | protected boolean isForViewType(@NonNull Order item, int position) { 20 | return item instanceof TextOrder; 21 | } 22 | 23 | @NonNull 24 | @Override 25 | protected PowerViewHolder onCreateViewHolder(@NonNull ViewGroup parent) { 26 | return new ChildViewHolder(parent, R.layout.order_text); 27 | } 28 | 29 | @Override 30 | protected void onBindViewHolder(@NonNull Order item, int position, @NonNull PowerViewHolder holder, @NonNull List payloads) { 31 | super.onBindViewHolder(item, position, holder, payloads); 32 | } 33 | 34 | static class ChildViewHolder extends AbsChildViewHolder { 35 | 36 | ChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 37 | super(parent, layoutResId); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/TimeDelegate.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.LayoutRes; 5 | import android.support.annotation.NonNull; 6 | import android.support.v4.content.ContextCompat; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.lin.poweradapter.AdapterDelegate; 11 | import com.lin.poweradapter.PowerViewHolder; 12 | 13 | import java.util.List; 14 | 15 | import butterknife.BindView; 16 | 17 | import static com.lin.timeline.example.Trace.TIME_TYPE; 18 | 19 | /** 20 | * 21 | * Created by lin18 on 2017/8/23. 22 | */ 23 | 24 | public class TimeDelegate extends AdapterDelegate { 25 | 26 | @Override 27 | protected boolean isForViewType(@NonNull Trace item, int position) { 28 | return TIME_TYPE.equals(item.type); 29 | } 30 | 31 | @NonNull 32 | @Override 33 | protected PowerViewHolder onCreateViewHolder(@NonNull ViewGroup parent) { 34 | return new ChildViewHolder(parent, R.layout.trace_time); 35 | } 36 | 37 | @Override 38 | protected void onBindViewHolder(@NonNull Trace item, int position, @NonNull PowerViewHolder holder, @NonNull List payloads) { 39 | final Context context = holder.itemView.getContext(); 40 | final ChildViewHolder vh = (ChildViewHolder) holder; 41 | vh.textView.setTextColor(ContextCompat.getColor(context, item.isHead ? R.color.item_title_color : R.color.item_color)); 42 | vh.textView.setText(item.value.toString()); 43 | } 44 | 45 | static class ChildViewHolder extends BaseViewHolder { 46 | 47 | @BindView(android.R.id.title) 48 | TextView textView; 49 | 50 | ChildViewHolder(@NonNull ViewGroup parent, @LayoutRes int layoutResId) { 51 | super(parent, layoutResId); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/TimeLineActivity.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.graphics.Rect; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.DefaultItemAnimator; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | 11 | import com.lin.timeline.TimeLineDecoration; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | import butterknife.BindView; 17 | import butterknife.ButterKnife; 18 | 19 | import static com.lin.timeline.TimeLineDecoration.BEGIN; 20 | import static com.lin.timeline.TimeLineDecoration.END_FULL; 21 | import static com.lin.timeline.TimeLineDecoration.NORMAL; 22 | 23 | /** 24 | * Created by lin18 on 2017/8/23. 25 | */ 26 | public class TimeLineActivity extends AppCompatActivity { 27 | 28 | @BindView(R.id.recyclerView) 29 | RecyclerView recyclerView; 30 | 31 | AnalogAdapter adapter; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_timeline); 37 | ButterKnife.bind(this); 38 | 39 | initView(); 40 | initData(); 41 | } 42 | 43 | private void initView() { 44 | recyclerView.setLayoutManager(new LinearLayoutManager(this)); 45 | recyclerView.setHasFixedSize(true); 46 | recyclerView.setNestedScrollingEnabled(false); 47 | recyclerView.setItemAnimator(new DefaultItemAnimator()); 48 | final TimeLineDecoration decoration = new TimeLineDecoration(this) 49 | .setLineColor(android.R.color.black) 50 | .setLineWidth(1) 51 | .setLeftDistance(16) 52 | .setTopDistance(16) 53 | .setBeginMarker(R.drawable.begin_marker) 54 | .setMarkerRadius(4) 55 | .setMarkerColor(R.color.colorAccent) 56 | .setCallback(new TimeLineDecoration.TimeLineAdapter() { 57 | 58 | @Nullable 59 | @Override 60 | public Rect getRect(int position) { 61 | return new Rect(0, 16, 0, 16); 62 | } 63 | 64 | @Override 65 | public int getTimeLineType(int position) { 66 | if (position == 0) return BEGIN; 67 | else if (position == adapter.getItemCount() - 1) return END_FULL; 68 | else return NORMAL; 69 | } 70 | }); 71 | recyclerView.addItemDecoration(decoration); 72 | 73 | adapter = new AnalogAdapter(this); 74 | recyclerView.setAdapter(adapter); 75 | } 76 | 77 | private void initData() { 78 | final List analogs = new ArrayList<>(); 79 | 80 | Analog analog0 = new Analog(); 81 | analog0.isHead = true; 82 | analog0.text = "更新了日志"; 83 | analog0.time = "2016-01-08 10:20:10"; 84 | analogs.add(analog0); 85 | 86 | Analog analog1 = new Analog(); 87 | analog1.isHead = false; 88 | analog1.text = "上传了图片"; 89 | analog1.time = "2016-01-02 15:10:10"; 90 | analogs.add(analog1); 91 | 92 | Analog analog2 = new Analog(); 93 | analog2.isHead = false; 94 | analog2.text = "开通了空间"; 95 | analog2.time = "2016-01-01 10:10:10"; 96 | analogs.add(analog2); 97 | 98 | adapter.setItems(analogs); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/Trace.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.support.annotation.StringDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | /** 9 | * Created by lin18 on 2017/8/23. 10 | */ 11 | 12 | public class Trace { 13 | 14 | public boolean isHead; 15 | 16 | public String name; 17 | @TraceType 18 | public String type; 19 | public T value; 20 | 21 | 22 | 23 | public final static String TEXT_TYPE = "text"; 24 | public final static String MARKER_TYPE = "marker"; 25 | public final static String TIME_TYPE = "time"; 26 | public final static String IMG_TYPE = "img"; 27 | public final static String BUTTON_TYPE = "button"; 28 | public final static String RATING_TYPE = "rating"; 29 | 30 | @Retention(RetentionPolicy.SOURCE) 31 | @StringDef({ 32 | TEXT_TYPE, 33 | MARKER_TYPE, 34 | TIME_TYPE, 35 | IMG_TYPE, 36 | BUTTON_TYPE, 37 | RATING_TYPE 38 | }) 39 | public @interface TraceType { } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/TraceActivity.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.graphics.Rect; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.app.AppCompatDelegate; 7 | import android.support.v7.widget.DefaultItemAnimator; 8 | import android.support.v7.widget.GridLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | 11 | import com.google.gson.Gson; 12 | import com.lin.timeline.TimeLineDecoration; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | import butterknife.BindView; 18 | import butterknife.ButterKnife; 19 | 20 | import static com.lin.timeline.TimeLineDecoration.BEGIN; 21 | import static com.lin.timeline.TimeLineDecoration.END; 22 | import static com.lin.timeline.TimeLineDecoration.LINE; 23 | import static com.lin.timeline.TimeLineDecoration.NORMAL; 24 | import static com.lin.timeline.example.Trace.BUTTON_TYPE; 25 | import static com.lin.timeline.example.Trace.IMG_TYPE; 26 | import static com.lin.timeline.example.Trace.MARKER_TYPE; 27 | import static com.lin.timeline.example.Trace.RATING_TYPE; 28 | import static com.lin.timeline.example.Trace.TEXT_TYPE; 29 | import static com.lin.timeline.example.Trace.TIME_TYPE; 30 | 31 | /** 32 | * Created by lin18 on 2017/8/23. 33 | */ 34 | public class TraceActivity extends AppCompatActivity implements TraceAdapter.OnTraceClickListener { 35 | 36 | @BindView(R.id.recyclerView) 37 | RecyclerView recyclerView; 38 | 39 | TraceAdapter adapter; 40 | 41 | int itemWidth; 42 | int itemHeight; 43 | 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); 47 | super.onCreate(savedInstanceState); 48 | setContentView(R.layout.activity_trace); 49 | ButterKnife.bind(this); 50 | 51 | initView(); 52 | initData(); 53 | } 54 | 55 | private void initView() { 56 | itemWidth = (getResources().getDisplayMetrics().widthPixels 57 | - getResources().getDimensionPixelSize(R.dimen.recycler_trace_padding_left) 58 | - getResources().getDimensionPixelSize(R.dimen.recycler_trace_padding_right) 59 | - getResources().getDimensionPixelSize(R.dimen.trace_image_padding_right) * 4) / 2; 60 | itemHeight = getResources().getDimensionPixelSize(R.dimen.trace_image_height); 61 | 62 | final GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2); 63 | gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 64 | @Override 65 | public int getSpanSize(int position) { 66 | final Trace trace = adapter.getItem(position); 67 | if (trace.value instanceof Picture) 68 | return 1; 69 | return 2; 70 | } 71 | }); 72 | recyclerView.setLayoutManager(gridLayoutManager); 73 | recyclerView.setHasFixedSize(true); 74 | recyclerView.setNestedScrollingEnabled(false); 75 | recyclerView.setItemAnimator(new DefaultItemAnimator()); 76 | final TimeLineDecoration decoration = new TimeLineDecoration(this) 77 | .setDividerHeight(0.5f) 78 | .setDividerColor(R.color.divider) 79 | .setDividerPaddingLeft(53) 80 | .setLineColor(R.color.divider) 81 | .setLineWidth(1) 82 | .setLeftDistance(25) 83 | .setTopDistance(15) 84 | .setNormalMarker(R.drawable.marker) 85 | .setBeginMarker(R.drawable.begin_marker) 86 | .setEndMarker(R.drawable.marker) 87 | .setCallback(new TimeLineDecoration.TimeLineCallback() { 88 | @Override 89 | public boolean isShowDivider(int position) { 90 | return position != adapter.getItemCount() - 1 && TIME_TYPE.equals(adapter.getItem(position).type); 91 | } 92 | 93 | @Override 94 | public Rect getRect(int position) { 95 | return isShowDivider(position) ? new Rect(0, 0, 0, TimeLineDecoration.dp2px(TraceActivity.this, 0.5f)) 96 | : IMG_TYPE.equals(adapter.getItem(position).type) ? new Rect(4, 4, 4, 4) : null; 97 | } 98 | 99 | @Override 100 | public int getTimeLineType(int position) { 101 | if (position == 0) return BEGIN; 102 | final Trace trace = adapter.getItem(position); 103 | return MARKER_TYPE.equals(trace.type) ? (position == adapter.getItemCount() - 1 ? END : NORMAL) : LINE; 104 | } 105 | }); 106 | recyclerView.addItemDecoration(decoration); 107 | 108 | adapter = new TraceAdapter(itemWidth, itemHeight, this, this); 109 | recyclerView.setAdapter(adapter); 110 | } 111 | 112 | private void initData() { 113 | final List traces = new ArrayList<>(); 114 | 115 | Trace trace0 = new Trace<>(); 116 | trace0.isHead = true; 117 | trace0.type = MARKER_TYPE; 118 | trace0.value = "夺杯无可奈何花落去夺"; 119 | traces.add(trace0); 120 | 121 | Trace trace1 = new Trace<>(); 122 | trace1.isHead = true; 123 | trace1.type = TEXT_TYPE; 124 | trace1.value = "压下肝的广泛的豆腐干个"; 125 | traces.add(trace1); 126 | 127 | Trace trace2 = new Trace<>(); 128 | trace2.isHead = true; 129 | trace2.type = TEXT_TYPE; 130 | trace2.name = "士大夫似的士大夫阿三发"; 131 | trace2.value = "法国东方士士大夫"; 132 | traces.add(trace2); 133 | 134 | Trace trace3 = new Trace<>(); 135 | trace3.isHead = true; 136 | trace3.type = BUTTON_TYPE; 137 | trace3.name = "按钮"; 138 | traces.add(trace3); 139 | 140 | Trace trace4 = new Trace<>(); 141 | trace4.isHead = true; 142 | trace4.type = TIME_TYPE; 143 | trace4.value = "2017-06-23 11:22:22"; 144 | traces.add(trace4); 145 | 146 | Trace trace5 = new Trace<>(); 147 | trace5.type = MARKER_TYPE; 148 | trace5.value = "和计划工具钢"; 149 | traces.add(trace5); 150 | 151 | Trace pictureTrace0 = new Trace<>(); 152 | pictureTrace0.type = IMG_TYPE; 153 | pictureTrace0.value = new Picture("https://unsplash.it/160?image=5", "https://unsplash.it/750?image=5"); 154 | traces.add(pictureTrace0); 155 | 156 | Trace pictureTrace1 = new Trace<>(); 157 | pictureTrace1.type = IMG_TYPE; 158 | pictureTrace1.value = new Picture("https://unsplash.it/160?image=360", "https://unsplash.it/750?image=360"); 159 | traces.add(pictureTrace1); 160 | 161 | Trace pictureTrace2 = new Trace<>(); 162 | pictureTrace2.type = IMG_TYPE; 163 | pictureTrace2.value = new Picture("https://unsplash.it/160?image=356", "https://unsplash.it/750?image=356"); 164 | traces.add(pictureTrace2); 165 | 166 | Trace pictureTrace3 = new Trace<>(); 167 | pictureTrace3.type = IMG_TYPE; 168 | pictureTrace3.value = new Picture("https://unsplash.it/160?image=351", "https://unsplash.it/750?image=351"); 169 | traces.add(pictureTrace3); 170 | 171 | Trace trace6 = new Trace<>(); 172 | trace6.type = TIME_TYPE; 173 | trace6.value = "2017-06-23 11:43:54"; 174 | traces.add(trace6); 175 | 176 | Trace trace7 = new Trace<>(); 177 | trace7.type = MARKER_TYPE; 178 | trace7.value = "的非官方的接口和夫似的"; 179 | traces.add(trace7); 180 | 181 | Trace trace8 = new Trace<>(); 182 | trace8.type = TEXT_TYPE; 183 | trace8.name = "萨芬健康,发的"; 184 | trace8.value = "将货款麻烦"; 185 | traces.add(trace8); 186 | 187 | Trace trace9 = new Trace<>(); 188 | trace9.type = TIME_TYPE; 189 | trace9.value = "2017-06-23 11:42:37"; 190 | traces.add(trace9); 191 | 192 | Trace trace10 = new Trace<>(); 193 | trace10.type = MARKER_TYPE; 194 | trace10.value = "犯嘀咕水电费"; 195 | traces.add(trace10); 196 | 197 | Trace pictureTrace4 = new Trace<>(); 198 | pictureTrace4.type = IMG_TYPE; 199 | pictureTrace4.value = new Picture("https://unsplash.it/160?image=361", "https://unsplash.it/750?image=361"); 200 | traces.add(pictureTrace4); 201 | 202 | Trace trace11 = new Trace<>(); 203 | trace11.type = TIME_TYPE; 204 | trace11.value = "2017-06-23 11:41:51"; 205 | traces.add(trace11); 206 | 207 | Trace trace12 = new Trace<>(); 208 | trace12.type = MARKER_TYPE; 209 | trace12.value = "朋友提供梵"; 210 | traces.add(trace12); 211 | 212 | Trace ratingTrace = new Trace<>(); 213 | ratingTrace.type = RATING_TYPE; 214 | ratingTrace.value = 4.5f; 215 | traces.add(ratingTrace); 216 | 217 | Trace trace13 = new Trace<>(); 218 | trace13.type = TIME_TYPE; 219 | trace13.value = "2017-06-23 11:40:35"; 220 | traces.add(trace13); 221 | 222 | Trace trace14 = new Trace<>(); 223 | trace14.type = MARKER_TYPE; 224 | trace14.value = "问的非官方"; 225 | traces.add(trace14); 226 | 227 | Trace trace15 = new Trace<>(); 228 | trace15.type = TEXT_TYPE; 229 | trace15.value = "厂校挂钩"; 230 | traces.add(trace15); 231 | 232 | Trace trace16 = new Trace<>(); 233 | trace16.type = TIME_TYPE; 234 | trace16.value = "2017-06-22 09:12:54"; 235 | traces.add(trace16); 236 | 237 | // String data = new Gson().toJson(traces); 238 | 239 | adapter.setItems(traces); 240 | } 241 | 242 | @Override 243 | public void onImageClick(int position) { 244 | 245 | } 246 | 247 | @Override 248 | public void onButtonClick(int position) { 249 | 250 | } 251 | 252 | } 253 | -------------------------------------------------------------------------------- /app/src/main/java/com/lin/timeline/example/TraceAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lin.timeline.example; 2 | 3 | import android.support.annotation.Nullable; 4 | 5 | import com.lin.poweradapter.DefaultAdapterDelegate; 6 | import com.lin.poweradapter.MultiAdapter; 7 | import com.lin.poweradapter.PowerViewHolder; 8 | 9 | /** 10 | * 11 | * Created by lin18 on 2017/8/23. 12 | */ 13 | 14 | public class TraceAdapter extends MultiAdapter { 15 | 16 | public TraceAdapter(int width, int height, 17 | @Nullable Object listener, @Nullable OnTraceClickListener clickListener) { 18 | super(listener); 19 | delegatesManager.addDelegate(new MarkerDelegate()); 20 | delegatesManager.addDelegate(new TextDelegate()); 21 | delegatesManager.addDelegate(new TimeDelegate()); 22 | delegatesManager.addDelegate(new ImageDelegate(width, height, clickListener)); 23 | delegatesManager.addDelegate(new ButtonDelegate(clickListener)); 24 | delegatesManager.addDelegate(new RatingDelegate()); 25 | delegatesManager.setFallbackDelegate(new DefaultAdapterDelegate()); 26 | } 27 | 28 | public interface OnTraceClickListener { 29 | void onImageClick(int position); 30 | 31 | void onButtonClick(int position); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/begin_marker.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/begin_up.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/marker.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/up.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/vector_default_image.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 |