├── README.md
└── Timeline
├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── lvr
│ │ └── timeline
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── lvr
│ │ │ └── timeline
│ │ │ ├── adapter
│ │ │ └── TimelineAdapter.java
│ │ │ ├── anims
│ │ │ ├── AlphaInAnimationAdapter.java
│ │ │ ├── AnimationAdapter.java
│ │ │ ├── BaseItemAnimator.java
│ │ │ ├── LandingAnimator.java
│ │ │ ├── ScaleInAnimationAdapter.java
│ │ │ └── ViewHelper.java
│ │ │ ├── app
│ │ │ ├── AppApplication.java
│ │ │ ├── AppConstantValue.java
│ │ │ └── AppManager.java
│ │ │ ├── base
│ │ │ ├── BaseActivity.java
│ │ │ ├── BaseApplication.java
│ │ │ ├── BaseFragment.java
│ │ │ └── BaseFragmentAdapter.java
│ │ │ ├── bean
│ │ │ └── TimeInfo.java
│ │ │ ├── home
│ │ │ ├── fragment
│ │ │ │ ├── CountDownFragment.java
│ │ │ │ ├── TodayFragment.java
│ │ │ │ └── YesterdayFragment.java
│ │ │ └── ui
│ │ │ │ ├── EditActivity.java
│ │ │ │ └── MainActivity.java
│ │ │ ├── utils
│ │ │ ├── ACache.java
│ │ │ ├── CollectionUtils.java
│ │ │ ├── DisplayUtil.java
│ │ │ ├── GlideRoundTransformUtil.java
│ │ │ ├── ImageLoaderUtils.java
│ │ │ ├── RealmOperationHelper.java
│ │ │ ├── StatusBarSetting.java
│ │ │ ├── TUtil.java
│ │ │ └── TimeUtil.java
│ │ │ └── widget
│ │ │ ├── CircleImageView.java
│ │ │ ├── CircleTextView.java
│ │ │ ├── ItemDragHelperCallback.java
│ │ │ └── StatusBarView.java
│ └── res
│ │ ├── drawable-xxhdpi
│ │ ├── about.png
│ │ ├── calender.png
│ │ ├── change.png
│ │ ├── fb_plus.png
│ │ ├── habbit.png
│ │ ├── ic_empty_picture.png
│ │ ├── ic_image_loading.png
│ │ ├── ic_search_menu.png
│ │ ├── item_delete.png
│ │ ├── mn_back.png
│ │ ├── mn_edit.png
│ │ ├── mn_right.png
│ │ ├── moddy.png
│ │ ├── nav_header.jpg
│ │ ├── nav_photo.jpg
│ │ ├── out.png
│ │ ├── progress.png
│ │ ├── select_time_online.png
│ │ ├── select_today.png
│ │ ├── select_yesterday.png
│ │ ├── sorry_hint.png
│ │ ├── thing.png
│ │ ├── time_online.png
│ │ ├── today.png
│ │ ├── toux2.png
│ │ └── yesterday.png
│ │ ├── drawable
│ │ ├── select_button_countdown.xml
│ │ ├── select_button_today.xml
│ │ └── select_button_yesterday.xml
│ │ ├── layout
│ │ ├── activity_edit.xml
│ │ ├── activity_home.xml
│ │ ├── app_bar.xml
│ │ ├── dialog_view.xml
│ │ ├── fragment_countdown.xml
│ │ ├── fragment_today.xml
│ │ ├── fragment_yesterday.xml
│ │ ├── item_line.xml
│ │ └── view_nav.xml
│ │ ├── menu
│ │ ├── menu_nav.xml
│ │ └── menu_toolabr.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── time.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ ├── dimens.xml
│ │ └── ids.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── lvr
│ └── timeline
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/README.md:
--------------------------------------------------------------------------------
1 | # TimeLine
2 | 一款时间管理软件,可以记录每天需要完成的事项,并进行监督执行。同时可以对每天的时间进行管理分析。
3 |
--------------------------------------------------------------------------------
/Timeline/.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 |
--------------------------------------------------------------------------------
/Timeline/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Timeline/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Timeline/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Timeline/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/Timeline/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Timeline/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Timeline/.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 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 1.8
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Timeline/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Timeline/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Timeline/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Timeline/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'com.neenbedankt.android-apt'
3 | apply plugin: 'realm-android'
4 | android {
5 | compileSdkVersion 25
6 | buildToolsVersion "25.0.2"
7 | defaultConfig {
8 | applicationId "com.lvr.timeline"
9 | minSdkVersion 15
10 | targetSdkVersion 25
11 | versionCode 1
12 | versionName "1.0"
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | compile fileTree(include: ['*.jar'], dir: 'libs')
25 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
26 | exclude group: 'com.android.support', module: 'support-annotations'
27 | })
28 | compile 'com.android.support:appcompat-v7:25.1.0'
29 | testCompile 'junit:junit:4.12'
30 | compile 'com.android.support:design:25.1.0'
31 | compile 'com.android.support:cardview-v7:25.1.0'
32 | compile 'com.android.support:recyclerview-v7:25.1.0'
33 | //视图绑定 butterknife
34 | compile 'com.jakewharton:butterknife:8.4.0'
35 | apt 'com.jakewharton:butterknife-compiler:8.4.0'
36 | compile 'com.github.bumptech.glide:glide:3.7.0'
37 | compile 'de.greenrobot:eventbus:3.0.0-beta1'
38 | compile 'com.borax12.materialdaterangepicker:library:1.9'
39 | //侧滑删除Item
40 | compile 'com.github.mcxtzhang:SwipeDelMenuLayout:V1.1.0'
41 | }
42 |
--------------------------------------------------------------------------------
/Timeline/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in E:\AndroidStudio\SDKinstallpackage/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 |
--------------------------------------------------------------------------------
/Timeline/app/src/androidTest/java/com/lvr/timeline/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.lvr.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 | * 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.lvr.timeline", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/adapter/TimelineAdapter.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.adapter;
2 |
3 | import android.content.Context;
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.ImageButton;
10 | import android.widget.RelativeLayout;
11 | import android.widget.TextView;
12 | import android.widget.Toast;
13 |
14 | import com.lvr.timeline.R;
15 | import com.lvr.timeline.app.AppApplication;
16 | import com.lvr.timeline.bean.TimeInfo;
17 | import com.lvr.timeline.utils.RealmOperationHelper;
18 | import com.mcxtzhang.swipemenulib.SwipeMenuLayout;
19 |
20 | import java.text.SimpleDateFormat;
21 | import java.util.Date;
22 | import java.util.List;
23 |
24 |
25 | public class TimelineAdapter extends RecyclerView.Adapter {
26 | private List list;
27 | private Context context;
28 | private OnItemClickListener mOnItemClickListener;
29 | private int[] colors;
30 | public TimelineAdapter(Context context, List list) {
31 | this.list=list;
32 | this.context=context;
33 | this.colors = new int[]{context.getResources().getColor(R.color.color1), context.getResources().getColor(R.color.color2), context.getResources().getColor(R.color.color3)
34 | , context.getResources().getColor(R.color.color4), context.getResources().getColor(R.color.color5), context.getResources().getColor(R.color.color6), context.getResources().getColor(R.color.color7)
35 | , context.getResources().getColor(R.color.color8), context.getResources().getColor(R.color.color9), context.getResources().getColor(R.color.color10), context.getResources().getColor(R.color.color11)
36 | , context.getResources().getColor(R.color.color12), context.getResources().getColor(R.color.color13), context.getResources().getColor(R.color.color14), context.getResources().getColor(R.color.color15)
37 | , context.getResources().getColor(R.color.color16), context.getResources().getColor(R.color.color17), context.getResources().getColor(R.color.color18), context.getResources().getColor(R.color.color19)
38 | , context.getResources().getColor(R.color.color20), context.getResources().getColor(R.color.color21), context.getResources().getColor(R.color.color22), context.getResources().getColor(R.color.color23)
39 | , context.getResources().getColor(R.color.color24)};
40 |
41 | }
42 | @Override
43 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
44 | View v = LayoutInflater.from(parent.getContext())
45 | .inflate(R.layout.item_line, parent,false);
46 | return new ViewHolder(v);
47 | }
48 |
49 | @Override
50 | public void onBindViewHolder(final ViewHolder holder, final int position) {
51 | TimeInfo info = list.get(position);
52 | holder.yMDText.setText(info.getYmD());
53 | holder.titleText.setText(info.getTitle());
54 | holder.contentText.setText(info.getContent());
55 | // TODO: 2017/4/17 有问题 创建该条目的时间会出错
56 | SimpleDateFormat format = new SimpleDateFormat("HH:mm");
57 | String allTime = format.format(new Date());
58 | holder.timeText.setText(allTime);
59 | String[] split = info.getAddTime().split("-");
60 | holder.hourText.setText(split[0]);
61 | String[] hours = split[0].split(":");
62 | System.out.println(hours);
63 | int hour = Integer.parseInt(hours[0]);
64 | System.out.println(hour);
65 | int color = colors[hour-1];
66 | holder.hourText.setBackgroundColor(color);
67 | holder.hourText.setTextColor(context.getResources().getColor(R.color.white));
68 | holder.rl_root.setOnClickListener(new View.OnClickListener() {
69 | @Override
70 | public void onClick(View v) {
71 | mOnItemClickListener.onItemClick(list.get(position),position);
72 | }
73 | });
74 |
75 | ((SwipeMenuLayout) holder.itemView).setIos(false).setLeftSwipe(true);
76 | holder.deleteIButton.setOnClickListener(new View.OnClickListener() {
77 | @Override
78 | public void onClick(View v) {
79 | int curPosition = holder.getPosition();
80 | System.out.println("当前位置:"+curPosition);
81 | list.remove(curPosition);
82 | notifyItemRemoved(curPosition);
83 | RealmOperationHelper.getInstance(AppApplication.REALM_INSTANCE).deleteElement(TimeInfo.class,curPosition);
84 |
85 | }
86 | });
87 | holder.completeButton.setOnClickListener(new View.OnClickListener() {
88 | @Override
89 | public void onClick(View v) {
90 | Toast.makeText(context,"完成了",Toast.LENGTH_SHORT).show();
91 | }
92 | });
93 | }
94 |
95 | @Override
96 | public int getItemCount() {
97 | return list.size();
98 | }
99 |
100 |
101 |
102 |
103 | public static class ViewHolder extends RecyclerView.ViewHolder {
104 | private TextView hourText;
105 | private RelativeLayout rl_root;
106 | private TextView yMDText;
107 | private TextView titleText;
108 | private TextView timeText;
109 | private TextView contentText;
110 | private ImageButton deleteIButton;
111 | private Button completeButton;
112 | public ViewHolder(View v) {
113 | super(v);
114 | titleText = (TextView) v.findViewById(R.id.tv_title);
115 | yMDText = (TextView) v.findViewById(R.id.tv_yMD);
116 | timeText = (TextView) v.findViewById(R.id.tv_time);
117 | contentText = (TextView) v.findViewById(R.id.tv_content);
118 | rl_root = (RelativeLayout) v.findViewById(R.id.rl_root);
119 | hourText = (TextView) v.findViewById(R.id.tv_hour);
120 | deleteIButton = (ImageButton) v.findViewById(R.id.ib_delete);
121 | completeButton = (Button) v.findViewById(R.id.btn_complete);
122 | }
123 | }
124 | public interface OnItemClickListener{
125 | void onItemClick(TimeInfo mInfo,int position);
126 | }
127 | public void setOnItemClickListener(OnItemClickListener onItemClickListener){
128 | this.mOnItemClickListener = onItemClickListener;
129 | }
130 |
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/anims/AlphaInAnimationAdapter.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.anims;
2 |
3 | import android.animation.Animator;
4 | import android.animation.ObjectAnimator;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.View;
7 |
8 | /**
9 | * Copyright (C) 2017 Wasabeef
10 | *
11 | * Licensed under the Apache License, Version 2.0 (the "License");
12 | * you may not use this file except in compliance with the License.
13 | * You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | */
23 |
24 | public class AlphaInAnimationAdapter extends AnimationAdapter {
25 |
26 | private static final float DEFAULT_ALPHA_FROM = 0f;
27 | private final float mFrom;
28 |
29 | public AlphaInAnimationAdapter(RecyclerView.Adapter adapter) {
30 | this(adapter, DEFAULT_ALPHA_FROM);
31 | }
32 |
33 | public AlphaInAnimationAdapter(RecyclerView.Adapter adapter, float from) {
34 | super(adapter);
35 | mFrom = from;
36 | }
37 |
38 | @Override protected Animator[] getAnimators(View view) {
39 | return new Animator[] { ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f) };
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/anims/AnimationAdapter.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.anims;
2 |
3 | import android.animation.Animator;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.view.animation.Interpolator;
8 | import android.view.animation.LinearInterpolator;
9 |
10 | /**
11 | * Copyright (C) 2017 Wasabeef
12 | *
13 | * Licensed under the Apache License, Version 2.0 (the "License");
14 | * you may not use this file except in compliance with the License.
15 | * You may obtain a copy of the License at
16 | *
17 | * http://www.apache.org/licenses/LICENSE-2.0
18 | *
19 | * Unless required by applicable law or agreed to in writing, software
20 | * distributed under the License is distributed on an "AS IS" BASIS,
21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 | * See the License for the specific language governing permissions and
23 | * limitations under the License.
24 | */
25 | public abstract class AnimationAdapter extends RecyclerView.Adapter {
26 |
27 | private RecyclerView.Adapter mAdapter;
28 | private int mDuration = 300;
29 | private Interpolator mInterpolator = new LinearInterpolator();
30 | private int mLastPosition = -1;
31 |
32 | private boolean isFirstOnly = true;
33 |
34 | public AnimationAdapter(RecyclerView.Adapter adapter) {
35 | mAdapter = adapter;
36 | }
37 |
38 | @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
39 | return mAdapter.onCreateViewHolder(parent, viewType);
40 | }
41 |
42 | @Override public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
43 | super.registerAdapterDataObserver(observer);
44 | mAdapter.registerAdapterDataObserver(observer);
45 | }
46 |
47 | @Override public void unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
48 | super.unregisterAdapterDataObserver(observer);
49 | mAdapter.unregisterAdapterDataObserver(observer);
50 | }
51 |
52 | @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
53 | mAdapter.onBindViewHolder(holder, position);
54 |
55 | int adapterPosition = holder.getAdapterPosition();
56 | if (!isFirstOnly || adapterPosition > mLastPosition) {
57 | for (Animator anim : getAnimators(holder.itemView)) {
58 | anim.setDuration(mDuration).start();
59 | anim.setInterpolator(mInterpolator);
60 | }
61 | mLastPosition = adapterPosition;
62 | } else {
63 | ViewHelper.clear(holder.itemView);
64 | }
65 | }
66 |
67 | @Override public void onViewRecycled(RecyclerView.ViewHolder holder) {
68 | mAdapter.onViewRecycled(holder);
69 | super.onViewRecycled(holder);
70 | }
71 |
72 | @Override public int getItemCount() {
73 | return mAdapter.getItemCount();
74 | }
75 |
76 | public void setDuration(int duration) {
77 | mDuration = duration;
78 | }
79 |
80 | public void setInterpolator(Interpolator interpolator) {
81 | mInterpolator = interpolator;
82 | }
83 |
84 | public void setStartPosition(int start) {
85 | mLastPosition = start;
86 | }
87 |
88 | protected abstract Animator[] getAnimators(View view);
89 |
90 | public void setFirstOnly(boolean firstOnly) {
91 | isFirstOnly = firstOnly;
92 | }
93 |
94 | @Override public int getItemViewType(int position) {
95 | return mAdapter.getItemViewType(position);
96 | }
97 |
98 | public RecyclerView.Adapter getWrappedAdapter() {
99 | return mAdapter;
100 | }
101 |
102 | @Override public long getItemId(int position) {
103 | return mAdapter.getItemId(position);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/anims/BaseItemAnimator.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.anims;
2 | /*
3 | * Copyright (C) 2017 Wasabeef
4 | * Copyright (C) 2014 The Android Open Source Project
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | */
19 |
20 | import android.support.v4.view.ViewCompat;
21 | import android.support.v4.view.ViewPropertyAnimatorCompat;
22 | import android.support.v4.view.ViewPropertyAnimatorListener;
23 | import android.support.v7.widget.RecyclerView.ViewHolder;
24 | import android.support.v7.widget.SimpleItemAnimator;
25 | import android.view.View;
26 | import android.view.animation.DecelerateInterpolator;
27 | import android.view.animation.Interpolator;
28 |
29 | import java.util.ArrayList;
30 | import java.util.List;
31 |
32 | public abstract class BaseItemAnimator extends SimpleItemAnimator {
33 |
34 | private static final boolean DEBUG = false;
35 |
36 | private ArrayList mPendingRemovals = new ArrayList<>();
37 | private ArrayList mPendingAdditions = new ArrayList<>();
38 | private ArrayList mPendingMoves = new ArrayList<>();
39 | private ArrayList mPendingChanges = new ArrayList<>();
40 |
41 | private ArrayList> mAdditionsList = new ArrayList<>();
42 | private ArrayList> mMovesList = new ArrayList<>();
43 | private ArrayList> mChangesList = new ArrayList<>();
44 |
45 | protected ArrayList mAddAnimations = new ArrayList<>();
46 | private ArrayList mMoveAnimations = new ArrayList<>();
47 | protected ArrayList mRemoveAnimations = new ArrayList<>();
48 | private ArrayList mChangeAnimations = new ArrayList<>();
49 |
50 | protected Interpolator mInterpolator = new DecelerateInterpolator();
51 |
52 | private static class MoveInfo {
53 |
54 | public ViewHolder holder;
55 | public int fromX, fromY, toX, toY;
56 |
57 | private MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
58 | this.holder = holder;
59 | this.fromX = fromX;
60 | this.fromY = fromY;
61 | this.toX = toX;
62 | this.toY = toY;
63 | }
64 | }
65 |
66 | private static class ChangeInfo {
67 |
68 | public ViewHolder oldHolder, newHolder;
69 | public int fromX, fromY, toX, toY;
70 |
71 | private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) {
72 | this.oldHolder = oldHolder;
73 | this.newHolder = newHolder;
74 | }
75 |
76 | private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX,
77 | int toY) {
78 | this(oldHolder, newHolder);
79 | this.fromX = fromX;
80 | this.fromY = fromY;
81 | this.toX = toX;
82 | this.toY = toY;
83 | }
84 |
85 | @Override public String toString() {
86 | return "ChangeInfo{" +
87 | "oldHolder=" + oldHolder +
88 | ", newHolder=" + newHolder +
89 | ", fromX=" + fromX +
90 | ", fromY=" + fromY +
91 | ", toX=" + toX +
92 | ", toY=" + toY +
93 | '}';
94 | }
95 | }
96 |
97 | public BaseItemAnimator() {
98 | super();
99 | setSupportsChangeAnimations(false);
100 | }
101 |
102 | public void setInterpolator(Interpolator mInterpolator) {
103 | this.mInterpolator = mInterpolator;
104 | }
105 |
106 | @Override public void runPendingAnimations() {
107 | boolean removalsPending = !mPendingRemovals.isEmpty();
108 | boolean movesPending = !mPendingMoves.isEmpty();
109 | boolean changesPending = !mPendingChanges.isEmpty();
110 | boolean additionsPending = !mPendingAdditions.isEmpty();
111 | if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
112 | // nothing to animate
113 | return;
114 | }
115 | // First, remove stuff
116 | for (ViewHolder holder : mPendingRemovals) {
117 | doAnimateRemove(holder);
118 | }
119 | mPendingRemovals.clear();
120 | // Next, move stuff
121 | if (movesPending) {
122 | final ArrayList moves = new ArrayList();
123 | moves.addAll(mPendingMoves);
124 | mMovesList.add(moves);
125 | mPendingMoves.clear();
126 | Runnable mover = new Runnable() {
127 | @Override public void run() {
128 | boolean removed = mMovesList.remove(moves);
129 | if (!removed) {
130 | // already canceled
131 | return;
132 | }
133 | for (MoveInfo moveInfo : moves) {
134 | animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX,
135 | moveInfo.toY);
136 | }
137 | moves.clear();
138 | }
139 | };
140 | if (removalsPending) {
141 | View view = moves.get(0).holder.itemView;
142 | ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration());
143 | } else {
144 | mover.run();
145 | }
146 | }
147 | // Next, change stuff, to run in parallel with move animations
148 | if (changesPending) {
149 | final ArrayList changes = new ArrayList();
150 | changes.addAll(mPendingChanges);
151 | mChangesList.add(changes);
152 | mPendingChanges.clear();
153 | Runnable changer = new Runnable() {
154 | @Override public void run() {
155 | boolean removed = mChangesList.remove(changes);
156 | if (!removed) {
157 | // already canceled
158 | return;
159 | }
160 | for (ChangeInfo change : changes) {
161 | animateChangeImpl(change);
162 | }
163 | changes.clear();
164 | }
165 | };
166 | if (removalsPending) {
167 | ViewHolder holder = changes.get(0).oldHolder;
168 | ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration());
169 | } else {
170 | changer.run();
171 | }
172 | }
173 | // Next, add stuff
174 | if (additionsPending) {
175 | final ArrayList additions = new ArrayList();
176 | additions.addAll(mPendingAdditions);
177 | mAdditionsList.add(additions);
178 | mPendingAdditions.clear();
179 | Runnable adder = new Runnable() {
180 | public void run() {
181 | boolean removed = mAdditionsList.remove(additions);
182 | if (!removed) {
183 | // already canceled
184 | return;
185 | }
186 | for (ViewHolder holder : additions) {
187 | doAnimateAdd(holder);
188 | }
189 | additions.clear();
190 | }
191 | };
192 | if (removalsPending || movesPending || changesPending) {
193 | long removeDuration = removalsPending ? getRemoveDuration() : 0;
194 | long moveDuration = movesPending ? getMoveDuration() : 0;
195 | long changeDuration = changesPending ? getChangeDuration() : 0;
196 | long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
197 | View view = additions.get(0).itemView;
198 | ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
199 | } else {
200 | adder.run();
201 | }
202 | }
203 | }
204 |
205 | protected void preAnimateRemoveImpl(final ViewHolder holder) {
206 | }
207 |
208 | protected void preAnimateAddImpl(final ViewHolder holder) {
209 | }
210 |
211 | protected abstract void animateRemoveImpl(final ViewHolder holder);
212 |
213 | protected abstract void animateAddImpl(final ViewHolder holder);
214 |
215 | private void preAnimateRemove(final ViewHolder holder) {
216 | ViewHelper.clear(holder.itemView);
217 |
218 | if (holder instanceof AnimateViewHolder) {
219 | ((AnimateViewHolder) holder).preAnimateRemoveImpl(holder);
220 | } else {
221 | preAnimateRemoveImpl(holder);
222 | }
223 | }
224 |
225 | private void preAnimateAdd(final ViewHolder holder) {
226 | ViewHelper.clear(holder.itemView);
227 |
228 | if (holder instanceof AnimateViewHolder) {
229 | ((AnimateViewHolder) holder).preAnimateAddImpl(holder);
230 | } else {
231 | preAnimateAddImpl(holder);
232 | }
233 | }
234 |
235 | private void doAnimateRemove(final ViewHolder holder) {
236 | if (holder instanceof AnimateViewHolder) {
237 | ((AnimateViewHolder) holder).animateRemoveImpl(holder, new DefaultRemoveVpaListener(holder));
238 | } else {
239 | animateRemoveImpl(holder);
240 | }
241 |
242 | mRemoveAnimations.add(holder);
243 | }
244 |
245 | private void doAnimateAdd(final ViewHolder holder) {
246 | if (holder instanceof AnimateViewHolder) {
247 | ((AnimateViewHolder) holder).animateAddImpl(holder, new DefaultAddVpaListener(holder));
248 | } else {
249 | animateAddImpl(holder);
250 | }
251 |
252 | mAddAnimations.add(holder);
253 | }
254 |
255 | @Override public boolean animateRemove(final ViewHolder holder) {
256 | endAnimation(holder);
257 | preAnimateRemove(holder);
258 | mPendingRemovals.add(holder);
259 | return true;
260 | }
261 |
262 | protected long getRemoveDelay(final ViewHolder holder) {
263 | return Math.abs(holder.getOldPosition() * getRemoveDuration() / 4);
264 | }
265 |
266 | @Override public boolean animateAdd(final ViewHolder holder) {
267 | endAnimation(holder);
268 | preAnimateAdd(holder);
269 | mPendingAdditions.add(holder);
270 | return true;
271 | }
272 |
273 | protected long getAddDelay(final ViewHolder holder) {
274 | return Math.abs(holder.getAdapterPosition() * getAddDuration() / 4);
275 | }
276 |
277 | @Override
278 | public boolean animateMove(final ViewHolder holder, int fromX, int fromY, int toX, int toY) {
279 | final View view = holder.itemView;
280 | fromX += ViewCompat.getTranslationX(holder.itemView);
281 | fromY += ViewCompat.getTranslationY(holder.itemView);
282 | endAnimation(holder);
283 | int deltaX = toX - fromX;
284 | int deltaY = toY - fromY;
285 | if (deltaX == 0 && deltaY == 0) {
286 | dispatchMoveFinished(holder);
287 | return false;
288 | }
289 | if (deltaX != 0) {
290 | ViewCompat.setTranslationX(view, -deltaX);
291 | }
292 | if (deltaY != 0) {
293 | ViewCompat.setTranslationY(view, -deltaY);
294 | }
295 | mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
296 | return true;
297 | }
298 |
299 | private void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) {
300 | final View view = holder.itemView;
301 | final int deltaX = toX - fromX;
302 | final int deltaY = toY - fromY;
303 | if (deltaX != 0) {
304 | ViewCompat.animate(view).translationX(0);
305 | }
306 | if (deltaY != 0) {
307 | ViewCompat.animate(view).translationY(0);
308 | }
309 | // TODO: make EndActions end listeners instead, since end actions aren't called when
310 | // vpas are canceled (and can't end them. why?)
311 | // need listener functionality in VPACompat for this. Ick.
312 | mMoveAnimations.add(holder);
313 | final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
314 | animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() {
315 | @Override public void onAnimationStart(View view) {
316 | dispatchMoveStarting(holder);
317 | }
318 |
319 | @Override public void onAnimationCancel(View view) {
320 | if (deltaX != 0) {
321 | ViewCompat.setTranslationX(view, 0);
322 | }
323 | if (deltaY != 0) {
324 | ViewCompat.setTranslationY(view, 0);
325 | }
326 | }
327 |
328 | @Override public void onAnimationEnd(View view) {
329 | animation.setListener(null);
330 | dispatchMoveFinished(holder);
331 | mMoveAnimations.remove(holder);
332 | dispatchFinishedWhenDone();
333 | }
334 | }).start();
335 | }
336 |
337 | @Override
338 | public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY,
339 | int toX, int toY) {
340 | final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
341 | final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
342 | final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
343 | endAnimation(oldHolder);
344 | int deltaX = (int) (toX - fromX - prevTranslationX);
345 | int deltaY = (int) (toY - fromY - prevTranslationY);
346 | // recover prev translation state after ending animation
347 | ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
348 | ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
349 | ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
350 | if (newHolder != null && newHolder.itemView != null) {
351 | // carry over translation values
352 | endAnimation(newHolder);
353 | ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
354 | ViewCompat.setTranslationY(newHolder.itemView, -deltaY);
355 | ViewCompat.setAlpha(newHolder.itemView, 0);
356 | }
357 | mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
358 | return true;
359 | }
360 |
361 | private void animateChangeImpl(final ChangeInfo changeInfo) {
362 | final ViewHolder holder = changeInfo.oldHolder;
363 | final View view = holder == null ? null : holder.itemView;
364 | final ViewHolder newHolder = changeInfo.newHolder;
365 | final View newView = newHolder != null ? newHolder.itemView : null;
366 | if (view != null) {
367 | mChangeAnimations.add(changeInfo.oldHolder);
368 | final ViewPropertyAnimatorCompat oldViewAnim =
369 | ViewCompat.animate(view).setDuration(getChangeDuration());
370 | oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);
371 | oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);
372 | oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() {
373 | @Override public void onAnimationStart(View view) {
374 | dispatchChangeStarting(changeInfo.oldHolder, true);
375 | }
376 |
377 | @Override public void onAnimationEnd(View view) {
378 | oldViewAnim.setListener(null);
379 | ViewCompat.setAlpha(view, 1);
380 | ViewCompat.setTranslationX(view, 0);
381 | ViewCompat.setTranslationY(view, 0);
382 | dispatchChangeFinished(changeInfo.oldHolder, true);
383 | mChangeAnimations.remove(changeInfo.oldHolder);
384 | dispatchFinishedWhenDone();
385 | }
386 | }).start();
387 | }
388 | if (newView != null) {
389 | mChangeAnimations.add(changeInfo.newHolder);
390 | final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView);
391 | newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).
392 | alpha(1).setListener(new VpaListenerAdapter() {
393 | @Override public void onAnimationStart(View view) {
394 | dispatchChangeStarting(changeInfo.newHolder, false);
395 | }
396 |
397 | @Override public void onAnimationEnd(View view) {
398 | newViewAnimation.setListener(null);
399 | ViewCompat.setAlpha(newView, 1);
400 | ViewCompat.setTranslationX(newView, 0);
401 | ViewCompat.setTranslationY(newView, 0);
402 | dispatchChangeFinished(changeInfo.newHolder, false);
403 | mChangeAnimations.remove(changeInfo.newHolder);
404 | dispatchFinishedWhenDone();
405 | }
406 | }).start();
407 | }
408 | }
409 |
410 | private void endChangeAnimation(List infoList, ViewHolder item) {
411 | for (int i = infoList.size() - 1; i >= 0; i--) {
412 | ChangeInfo changeInfo = infoList.get(i);
413 | if (endChangeAnimationIfNecessary(changeInfo, item)) {
414 | if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
415 | infoList.remove(changeInfo);
416 | }
417 | }
418 | }
419 | }
420 |
421 | private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) {
422 | if (changeInfo.oldHolder != null) {
423 | endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder);
424 | }
425 | if (changeInfo.newHolder != null) {
426 | endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder);
427 | }
428 | }
429 |
430 | private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) {
431 | boolean oldItem = false;
432 | if (changeInfo.newHolder == item) {
433 | changeInfo.newHolder = null;
434 | } else if (changeInfo.oldHolder == item) {
435 | changeInfo.oldHolder = null;
436 | oldItem = true;
437 | } else {
438 | return false;
439 | }
440 | ViewCompat.setAlpha(item.itemView, 1);
441 | ViewCompat.setTranslationX(item.itemView, 0);
442 | ViewCompat.setTranslationY(item.itemView, 0);
443 | dispatchChangeFinished(item, oldItem);
444 | return true;
445 | }
446 |
447 | @Override public void endAnimation(ViewHolder item) {
448 | final View view = item.itemView;
449 | // this will trigger end callback which should set properties to their target values.
450 | ViewCompat.animate(view).cancel();
451 | // TODO if some other animations are chained to end, how do we cancel them as well?
452 | for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
453 | MoveInfo moveInfo = mPendingMoves.get(i);
454 | if (moveInfo.holder == item) {
455 | ViewCompat.setTranslationY(view, 0);
456 | ViewCompat.setTranslationX(view, 0);
457 | dispatchMoveFinished(item);
458 | mPendingMoves.remove(i);
459 | }
460 | }
461 | endChangeAnimation(mPendingChanges, item);
462 | if (mPendingRemovals.remove(item)) {
463 | ViewHelper.clear(item.itemView);
464 | dispatchRemoveFinished(item);
465 | }
466 | if (mPendingAdditions.remove(item)) {
467 | ViewHelper.clear(item.itemView);
468 | dispatchAddFinished(item);
469 | }
470 |
471 | for (int i = mChangesList.size() - 1; i >= 0; i--) {
472 | ArrayList changes = mChangesList.get(i);
473 | endChangeAnimation(changes, item);
474 | if (changes.isEmpty()) {
475 | mChangesList.remove(i);
476 | }
477 | }
478 | for (int i = mMovesList.size() - 1; i >= 0; i--) {
479 | ArrayList moves = mMovesList.get(i);
480 | for (int j = moves.size() - 1; j >= 0; j--) {
481 | MoveInfo moveInfo = moves.get(j);
482 | if (moveInfo.holder == item) {
483 | ViewCompat.setTranslationY(view, 0);
484 | ViewCompat.setTranslationX(view, 0);
485 | dispatchMoveFinished(item);
486 | moves.remove(j);
487 | if (moves.isEmpty()) {
488 | mMovesList.remove(i);
489 | }
490 | break;
491 | }
492 | }
493 | }
494 | for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
495 | ArrayList additions = mAdditionsList.get(i);
496 | if (additions.remove(item)) {
497 | ViewHelper.clear(item.itemView);
498 | dispatchAddFinished(item);
499 | if (additions.isEmpty()) {
500 | mAdditionsList.remove(i);
501 | }
502 | }
503 | }
504 |
505 | // animations should be ended by the cancel above.
506 | if (mRemoveAnimations.remove(item) && DEBUG) {
507 | throw new IllegalStateException(
508 | "after animation is cancelled, item should not be in " + "mRemoveAnimations list");
509 | }
510 |
511 | if (mAddAnimations.remove(item) && DEBUG) {
512 | throw new IllegalStateException(
513 | "after animation is cancelled, item should not be in " + "mAddAnimations list");
514 | }
515 |
516 | if (mChangeAnimations.remove(item) && DEBUG) {
517 | throw new IllegalStateException(
518 | "after animation is cancelled, item should not be in " + "mChangeAnimations list");
519 | }
520 |
521 | if (mMoveAnimations.remove(item) && DEBUG) {
522 | throw new IllegalStateException(
523 | "after animation is cancelled, item should not be in " + "mMoveAnimations list");
524 | }
525 | dispatchFinishedWhenDone();
526 | }
527 |
528 | @Override public boolean isRunning() {
529 | return (!mPendingAdditions.isEmpty() ||
530 | !mPendingChanges.isEmpty() ||
531 | !mPendingMoves.isEmpty() ||
532 | !mPendingRemovals.isEmpty() ||
533 | !mMoveAnimations.isEmpty() ||
534 | !mRemoveAnimations.isEmpty() ||
535 | !mAddAnimations.isEmpty() ||
536 | !mChangeAnimations.isEmpty() ||
537 | !mMovesList.isEmpty() ||
538 | !mAdditionsList.isEmpty() ||
539 | !mChangesList.isEmpty());
540 | }
541 |
542 | /**
543 | * Check the state of currently pending and running animations. If there are none
544 | * pending/running, call #dispatchAnimationsFinished() to notify any
545 | * listeners.
546 | */
547 | private void dispatchFinishedWhenDone() {
548 | if (!isRunning()) {
549 | dispatchAnimationsFinished();
550 | }
551 | }
552 |
553 | @Override public void endAnimations() {
554 | int count = mPendingMoves.size();
555 | for (int i = count - 1; i >= 0; i--) {
556 | MoveInfo item = mPendingMoves.get(i);
557 | View view = item.holder.itemView;
558 | ViewCompat.setTranslationY(view, 0);
559 | ViewCompat.setTranslationX(view, 0);
560 | dispatchMoveFinished(item.holder);
561 | mPendingMoves.remove(i);
562 | }
563 | count = mPendingRemovals.size();
564 | for (int i = count - 1; i >= 0; i--) {
565 | ViewHolder item = mPendingRemovals.get(i);
566 | dispatchRemoveFinished(item);
567 | mPendingRemovals.remove(i);
568 | }
569 | count = mPendingAdditions.size();
570 | for (int i = count - 1; i >= 0; i--) {
571 | ViewHolder item = mPendingAdditions.get(i);
572 | ViewHelper.clear(item.itemView);
573 | dispatchAddFinished(item);
574 | mPendingAdditions.remove(i);
575 | }
576 | count = mPendingChanges.size();
577 | for (int i = count - 1; i >= 0; i--) {
578 | endChangeAnimationIfNecessary(mPendingChanges.get(i));
579 | }
580 | mPendingChanges.clear();
581 | if (!isRunning()) {
582 | return;
583 | }
584 |
585 | int listCount = mMovesList.size();
586 | for (int i = listCount - 1; i >= 0; i--) {
587 | ArrayList moves = mMovesList.get(i);
588 | count = moves.size();
589 | for (int j = count - 1; j >= 0; j--) {
590 | MoveInfo moveInfo = moves.get(j);
591 | ViewHolder item = moveInfo.holder;
592 | View view = item.itemView;
593 | ViewCompat.setTranslationY(view, 0);
594 | ViewCompat.setTranslationX(view, 0);
595 | dispatchMoveFinished(moveInfo.holder);
596 | moves.remove(j);
597 | if (moves.isEmpty()) {
598 | mMovesList.remove(moves);
599 | }
600 | }
601 | }
602 | listCount = mAdditionsList.size();
603 | for (int i = listCount - 1; i >= 0; i--) {
604 | ArrayList additions = mAdditionsList.get(i);
605 | count = additions.size();
606 | for (int j = count - 1; j >= 0; j--) {
607 | ViewHolder item = additions.get(j);
608 | View view = item.itemView;
609 | ViewCompat.setAlpha(view, 1);
610 | dispatchAddFinished(item);
611 | //this check prevent exception when removal already happened during finishing animation
612 | if (j < additions.size()) {
613 | additions.remove(j);
614 | }
615 | if (additions.isEmpty()) {
616 | mAdditionsList.remove(additions);
617 | }
618 | }
619 | }
620 | listCount = mChangesList.size();
621 | for (int i = listCount - 1; i >= 0; i--) {
622 | ArrayList changes = mChangesList.get(i);
623 | count = changes.size();
624 | for (int j = count - 1; j >= 0; j--) {
625 | endChangeAnimationIfNecessary(changes.get(j));
626 | if (changes.isEmpty()) {
627 | mChangesList.remove(changes);
628 | }
629 | }
630 | }
631 |
632 | cancelAll(mRemoveAnimations);
633 | cancelAll(mMoveAnimations);
634 | cancelAll(mAddAnimations);
635 | cancelAll(mChangeAnimations);
636 |
637 | dispatchAnimationsFinished();
638 | }
639 |
640 | void cancelAll(List viewHolders) {
641 | for (int i = viewHolders.size() - 1; i >= 0; i--) {
642 | ViewCompat.animate(viewHolders.get(i).itemView).cancel();
643 | }
644 | }
645 |
646 | private static class VpaListenerAdapter implements ViewPropertyAnimatorListener {
647 |
648 | @Override public void onAnimationStart(View view) {
649 | }
650 |
651 | @Override public void onAnimationEnd(View view) {
652 | }
653 |
654 | @Override public void onAnimationCancel(View view) {
655 | }
656 | }
657 |
658 | protected class DefaultAddVpaListener extends VpaListenerAdapter {
659 |
660 | ViewHolder mViewHolder;
661 |
662 | public DefaultAddVpaListener(final ViewHolder holder) {
663 | mViewHolder = holder;
664 | }
665 |
666 | @Override public void onAnimationStart(View view) {
667 | dispatchAddStarting(mViewHolder);
668 | }
669 |
670 | @Override public void onAnimationCancel(View view) {
671 | ViewHelper.clear(view);
672 | }
673 |
674 | @Override public void onAnimationEnd(View view) {
675 | ViewHelper.clear(view);
676 | dispatchAddFinished(mViewHolder);
677 | mAddAnimations.remove(mViewHolder);
678 | dispatchFinishedWhenDone();
679 | }
680 | }
681 |
682 | protected class DefaultRemoveVpaListener extends VpaListenerAdapter {
683 |
684 | ViewHolder mViewHolder;
685 |
686 | public DefaultRemoveVpaListener(final ViewHolder holder) {
687 | mViewHolder = holder;
688 | }
689 |
690 | @Override public void onAnimationStart(View view) {
691 | dispatchRemoveStarting(mViewHolder);
692 | }
693 |
694 | @Override public void onAnimationCancel(View view) {
695 | ViewHelper.clear(view);
696 | }
697 |
698 | @Override public void onAnimationEnd(View view) {
699 | ViewHelper.clear(view);
700 | dispatchRemoveFinished(mViewHolder);
701 | mRemoveAnimations.remove(mViewHolder);
702 | dispatchFinishedWhenDone();
703 | }
704 | }
705 |
706 | public static interface AnimateViewHolder {
707 |
708 | void preAnimateAddImpl(final ViewHolder holder);
709 |
710 | void preAnimateRemoveImpl(final ViewHolder holder);
711 |
712 | void animateAddImpl(final ViewHolder holder, ViewPropertyAnimatorListener listener);
713 |
714 | void animateRemoveImpl(final ViewHolder holder,
715 | ViewPropertyAnimatorListener listener);
716 | }
717 | }
718 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/anims/LandingAnimator.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.anims;
2 |
3 | /**
4 | * Copyright (C) 2017 Wasabeef
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | import android.support.v4.view.ViewCompat;
20 | import android.support.v7.widget.RecyclerView;
21 | import android.view.animation.Interpolator;
22 |
23 | public class LandingAnimator extends BaseItemAnimator {
24 |
25 | public LandingAnimator() {
26 | }
27 |
28 | public LandingAnimator(Interpolator interpolator) {
29 | mInterpolator = interpolator;
30 | }
31 |
32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
33 | ViewCompat.animate(holder.itemView)
34 | .alpha(0)
35 | .scaleX(1.5f)
36 | .scaleY(1.5f)
37 | .setDuration(getRemoveDuration())
38 | .setInterpolator(mInterpolator)
39 | .setListener(new DefaultRemoveVpaListener(holder))
40 | .setStartDelay(getRemoveDelay(holder))
41 | .start();
42 | }
43 |
44 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
45 | ViewCompat.setAlpha(holder.itemView, 0);
46 | ViewCompat.setScaleX(holder.itemView, 1.5f);
47 | ViewCompat.setScaleY(holder.itemView, 1.5f);
48 | }
49 |
50 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
51 | ViewCompat.animate(holder.itemView)
52 | .alpha(1)
53 | .scaleX(1)
54 | .scaleY(1)
55 | .setDuration(getAddDuration())
56 | .setInterpolator(mInterpolator)
57 | .setListener(new DefaultAddVpaListener(holder))
58 | .setStartDelay(getAddDelay(holder))
59 | .start();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/anims/ScaleInAnimationAdapter.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.anims;
2 |
3 | import android.animation.Animator;
4 | import android.animation.ObjectAnimator;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.View;
7 |
8 | /**
9 | * Copyright (C) 2017 Wasabeef
10 | *
11 | * Licensed under the Apache License, Version 2.0 (the "License");
12 | * you may not use this file except in compliance with the License.
13 | * You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | */
23 |
24 | public class ScaleInAnimationAdapter extends AnimationAdapter {
25 |
26 | private static final float DEFAULT_SCALE_FROM = .5f;
27 | private final float mFrom;
28 |
29 | public ScaleInAnimationAdapter(RecyclerView.Adapter adapter) {
30 | this(adapter, DEFAULT_SCALE_FROM);
31 | }
32 |
33 | public ScaleInAnimationAdapter(RecyclerView.Adapter adapter, float from) {
34 | super(adapter);
35 | mFrom = from;
36 | }
37 |
38 | @Override protected Animator[] getAnimators(View view) {
39 | ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", mFrom, 1f);
40 | ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", mFrom, 1f);
41 | return new ObjectAnimator[] { scaleX, scaleY };
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/anims/ViewHelper.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.anims;
2 |
3 | import android.support.v4.view.ViewCompat;
4 | import android.view.View;
5 |
6 | /**
7 | * Copyright (C) 2017 Wasabeef
8 | *
9 | * Licensed under the Apache License, Version 2.0 (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 |
22 | public final class ViewHelper {
23 |
24 | public static void clear(View v) {
25 | ViewCompat.setAlpha(v, 1);
26 | ViewCompat.setScaleY(v, 1);
27 | ViewCompat.setScaleX(v, 1);
28 | ViewCompat.setTranslationY(v, 0);
29 | ViewCompat.setTranslationX(v, 0);
30 | ViewCompat.setRotation(v, 0);
31 | ViewCompat.setRotationY(v, 0);
32 | ViewCompat.setRotationX(v, 0);
33 | ViewCompat.setPivotY(v, v.getMeasuredHeight() / 2);
34 | ViewCompat.setPivotX(v, v.getMeasuredWidth() / 2);
35 | ViewCompat.animate(v).setInterpolator(null).setStartDelay(0);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/app/AppApplication.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.app;
2 |
3 |
4 | import com.lvr.timeline.base.BaseApplication;
5 |
6 | import io.realm.Realm;
7 | import io.realm.RealmConfiguration;
8 |
9 | /**
10 | * APPLICATION
11 | */
12 | public class AppApplication extends BaseApplication {
13 | public static Realm REALM_INSTANCE;
14 | @Override
15 | public void onCreate() {
16 | super.onCreate();
17 | Realm.init(this);
18 | RealmConfiguration config = new RealmConfiguration.Builder()
19 | .name("TimeLineRealm.realm")
20 | .deleteRealmIfMigrationNeeded()
21 | .build();
22 | REALM_INSTANCE = Realm.getInstance(config);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/app/AppConstantValue.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.app;
2 |
3 | /**
4 | * Created by lvr on 2017/4/17.
5 | */
6 |
7 | public class AppConstantValue {
8 | public static final String HINT_TITLE ="标题不能为空";
9 | public static final String HINT_TIME ="时间段设置错误";
10 | public static final String HINT_MISS ="少壮不努力,老大徒伤悲!\n时间已经过去了......";
11 | //滑动删除按钮 关闭
12 | public static final int DELETE_STATE_CLOSE = 0;
13 | //滑动删除按钮 开着
14 | public static final int DELETE_STATE_OPEN = 1;
15 | //滑动删除按钮 正在关闭
16 | public static final int DELETE_STATE_CLOSEING = 2;
17 | //滑动删除按钮 正在开
18 | public static final int DELETE_STATE_OPENING =3;
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/app/AppManager.java:
--------------------------------------------------------------------------------
1 |
2 | package com.lvr.timeline.app;
3 |
4 | import android.app.Activity;
5 | import android.app.ActivityManager;
6 | import android.content.Context;
7 |
8 | import java.util.Stack;
9 |
10 | /**
11 | * activity管理
12 | */
13 | public class AppManager {
14 | private static Stack activityStack;
15 | private volatile static AppManager instance;
16 |
17 | private AppManager() {
18 |
19 | }
20 | /**
21 | * 单一实例
22 | */
23 | public static AppManager getAppManager() {
24 | if (instance == null) {
25 | synchronized (AppManager.class){
26 | if(instance==null){
27 | instance = new AppManager();
28 | instance.activityStack = new Stack();
29 | }
30 | }
31 |
32 | }
33 | return instance;
34 | }
35 |
36 | /**
37 | * 添加Activity到堆栈
38 | */
39 | public void addActivity(Activity activity) {
40 | if (activityStack == null) {
41 | activityStack = new Stack();
42 | }
43 | activityStack.add(activity);
44 | }
45 |
46 | /**
47 | * 获取当前Activity(堆栈中最后一个压入的)
48 | */
49 | public Activity currentActivity() {
50 | try {
51 | Activity activity = activityStack.lastElement();
52 | return activity;
53 | } catch (Exception e) {
54 | // e.printStackTrace();
55 | return null;
56 | }
57 | }
58 |
59 | /**
60 | * 获取当前Activity的前一个Activity
61 | */
62 | public Activity preActivity() {
63 | int index = activityStack.size() - 2;
64 | if (index < 0) {
65 | return null;
66 | }
67 | Activity activity = activityStack.get(index);
68 | return activity;
69 | }
70 |
71 | /**
72 | * 结束当前Activity(堆栈中最后一个压入的)
73 | */
74 | public void finishActivity() {
75 | Activity activity = activityStack.lastElement();
76 | finishActivity(activity);
77 | }
78 |
79 | /**
80 | * 结束指定的Activity
81 | */
82 | public void finishActivity(Activity activity) {
83 | if (activity != null) {
84 | activityStack.remove(activity);
85 | activity.finish();
86 | activity = null;
87 | }
88 | }
89 |
90 | /**
91 | * 移除指定的Activity
92 | */
93 | public void removeActivity(Activity activity) {
94 | if (activity != null) {
95 | activityStack.remove(activity);
96 | activity = null;
97 | }
98 | }
99 |
100 | /**
101 | * 结束指定类名的Activity
102 | */
103 | public void finishActivity(Class> cls) {
104 | try {
105 | for (Activity activity : activityStack) {
106 | if (activity.getClass().equals(cls)) {
107 | finishActivity(activity);
108 | }
109 | }
110 | } catch (Exception e) {
111 | e.printStackTrace();
112 | }
113 |
114 | }
115 |
116 | /**
117 | * 结束所有Activity
118 | */
119 | public void finishAllActivity() {
120 | for (int i = 0, size = activityStack.size(); i < size; i++) {
121 | if (null != activityStack.get(i)) {
122 | activityStack.get(i).finish();
123 | }
124 | }
125 | activityStack.clear();
126 | }
127 |
128 | /**
129 | * 返回到指定的activity
130 | *
131 | * @param cls
132 | */
133 | public void returnToActivity(Class> cls) {
134 | while (activityStack.size() != 0)
135 | if (activityStack.peek().getClass() == cls) {
136 | break;
137 | } else {
138 | finishActivity(activityStack.peek());
139 | }
140 | }
141 |
142 |
143 | /**
144 | * 是否已经打开指定的activity
145 | * @param cls
146 | * @return
147 | */
148 | public boolean isOpenActivity(Class> cls) {
149 | if (activityStack!=null){
150 | for (int i = 0, size = activityStack.size(); i < size; i++) {
151 | if (cls == activityStack.peek().getClass()) {
152 | return true;
153 | }
154 | }
155 | }
156 | return false;
157 | }
158 |
159 | /**
160 | * 退出应用程序
161 | *
162 | * @param context 上下文
163 | * @param isBackground 是否开开启后台运行
164 | */
165 | public void AppExit(Context context, Boolean isBackground) {
166 | try {
167 | finishAllActivity();
168 | ActivityManager activityMgr = (ActivityManager) context
169 | .getSystemService(Context.ACTIVITY_SERVICE);
170 | activityMgr.restartPackage(context.getPackageName());
171 | } catch (Exception e) {
172 |
173 | } finally {
174 | // 注意,如果您有后台程序运行,请不要支持此句子
175 | if (!isBackground) {
176 | System.exit(0);
177 | }
178 | }
179 | }
180 | }
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/base/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.base;
2 |
3 |
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.pm.ActivityInfo;
7 | import android.os.Bundle;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.view.Window;
10 |
11 | import com.lvr.timeline.R;
12 | import com.lvr.timeline.app.AppManager;
13 | import com.lvr.timeline.utils.StatusBarSetting;
14 |
15 | import butterknife.ButterKnife;
16 | import butterknife.Unbinder;
17 |
18 | /**
19 | * 基类
20 | */
21 |
22 | public abstract class BaseActivity extends AppCompatActivity {
23 |
24 | public Context mContext;
25 | private Unbinder mUnbinder;
26 | private int count;//记录开启进度条的情况 只能开一个
27 |
28 | @Override
29 | public void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | doBeforeSetcontentView();
32 | setContentView(getLayoutId());
33 | // 默认着色状态栏
34 | SetStatusBarColor();
35 | mUnbinder = ButterKnife.bind(this);
36 | mContext = this;
37 |
38 | this.initPresenter();
39 | this.initView();
40 | }
41 |
42 | /**
43 | * 设置layout前配置
44 | */
45 | private void doBeforeSetcontentView() {
46 | // 把actvity放到application栈中管理
47 | AppManager.getAppManager().addActivity(this);
48 | // 无标题
49 | requestWindowFeature(Window.FEATURE_NO_TITLE);
50 | // 设置竖屏
51 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
52 |
53 |
54 | }
55 |
56 | /*********************
57 | * 子类实现
58 | *****************************/
59 | //获取布局文件
60 | public abstract int getLayoutId();
61 |
62 | //简单页面无需mvp就不用管此方法即可,完美兼容各种实际场景的变通
63 | public abstract void initPresenter();
64 |
65 | //初始化view
66 | public abstract void initView();
67 |
68 | /**
69 | * 着色状态栏(4.4以上系统有效)
70 | */
71 | protected void SetStatusBarColor() {
72 | StatusBarSetting.setColor(this, getResources().getColor(R.color.colorPrimary));
73 | }
74 |
75 | /**
76 | * 着色状态栏(4.4以上系统有效)
77 | */
78 | protected void SetStatusBarColor(int color) {
79 | StatusBarSetting.setColor(this, color);
80 | }
81 |
82 | /**
83 | * 沉浸状态栏(4.4以上系统有效)
84 | */
85 | protected void SetTranslanteBar() {
86 | StatusBarSetting.setTranslucent(this);
87 | }
88 |
89 |
90 | /**
91 | * 通过Class跳转界面
92 | **/
93 | public void startActivity(Class> cls) {
94 | startActivity(cls, null);
95 | }
96 |
97 | /**
98 | * 通过Class跳转界面
99 | **/
100 | public void startActivityForResult(Class> cls, int requestCode) {
101 | startActivityForResult(cls, null, requestCode);
102 | }
103 |
104 | /**
105 | * 含有Bundle通过Class跳转界面
106 | **/
107 | public void startActivityForResult(Class> cls, Bundle bundle,
108 | int requestCode) {
109 | Intent intent = new Intent();
110 | intent.setClass(this, cls);
111 | if (bundle != null) {
112 | intent.putExtras(bundle);
113 | }
114 | startActivityForResult(intent, requestCode);
115 | }
116 |
117 | /**
118 | * 含有Bundle通过Class跳转界面
119 | **/
120 | public void startActivity(Class> cls, Bundle bundle) {
121 | Intent intent = new Intent();
122 | intent.setClass(this, cls);
123 | if (bundle != null) {
124 | intent.putExtras(bundle);
125 | }
126 | startActivity(intent);
127 | }
128 |
129 |
130 |
131 | @Override
132 | protected void onResume() {
133 | super.onResume();
134 |
135 | }
136 |
137 | @Override
138 | protected void onPause() {
139 | super.onPause();
140 |
141 | }
142 |
143 |
144 | @Override
145 | protected void onDestroy() {
146 | super.onDestroy();
147 | mUnbinder.unbind();
148 | AppManager.getAppManager().finishActivity(this);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/base/BaseApplication.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.base;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.content.res.Resources;
6 |
7 | /**
8 | * APPLICATION
9 | */
10 | public class BaseApplication extends Application {
11 |
12 | private static BaseApplication baseApplication;
13 |
14 | @Override
15 | public void onCreate() {
16 | super.onCreate();
17 | baseApplication = this;
18 | }
19 |
20 | public static Context getAppContext() {
21 | return baseApplication;
22 | }
23 | public static Resources getAppResources() {
24 | return baseApplication.getResources();
25 | }
26 | @Override
27 | public void onTerminate() {
28 | super.onTerminate();
29 | }
30 |
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/base/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.base;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 |
12 | import butterknife.ButterKnife;
13 | import butterknife.Unbinder;
14 |
15 |
16 | public abstract class BaseFragment extends Fragment {
17 | protected View rootView;
18 |
19 | private Unbinder mUnbinder;
20 | private int count;//记录开启进度条的情况 只能开一个
21 | //当前Fragment是否处于可见状态标志,防止因ViewPager的缓存机制而导致回调函数的触发
22 | private boolean isFragmentVisible;
23 | //是否是第一次开启网络加载
24 | public boolean isFirst;
25 |
26 | @Nullable
27 | @Override
28 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
29 | if (rootView == null)
30 | rootView = inflater.inflate(getLayoutResource(), container, false);
31 | mUnbinder = ButterKnife.bind(this, rootView);
32 | initView();
33 | //可见,但是并没有加载过
34 | if (isFragmentVisible && !isFirst) {
35 | onFragmentVisibleChange(true);
36 | }
37 | return rootView;
38 | }
39 |
40 | //获取布局文件
41 | protected abstract int getLayoutResource();
42 |
43 |
44 | //初始化view
45 | protected abstract void initView();
46 |
47 |
48 | /**
49 | * 通过Class跳转界面
50 | **/
51 | public void startActivity(Class> cls) {
52 | startActivity(cls, null);
53 | }
54 |
55 | /**
56 | * 通过Class跳转界面
57 | **/
58 | public void startActivityForResult(Class> cls, int requestCode) {
59 | startActivityForResult(cls, null, requestCode);
60 | }
61 |
62 | /**
63 | * 含有Bundle通过Class跳转界面
64 | **/
65 | public void startActivityForResult(Class> cls, Bundle bundle,
66 | int requestCode) {
67 | Intent intent = new Intent();
68 | intent.setClass(getActivity(), cls);
69 | if (bundle != null) {
70 | intent.putExtras(bundle);
71 | }
72 | startActivityForResult(intent, requestCode);
73 | }
74 |
75 | /**
76 | * 含有Bundle通过Class跳转界面
77 | **/
78 | public void startActivity(Class> cls, Bundle bundle) {
79 | Intent intent = new Intent();
80 | intent.setClass(getActivity(), cls);
81 | if (bundle != null) {
82 | intent.putExtras(bundle);
83 | }
84 | startActivity(intent);
85 | }
86 |
87 | @Override
88 | public void setUserVisibleHint(boolean isVisibleToUser) {
89 | super.setUserVisibleHint(isVisibleToUser);
90 | if (isVisibleToUser) {
91 | isFragmentVisible = true;
92 | }
93 | if (rootView == null) {
94 | return;
95 | }
96 | //可见,并且没有加载过
97 | if (!isFirst&&isFragmentVisible) {
98 | onFragmentVisibleChange(true);
99 | return;
100 | }
101 | //由可见——>不可见 已经加载过
102 | if (isFragmentVisible) {
103 | onFragmentVisibleChange(false);
104 | isFragmentVisible = false;
105 | }
106 | }
107 |
108 |
109 |
110 | @Override
111 | public void onDestroyView() {
112 | super.onDestroyView();
113 | mUnbinder.unbind();
114 | }
115 |
116 | /**
117 | * 当前fragment可见状态发生变化时会回调该方法
118 | * 如果当前fragment是第一次加载,等待onCreateView后才会回调该方法,其它情况回调时机跟 {@link #setUserVisibleHint(boolean)}一致
119 | * 在该回调方法中你可以做一些加载数据操作,甚至是控件的操作.
120 | *
121 | * @param isVisible true 不可见 -> 可见
122 | * false 可见 -> 不可见
123 | */
124 | protected void onFragmentVisibleChange(boolean isVisible) {
125 |
126 | }
127 |
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/base/BaseFragmentAdapter.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.base;
2 |
3 | import android.support.v4.app.Fragment;
4 | import android.support.v4.app.FragmentManager;
5 | import android.support.v4.app.FragmentPagerAdapter;
6 |
7 | import com.lvr.timeline.utils.CollectionUtils;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class BaseFragmentAdapter extends FragmentPagerAdapter {
13 |
14 | List fragmentList = new ArrayList();
15 | private List mTitles;
16 |
17 | public BaseFragmentAdapter(FragmentManager fm, List fragmentList) {
18 | super(fm);
19 | this.fragmentList = fragmentList;
20 | }
21 |
22 | public BaseFragmentAdapter(FragmentManager fm, List fragmentList, List mTitles) {
23 | super(fm);
24 | this.fragmentList = fragmentList;
25 | this.mTitles = mTitles;
26 | }
27 |
28 | @Override
29 | public CharSequence getPageTitle(int position) {
30 | return !CollectionUtils.isNullOrEmpty(mTitles) ? mTitles.get(position) : "";
31 | }
32 |
33 | @Override
34 | public Fragment getItem(int position) {
35 | return fragmentList.get(position);
36 | }
37 |
38 | @Override
39 | public int getCount() {
40 | return fragmentList.size();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/bean/TimeInfo.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.bean;
2 |
3 |
4 | import android.os.Parcel;
5 | import android.os.Parcelable;
6 |
7 | import io.realm.RealmObject;
8 | import io.realm.annotations.PrimaryKey;
9 |
10 | public class TimeInfo extends RealmObject implements Parcelable {
11 | //年月日信息
12 | private String ymD;
13 | //标题
14 | private String title;
15 | //内容
16 | private String content;
17 | //时间段信息 12:00-13:00
18 | @PrimaryKey
19 | private String addTime;
20 |
21 | public String getCreateTime() {
22 | return createTime;
23 | }
24 |
25 | public void setCreateTime(String createTime) {
26 | this.createTime = createTime;
27 | }
28 |
29 | //创建该条目时的时间
30 | private String createTime;
31 | //是否是新的任务
32 | private boolean isNew = true;
33 | //在列表中所处位置
34 | private int position = -1;
35 |
36 | public int getPosition() {
37 | return position;
38 | }
39 |
40 | public void setPosition(int position) {
41 | this.position = position;
42 | }
43 |
44 |
45 |
46 | public boolean isNew() {
47 | return isNew;
48 | }
49 |
50 | public void setNew(boolean aNew) {
51 | isNew = aNew;
52 | }
53 |
54 |
55 |
56 | public String getTitle() {
57 | return title;
58 | }
59 |
60 | public void setTitle(String title) {
61 | this.title = title;
62 | }
63 |
64 | public String getContent() {
65 | return content;
66 | }
67 |
68 | public void setContent(String content) {
69 | this.content = content;
70 | }
71 |
72 | public String getYmD() {
73 | return ymD;
74 | }
75 |
76 | public void setYmD(String ymD) {
77 | this.ymD = ymD;
78 | }
79 |
80 | public String getAddTime() {
81 | return addTime;
82 | }
83 |
84 | public void setAddTime(String addTime) {
85 | this.addTime = addTime;
86 | }
87 |
88 | @Override
89 | public String toString() {
90 | return "TimeInfo{" +
91 | "ymD='" + ymD + '\'' +
92 | ", title='" + title + '\'' +
93 | ", content='" + content + '\'' +
94 | ", addTime='" + addTime + '\'' +
95 | '}';
96 | }
97 |
98 | @Override
99 | public int describeContents() {
100 | return 0;
101 | }
102 |
103 | @Override
104 | public void writeToParcel(Parcel dest, int flags) {
105 | dest.writeString(this.ymD);
106 | dest.writeString(this.title);
107 | dest.writeString(this.content);
108 | dest.writeString(this.addTime);
109 | }
110 |
111 | public TimeInfo() {
112 | }
113 |
114 | protected TimeInfo(Parcel in) {
115 | this.ymD = in.readString();
116 | this.title = in.readString();
117 | this.content = in.readString();
118 | this.addTime = in.readString();
119 | }
120 |
121 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
122 | @Override
123 | public TimeInfo createFromParcel(Parcel source) {
124 | return new TimeInfo(source);
125 | }
126 |
127 | @Override
128 | public TimeInfo[] newArray(int size) {
129 | return new TimeInfo[size];
130 | }
131 | };
132 | }
133 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/home/fragment/CountDownFragment.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.home.fragment;
2 |
3 | import com.lvr.timeline.R;
4 | import com.lvr.timeline.base.BaseFragment;
5 |
6 | /**
7 | * Created by lvr on 2017/4/8.
8 | */
9 |
10 | public class CountDownFragment extends BaseFragment {
11 | @Override
12 | protected int getLayoutResource() {
13 | return R.layout.fragment_countdown;
14 | }
15 |
16 | @Override
17 | protected void initView() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/home/fragment/TodayFragment.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.home.fragment;
2 |
3 | import android.content.Intent;
4 | import android.support.v7.widget.LinearLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.widget.Toast;
7 |
8 | import com.lvr.timeline.R;
9 | import com.lvr.timeline.adapter.TimelineAdapter;
10 | import com.lvr.timeline.anims.LandingAnimator;
11 | import com.lvr.timeline.anims.ScaleInAnimationAdapter;
12 | import com.lvr.timeline.app.AppApplication;
13 | import com.lvr.timeline.base.BaseFragment;
14 | import com.lvr.timeline.bean.TimeInfo;
15 | import com.lvr.timeline.home.ui.EditActivity;
16 | import com.lvr.timeline.utils.RealmOperationHelper;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | import butterknife.BindView;
22 | import de.greenrobot.event.EventBus;
23 | import de.greenrobot.event.Subscribe;
24 | import io.realm.RealmChangeListener;
25 | import io.realm.RealmResults;
26 |
27 | /**
28 | * Created by lvr on 2017/4/8.
29 | */
30 |
31 | public class TodayFragment extends BaseFragment implements TimelineAdapter.OnItemClickListener{
32 | @BindView(R.id.rv_record)
33 | RecyclerView mRvRecord;
34 | private TimelineAdapter mAdapter;
35 | private List mInfos = new ArrayList<>();
36 | @Override
37 | protected int getLayoutResource() {
38 | return R.layout.fragment_today;
39 | }
40 |
41 | @Override
42 | protected void initView() {
43 | mAdapter = new TimelineAdapter(getActivity(),mInfos);
44 | mRvRecord.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false));
45 | mAdapter.setOnItemClickListener(this);
46 | mRvRecord.setItemAnimator(new LandingAnimator());
47 | ScaleInAnimationAdapter scaleAdapter = new ScaleInAnimationAdapter(mAdapter);
48 | scaleAdapter.setFirstOnly(false);
49 | scaleAdapter.setDuration(500);
50 | mRvRecord.setAdapter(scaleAdapter);
51 | mRvRecord.getItemAnimator().setAddDuration(300);
52 | mRvRecord.getItemAnimator().setChangeDuration(300);
53 | mRvRecord.getItemAnimator().setMoveDuration(300);
54 | mRvRecord.getItemAnimator().setRemoveDuration(300);
55 | if(!EventBus.getDefault().isRegistered(this)){
56 | EventBus.getDefault().register(this);
57 | }
58 | coverData();
59 | }
60 |
61 | /**
62 | * 恢复数据库中数据
63 | */
64 | private void coverData() {
65 | final RealmResults results = (RealmResults) RealmOperationHelper.getInstance(AppApplication.REALM_INSTANCE).queryAllAsync(TimeInfo.class);
66 | // TODO: 2017/4/20 开启加载提示
67 | results.addChangeListener(new RealmChangeListener>() {
68 | @Override
69 | public void onChange(RealmResults element) {
70 | results.removeAllChangeListeners();
71 | // TODO: 2017/4/20 关闭加载提示
72 | Toast.makeText(getActivity(), "加载数据完毕", Toast.LENGTH_SHORT).show();
73 | System.out.println("从数据库中查找到的条目:" + element.size());
74 | if (element == null) {
75 | return;
76 | }
77 | mInfos.addAll(element);
78 | System.out.println("复制后的数据条目:" + mInfos.size());
79 | mAdapter.notifyDataSetChanged();
80 | }
81 | });
82 |
83 |
84 |
85 | }
86 |
87 | @Subscribe
88 | public void onTimeInfoEvent(final TimeInfo info) {
89 | if(info.isNew()){
90 | mInfos.add(info);
91 | mAdapter.notifyItemRangeInserted(mInfos.size(),1);
92 | RealmOperationHelper.getInstance(AppApplication.REALM_INSTANCE).add(info);
93 | System.out.println("添加一个新数据");
94 | }else{
95 | if(info.getPosition()!=-1){
96 | mInfos.remove(info.getPosition());
97 | mInfos.add(info.getPosition(),info);
98 | mAdapter.notifyItemChanged(info.getPosition());
99 | }
100 | }
101 |
102 | }
103 |
104 |
105 | @Override
106 | public void onItemClick(TimeInfo mInfo,int position) {
107 | Intent intent = new Intent(getActivity(), EditActivity.class);
108 | intent.putExtra("TimeInfo",mInfo);
109 | intent.putExtra("position",position);
110 | startActivity(intent);
111 | }
112 |
113 | @Override
114 | public void onDestroy() {
115 | super.onDestroy();
116 | AppApplication.REALM_INSTANCE.close();
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/home/fragment/YesterdayFragment.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.home.fragment;
2 |
3 | import com.lvr.timeline.R;
4 | import com.lvr.timeline.base.BaseFragment;
5 |
6 | /**
7 | * Created by lvr on 2017/4/8.
8 | */
9 |
10 | public class YesterdayFragment extends BaseFragment {
11 | @Override
12 | protected int getLayoutResource() {
13 | return R.layout.fragment_yesterday;
14 | }
15 |
16 | @Override
17 | protected void initView() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/home/ui/EditActivity.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.home.ui;
2 |
3 |
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.support.v7.app.AlertDialog;
8 | import android.support.v7.widget.Toolbar;
9 | import android.text.TextUtils;
10 | import android.util.Log;
11 | import android.view.LayoutInflater;
12 | import android.view.Menu;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.widget.Button;
16 | import android.widget.EditText;
17 | import android.widget.LinearLayout;
18 | import android.widget.TextView;
19 |
20 | import com.borax12.materialdaterangepicker.time.RadialPickerLayout;
21 | import com.borax12.materialdaterangepicker.time.TimePickerDialog;
22 | import com.lvr.timeline.R;
23 | import com.lvr.timeline.app.AppConstantValue;
24 | import com.lvr.timeline.base.BaseActivity;
25 | import com.lvr.timeline.bean.TimeInfo;
26 |
27 | import java.text.SimpleDateFormat;
28 | import java.util.Calendar;
29 | import java.util.Date;
30 | import java.util.GregorianCalendar;
31 |
32 | import butterknife.BindView;
33 | import de.greenrobot.event.EventBus;
34 |
35 | /**
36 | * Created by lvr on 2017/4/8.
37 | */
38 |
39 | public class EditActivity extends BaseActivity implements View.OnClickListener, TimePickerDialog.OnTimeSetListener {
40 | @BindView(R.id.toolbar)
41 | Toolbar mToolbar;
42 | @BindView(R.id.ed_title)
43 | EditText mEdTitle;
44 | @BindView(R.id.ed_content)
45 | EditText mEdContent;
46 | @BindView(R.id.ll_root)
47 | LinearLayout mLlRoot;
48 | @BindView(R.id.tv_time)
49 | TextView mTvTime;
50 | @BindView(R.id.tv_today)
51 | TextView mTvToday;
52 | private TimeInfo mInfo;
53 | private int mPosition = -2;
54 | private AlertDialog mDialog;
55 |
56 | @Override
57 | public int getLayoutId() {
58 | return R.layout.activity_edit;
59 | }
60 |
61 | @Override
62 | public void initPresenter() {
63 |
64 | }
65 |
66 | @Override
67 | public void initView() {
68 | mToolbar.setTitle("添加任务");
69 | mToolbar.setTitleTextColor(getResources().getColor(R.color.white));
70 | setSupportActionBar(mToolbar);
71 | mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
72 | @Override
73 | public void onClick(View view) {
74 | onBackPressed();
75 | }
76 | });
77 | Intent intent = getIntent();
78 | setPreInformation(intent);
79 | mTvTime.setOnClickListener(this);
80 | }
81 |
82 | /**
83 | * 初始化时间
84 | */
85 | private void initDate() {
86 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
87 | String allTime = format.format(new Date());
88 | int index = allTime.indexOf(" ");
89 | String ymd = allTime.substring(0, index);
90 | String hm = allTime.substring(index + 1);
91 | setDate(ymd, hm);
92 | }
93 |
94 | /**
95 | * 设置启动Intent时,携带的信息
96 | *
97 | * @param intent
98 | */
99 | private void setPreInformation(Intent intent) {
100 | if (intent != null) {
101 | Bundle extras = intent.getExtras();
102 | if (extras != null) {
103 | mInfo = (TimeInfo) extras.get("TimeInfo");
104 | if (mInfo != null) {
105 | if (mInfo.getTitle() != null) {
106 | mEdTitle.setText(mInfo.getTitle());
107 | }
108 | if (mInfo.getContent() != null) {
109 | mEdContent.setText(mInfo.getContent());
110 | }
111 | if (mInfo.getYmD() != null) {
112 | mTvToday.setText(mInfo.getYmD());
113 | }
114 | if (mInfo.getAddTime() != null) {
115 | mTvTime.setText(mInfo.getAddTime());
116 | }
117 | mInfo.setNew(false);
118 | }
119 | mPosition = (int) extras.get("position");
120 | if (mPosition != -2) {
121 | mInfo.setPosition(mPosition);
122 | }
123 |
124 | } else {
125 | initDate();
126 | }
127 | }
128 |
129 | }
130 |
131 |
132 | @Override
133 | public boolean onCreateOptionsMenu(Menu menu) {
134 | getMenuInflater().inflate(R.menu.menu_toolabr, menu);
135 | MenuItem item = menu.findItem(R.id.mn_it_edit);
136 | item.setIcon(R.drawable.mn_right);
137 | item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
138 | @Override
139 | public boolean onMenuItemClick(MenuItem item) {
140 | if (verfyContent()) {
141 | String title = mEdTitle.getText().toString();
142 | System.out.println("title的内容:" + title);
143 | String content = mEdContent.getText().toString();
144 | if (mInfo == null) {
145 | mInfo = new TimeInfo();
146 | }
147 | mInfo.setTitle(title);
148 | mInfo.setContent(content);
149 | mInfo.setYmD(mTvToday.getText().toString());
150 | mInfo.setAddTime(mTvTime.getText().toString());
151 | System.out.println(mInfo);
152 | EventBus.getDefault().post(mInfo);
153 | finish();
154 | }
155 | return true;
156 | }
157 | });
158 | return true;
159 | }
160 |
161 | /**
162 | * 任务内容格式是否符合
163 | */
164 | private boolean verfyContent() {
165 | if (TextUtils.isEmpty(mEdTitle.getText().toString())) {
166 | //开启AlertDialog提示
167 | showErrorDialog(AppConstantValue.HINT_TITLE);
168 | return false;
169 | } else {
170 | boolean flag = verfyTime();
171 | return flag;
172 | }
173 | }
174 |
175 | /**
176 | * 创建AlertDialog提示
177 | *
178 | * @param hint
179 | */
180 | private void showErrorDialog(final String hint) {
181 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
182 | LayoutInflater inflater = LayoutInflater.from(this);
183 | View view = inflater.inflate(R.layout.dialog_view, null);
184 | Button btn_hint = (Button) view.findViewById(R.id.btn_hint);
185 | TextView tv_hint = (TextView) view.findViewById(R.id.tv_hint);
186 | tv_hint.setText(hint);
187 | builder.setView(view, 0, 0, 0, 0);
188 | btn_hint.setOnClickListener(new View.OnClickListener() {
189 | @Override
190 | public void onClick(View v) {
191 | mDialog.dismiss();
192 | if (hint.equals(AppConstantValue.HINT_TITLE)) {
193 | verfyTime();
194 | }
195 | }
196 | });
197 | mDialog = builder.create();
198 | mDialog.show();
199 |
200 |
201 | }
202 |
203 | /**
204 | * 检查时间段设置是否正确
205 | */
206 | private boolean verfyTime() {
207 | String time = mTvTime.getText().toString();
208 | String[] split = time.split("-");
209 | String begin = split[0];
210 | String end = split[1];
211 | String[] begin_split = begin.split(":");
212 | String[] end_split = end.split(":");
213 | int hour_begin = Integer.parseInt(begin_split[0]);
214 | int minute_begin = Integer.parseInt(begin_split[1]);
215 | int hour_end = Integer.parseInt(end_split[0]);
216 | int minute_end = Integer.parseInt(end_split[1]);
217 | SimpleDateFormat format = new SimpleDateFormat("HH:mm");
218 | String cur_time = format.format(new Date());
219 | String[] cur_split = cur_time.split(":");
220 | int hour_cur = Integer.parseInt(cur_split[0]);
221 | int minute_cur = Integer.parseInt(cur_split[1]);
222 | //获取当前的年月日信息
223 | format = new SimpleDateFormat("yyyy-MM-dd");
224 | String cur_date = format.format(new Date());
225 | String[] date_split = cur_date.split("-");
226 | int cur_day = Integer.parseInt(date_split[2]);
227 | String show_date = mTvToday.getText().toString();
228 | String[] show_split = show_date.split("-");
229 | int show_day = Integer.parseInt(show_split[2]);
230 | if (show_day == cur_day) {
231 | if (hour_cur > hour_begin) {
232 | showErrorDialog(AppConstantValue.HINT_MISS);
233 | return false;
234 | } else if (hour_cur == hour_begin) {
235 | if (minute_cur > minute_begin) {
236 | showErrorDialog(AppConstantValue.HINT_MISS);
237 | return false;
238 | }
239 | }
240 | }
241 |
242 | if (hour_begin > hour_end) {
243 | showErrorDialog(AppConstantValue.HINT_TIME);
244 | return false;
245 | } else if (hour_begin == hour_end) {
246 | if (minute_begin > minute_end) {
247 | showErrorDialog(AppConstantValue.HINT_TIME);
248 | return false;
249 | }
250 | }
251 | return true;
252 | }
253 |
254 | /**
255 | * 设置具体时间信息
256 | *
257 | * @param ymd
258 | * @param hm
259 | */
260 | private void setDate(String ymd, String hm) {
261 | //获得当前小时时间
262 | String hour = hm.substring(0, 2);
263 | int cur_hour = Integer.parseInt(hour);
264 | if (cur_hour > 22) {
265 | Date date = new Date();//取时间
266 | Calendar calendar = new GregorianCalendar();
267 | calendar.setTime(date);
268 | calendar.add(calendar.DATE, 1);
269 | date = calendar.getTime();
270 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
271 | ymd = formatter.format(date);
272 | }
273 | mTvTime.setText(hm + "-" + hm);
274 | mTvToday.setText(ymd);
275 | }
276 |
277 |
278 | @Override
279 | public void onClick(View v) {
280 | Calendar now = Calendar.getInstance();
281 | TimePickerDialog tpd = TimePickerDialog.newInstance(
282 | EditActivity.this,
283 | now.get(Calendar.HOUR_OF_DAY),
284 | now.get(Calendar.MINUTE),
285 | false);
286 | tpd.setOnCancelListener(new DialogInterface.OnCancelListener() {
287 | @Override
288 | public void onCancel(DialogInterface dialogInterface) {
289 | Log.d("TimePicker", "Dialog was cancelled");
290 | }
291 | });
292 | tpd.show(getFragmentManager(), "Timepickerdialog");
293 | }
294 |
295 | @Override
296 | public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute, int hourOfDayEnd, int minuteEnd) {
297 | System.out.println("hourOfDay:" + hourOfDay);
298 | System.out.println("minute:" + minute);
299 | System.out.println("hourOfDayEnd:" + hourOfDayEnd);
300 | System.out.println("minuteEnd:" + minuteEnd);
301 | //这个日历库有个BUG 12点与24点显示有误
302 | int temp = hourOfDay;
303 | if (temp == 0) {
304 | hourOfDay = 12;
305 | }
306 | if (temp == 12) {
307 | hourOfDay = 0;
308 | }
309 | String hourString = hourOfDay < 10 ? "0" + hourOfDay : "" + hourOfDay;
310 | String minuteString = minute < 10 ? "0" + minute : "" + minute;
311 | String hourStringEnd = hourOfDayEnd < 10 ? "0" + hourOfDayEnd : "" + hourOfDayEnd;
312 | String minuteStringEnd = minuteEnd < 10 ? "0" + minuteEnd : "" + minuteEnd;
313 | String time = hourString + ":" + minuteString + "-" + hourStringEnd + ":" + minuteStringEnd;
314 |
315 | mTvTime.setText(time);
316 | }
317 |
318 | }
319 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/home/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.home.ui;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.design.widget.NavigationView;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentTransaction;
8 | import android.support.v4.widget.DrawerLayout;
9 | import android.support.v7.app.ActionBar;
10 | import android.support.v7.app.ActionBarDrawerToggle;
11 | import android.support.v7.widget.Toolbar;
12 | import android.view.Menu;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.widget.FrameLayout;
16 | import android.widget.RadioButton;
17 | import android.widget.RadioGroup;
18 |
19 | import com.lvr.timeline.R;
20 | import com.lvr.timeline.app.AppApplication;
21 | import com.lvr.timeline.base.BaseActivity;
22 | import com.lvr.timeline.home.fragment.CountDownFragment;
23 | import com.lvr.timeline.home.fragment.TodayFragment;
24 | import com.lvr.timeline.home.fragment.YesterdayFragment;
25 | import com.lvr.timeline.utils.StatusBarSetting;
26 |
27 | import java.util.List;
28 |
29 | import butterknife.BindView;
30 |
31 | public class MainActivity extends BaseActivity implements View.OnClickListener{
32 |
33 |
34 | @BindView(R.id.toolbar)
35 | Toolbar mToolbar;
36 | @BindView(R.id.navigation)
37 | NavigationView mNavigation;
38 | @BindView(R.id.drawer_layout)
39 | DrawerLayout mDrawerLayout;
40 | @BindView(R.id.fl_root)
41 | FrameLayout mFl_root;
42 | @BindView(R.id.rb_today)
43 | RadioButton mRbToday;
44 | @BindView(R.id.rb_time)
45 | RadioButton mRbTime;
46 | @BindView(R.id.rb_yesterday)
47 | RadioButton mRbYesterday;
48 | @BindView(R.id.rg_root)
49 | RadioGroup mRgRoot;
50 | private CountDownFragment mCountDownFragment;
51 | private TodayFragment mTodayFragment;
52 | private YesterdayFragment mYesterdayFragment;
53 |
54 |
55 |
56 | @Override
57 | public int getLayoutId() {
58 | return R.layout.activity_home;
59 | }
60 |
61 | @Override
62 | public void initPresenter() {
63 |
64 | }
65 |
66 | @Override
67 | public void initView() {
68 | StatusBarSetting.setColorForDrawerLayout(this, mDrawerLayout, getResources().getColor(R.color.colorPrimary), StatusBarSetting.DEFAULT_STATUS_BAR_ALPHA);
69 | setToolBar();
70 | setNavigationView();
71 | setRadioGroup();
72 |
73 | }
74 |
75 | private void setRadioGroup() {
76 | mRbToday.setOnClickListener(this);
77 | mRbYesterday.setOnClickListener(this);
78 | mRbTime.setOnClickListener(this);
79 | mRbToday.setChecked(true);
80 | mRbToday.setTextColor(getResources().getColor(R.color.tab_selecet));
81 | }
82 |
83 | @Override
84 | public void onCreate(Bundle savedInstanceState) {
85 | super.onCreate(savedInstanceState);
86 | //初始化Framgent,考虑到异常杀死的情况
87 | initFragment(savedInstanceState);
88 | }
89 |
90 | private void initFragment(Bundle savedInstanceState) {
91 | if (savedInstanceState != null) {
92 | //异常情况下
93 | List fragments = getSupportFragmentManager().getFragments();
94 | for (Fragment fragment : fragments) {
95 | if (fragment instanceof TodayFragment) {
96 | mTodayFragment = (TodayFragment) fragment;
97 | }
98 | if (fragment instanceof YesterdayFragment) {
99 | mYesterdayFragment = (YesterdayFragment) fragment;
100 | }
101 | if (fragment instanceof CountDownFragment) {
102 | mCountDownFragment = (CountDownFragment) fragment;
103 | }
104 | }
105 | } else {
106 | //添加到FragmentManger,异常时,自动保存Fragment状态
107 | mTodayFragment = new TodayFragment();
108 | mYesterdayFragment = new YesterdayFragment();
109 | mCountDownFragment = new CountDownFragment();
110 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
111 | transaction.add(R.id.fl_root, mTodayFragment);
112 | transaction.add(R.id.fl_root, mYesterdayFragment);
113 | transaction.add(R.id.fl_root, mCountDownFragment);
114 | transaction.commit();
115 | }
116 |
117 | //显示与隐藏正确的Fragment
118 | getSupportFragmentManager().beginTransaction().
119 | show(mTodayFragment).
120 | hide(mYesterdayFragment).
121 | hide(mCountDownFragment).commit();
122 | }
123 |
124 |
125 | private void setNavigationView() {
126 | //NavigationView初始化
127 | mNavigation.setItemIconTintList(null);
128 | View headerView = mNavigation.getHeaderView(0);
129 |
130 | }
131 |
132 | private void setToolBar() {
133 | mToolbar.setTitle("今天");//设置标题
134 | setSupportActionBar(mToolbar);
135 | ActionBar actionBar = getSupportActionBar();
136 | //菜单按钮可用
137 | actionBar.setHomeButtonEnabled(true);
138 | //回退按钮可用
139 | actionBar.setDisplayHomeAsUpEnabled(true);
140 | //将drawlayout与toolbar绑定在一起
141 | ActionBarDrawerToggle abdt = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.app_name, R.string.app_name);
142 | abdt.syncState();//初始化状态
143 | //设置drawlayout的监听事件 打开/关闭
144 | mDrawerLayout.setDrawerListener(abdt);
145 | //actionbar中的内容进行初始化
146 | mToolbar.setTitleTextColor(getResources().getColor(R.color.white));
147 | }
148 |
149 |
150 | @Override
151 | public void onClick(View v) {
152 | switch (v.getId()){
153 | case(R.id.rb_today):{
154 | clearState();
155 | mRbToday.setChecked(true);
156 | mRbToday.setTextColor(getResources().getColor(R.color.tab_selecet));
157 | getSupportFragmentManager().beginTransaction().show(mTodayFragment)
158 | .hide(mYesterdayFragment)
159 | .hide(mCountDownFragment)
160 | .commit();
161 | break;
162 | }
163 | case(R.id.rb_time):{
164 | clearState();
165 | mRbTime.setChecked(true);
166 | mRbTime.setTextColor(getResources().getColor(R.color.tab_selecet));
167 | getSupportFragmentManager().beginTransaction().show(mCountDownFragment)
168 | .hide(mYesterdayFragment)
169 | .hide(mTodayFragment)
170 | .commit();
171 | break;
172 | }
173 | case(R.id.rb_yesterday):{
174 | clearState();
175 | mRbYesterday.setChecked(true);
176 | mRbYesterday.setTextColor(getResources().getColor(R.color.tab_selecet));
177 | getSupportFragmentManager().beginTransaction().show(mYesterdayFragment)
178 | .hide(mTodayFragment)
179 | .hide(mCountDownFragment)
180 | .commit();
181 | break;
182 | }
183 | }
184 | }
185 |
186 | //清空之前的状态
187 | private void clearState() {
188 | mRgRoot.clearCheck();
189 | mRbTime.setTextColor(getResources().getColor(R.color.black));
190 | mRbToday.setTextColor(getResources().getColor(R.color.black));
191 | mRbYesterday.setTextColor(getResources().getColor(R.color.black));
192 |
193 | }
194 | @Override
195 | public boolean onCreateOptionsMenu(Menu menu) {
196 | getMenuInflater().inflate(R.menu.menu_toolabr, menu);
197 | MenuItem item = menu.findItem(R.id.mn_it_edit);
198 | item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
199 | @Override
200 | public boolean onMenuItemClick(MenuItem item) {
201 | Intent intent = new Intent(getApplicationContext(),EditActivity.class);
202 | startActivity(intent);
203 | return true;
204 | }
205 | });
206 | return true;
207 | }
208 |
209 | @Override
210 | protected void onDestroy() {
211 | super.onDestroy();
212 | AppApplication.REALM_INSTANCE.close();
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/utils/CollectionUtils.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.utils;
2 |
3 | import java.util.Collection;
4 |
5 | /**
6 | * 集合操作工具类
7 | *
8 | */
9 | public class CollectionUtils {
10 |
11 | /**
12 | * 判断集合是否为null或者0个元素
13 | *
14 | * @param c
15 | * @return
16 | */
17 | public static boolean isNullOrEmpty(Collection c) {
18 | if (null == c || c.isEmpty()) {
19 | return true;
20 | }
21 | return false;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/utils/DisplayUtil.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.utils;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Rect;
7 | import android.util.DisplayMetrics;
8 | import android.view.View;
9 | import android.view.ViewTreeObserver;
10 | import android.view.ViewTreeObserver.OnGlobalLayoutListener;
11 | import android.view.WindowManager;
12 | import android.widget.LinearLayout;
13 |
14 | import com.lvr.timeline.app.AppApplication;
15 |
16 |
17 | /**
18 | * 屏幕相关的辅助类
19 | */
20 | public class DisplayUtil {
21 | private DisplayUtil() {
22 | /* cannot be instantiated */
23 | throw new UnsupportedOperationException("cannot be instantiated");
24 | }
25 |
26 |
27 | /**
28 | * 将px值转换为dip或dp值,保证尺寸大小不变
29 | *
30 | * @param pxValue
31 | * (DisplayMetrics类中属性density)
32 | * @return
33 | */
34 | public static int px2dip(float pxValue) {
35 | final float scale = AppApplication.getAppContext().getResources().getDisplayMetrics().density;
36 | return (int) (pxValue / scale + 0.5f);
37 | }
38 |
39 | /**
40 | * 将dip或dp值转换为px值,保证尺寸大小不变
41 | *
42 | * @param dipValue
43 | * (DisplayMetrics类中属性density)
44 | * @return
45 | */
46 | public static int dip2px( float dipValue) {
47 | final float scale = AppApplication.getAppContext().getResources().getDisplayMetrics().density;
48 | return (int) (dipValue * scale + 0.5f);
49 | }
50 |
51 | /**
52 | * 将px值转换为sp值,保证文字大小不变
53 | *
54 | * @param pxValue
55 | * (DisplayMetrics类中属性scaledDensity)
56 | * @return
57 | */
58 | public static int px2sp(float pxValue) {
59 | final float fontScale = AppApplication.getAppContext().getResources().getDisplayMetrics().scaledDensity;
60 | return (int) (pxValue / fontScale + 0.5f);
61 | }
62 |
63 | /**
64 | * 将sp值转换为px值,保证文字大小不变
65 | *
66 | * @param spValue
67 | * (DisplayMetrics类中属性scaledDensity)
68 | * @return
69 | */
70 | public static int sp2px(float spValue) {
71 | final float fontScale = AppApplication.getAppContext().getResources().getDisplayMetrics().scaledDensity;
72 | return (int) (spValue * fontScale + 0.5f);
73 | }
74 |
75 | /**
76 | * 直接获取控件的宽、高
77 | * @param view
78 | * @return int[]
79 | */
80 | public static int[] getWidgetWH(final View view){
81 | ViewTreeObserver vto2 = view.getViewTreeObserver();
82 | vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
83 | @Override
84 | public void onGlobalLayout() {
85 | view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
86 | }
87 | });
88 | return new int[]{view.getWidth(),view.getHeight()};
89 | }
90 |
91 | /**
92 | * 直接获取控件的宽、高
93 | * @param view
94 | * @return int[]
95 | */
96 | public static int getViewHeight(final View view){
97 | ViewTreeObserver vto2 = view.getViewTreeObserver();
98 | vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
99 | @Override
100 | public void onGlobalLayout() {
101 | view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
102 | }
103 | });
104 | return view.getHeight();
105 | }
106 |
107 | /**
108 | * 直接获取控件的宽、高
109 | * @param view
110 | * @return int[]
111 | */
112 | public static int getViewWidth(final View view){
113 | ViewTreeObserver vto2 = view.getViewTreeObserver();
114 | vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
115 | @Override
116 | public void onGlobalLayout() {
117 | view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
118 | }
119 | });
120 | return view.getWidth();
121 | }
122 |
123 | /**
124 | * 获得屏幕宽度
125 | *
126 | * @param context
127 | * @return
128 | */
129 | public static int getScreenWidth(Context context) {
130 | WindowManager wm = (WindowManager) context
131 | .getSystemService(Context.WINDOW_SERVICE);
132 | DisplayMetrics outMetrics = new DisplayMetrics();
133 | wm.getDefaultDisplay().getMetrics(outMetrics);
134 | return outMetrics.widthPixels;
135 | }
136 |
137 | /**
138 | * 获得屏幕高度
139 | *
140 | * @param context
141 | * @return
142 | */
143 | public static int getScreenHeight(Context context) {
144 | WindowManager wm = (WindowManager) context
145 | .getSystemService(Context.WINDOW_SERVICE);
146 | DisplayMetrics outMetrics = new DisplayMetrics();
147 | wm.getDefaultDisplay().getMetrics(outMetrics);
148 | return outMetrics.heightPixels;
149 | }
150 |
151 | /**
152 | * 获得状态栏的高度
153 | * 注意:该方法只能在Activity类中使用,在测试模式下失败
154 | * @param context
155 | * @return
156 | */
157 | public static int getStatusBarHeight(Context context) {
158 | int statusBarHeight = -1;
159 | try {
160 | Class> clazz = Class.forName("com.android.internal.R$dimen");
161 | Object object = clazz.newInstance();
162 | int height = Integer.parseInt(clazz.getField("status_bar_height")
163 | .get(object).toString());
164 | statusBarHeight = context.getResources().getDimensionPixelSize(height);
165 | } catch (Exception e) {
166 | e.printStackTrace();
167 | }
168 | return statusBarHeight;
169 | }
170 |
171 | /**
172 | * 获取控件的宽
173 | * @param view
174 | * @return
175 | */
176 | public static int getWidgetWidth(View view){
177 | int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
178 | int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
179 | view.measure(w, h);//先度量
180 | int width = view.getMeasuredWidth();
181 | return width;
182 | }
183 | /**
184 | * 获取控件的高
185 | * @param view
186 | * @return
187 | */
188 | public static int getWidgetHeight(View view){
189 | int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
190 | int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
191 | view.measure(w, h);//先度量
192 | int height = view.getMeasuredHeight();
193 | return height;
194 | }
195 | /**
196 | * 设置控件宽
197 | * @param view
198 | * @param width
199 | */
200 | public static void setWidgetWidth(View view, int width){
201 | LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
202 | params.width = width;
203 | view.setLayoutParams(params);
204 | }
205 | /**
206 | * 设置控件高
207 | * @param view
208 | * @param height
209 | */
210 | public static void setWidgetHeight(View view, int height){
211 | LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
212 | params.height = height;
213 | view.setLayoutParams(params);
214 | }
215 |
216 |
217 | //----------------------------------------------
218 |
219 | /**
220 | * 获取当前屏幕截图,包含状态栏(这个方法没测试通过)
221 | *
222 | * @param activity
223 | * @return Bitmap
224 | */
225 | public static Bitmap snapShotWithStatusBar(Activity activity) {
226 | View view = activity.getWindow().getDecorView();
227 | view.setDrawingCacheEnabled(true);
228 | view.buildDrawingCache();
229 | Bitmap bmp = view.getDrawingCache();
230 | int width = getScreenWidth(activity);
231 | int height = getScreenHeight(activity);
232 | Bitmap bp = null;
233 | bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
234 | view.destroyDrawingCache();
235 | return bp;
236 | }
237 |
238 | /**
239 | * 获取当前屏幕截图,不包含状态栏(这个方法没测试通过)
240 | *
241 | * @param activity
242 | * @return Bitmap
243 | */
244 | public static Bitmap snapShotWithoutStatusBar(Activity activity) {
245 | View view = activity.getWindow().getDecorView();
246 | view.setDrawingCacheEnabled(true);
247 | view.buildDrawingCache();
248 | Bitmap bmp = view.getDrawingCache();
249 | Rect frame = new Rect();
250 | activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
251 | int statusBarHeight = frame.top;
252 |
253 | int width = getScreenWidth(activity);
254 | int height = getScreenHeight(activity);
255 | Bitmap bp = null;
256 | bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
257 | - statusBarHeight);
258 | view.destroyDrawingCache();
259 | return bp;
260 | }
261 | }
262 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/utils/GlideRoundTransformUtil.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.utils;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapShader;
6 | import android.graphics.Canvas;
7 | import android.graphics.Paint;
8 |
9 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
10 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
11 |
12 |
13 | /**
14 | * description:glide转换圆角图片
15 | * Created by xsf
16 | * on 2016.04.15:17
17 | */
18 | public class GlideRoundTransformUtil extends BitmapTransformation {
19 | public GlideRoundTransformUtil(Context context) {
20 | super(context);
21 | }
22 |
23 | @Override
24 | protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
25 | return circleCrop(pool, toTransform);
26 | }
27 |
28 | private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
29 | if (source == null) return null;
30 |
31 | int size = Math.min(source.getWidth(), source.getHeight());
32 | int x = (source.getWidth() - size) / 2;
33 | int y = (source.getHeight() - size) / 2;
34 |
35 | // TODO this could be acquired from the pool too
36 | Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
37 |
38 | Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
39 | if (result == null) {
40 | result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
41 | }
42 |
43 | Canvas canvas = new Canvas(result);
44 | Paint paint = new Paint();
45 | paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
46 | paint.setAntiAlias(true);
47 | float r = size / 2f;
48 | canvas.drawCircle(r, r, r, paint);
49 | return result;
50 | }
51 |
52 | @Override
53 | public String getId() {
54 | return getClass().getName();
55 | }
56 | }
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/utils/ImageLoaderUtils.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.utils;
2 |
3 | import android.content.Context;
4 | import android.widget.ImageView;
5 |
6 | import com.bumptech.glide.Glide;
7 | import com.bumptech.glide.load.DecodeFormat;
8 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
9 | import com.lvr.timeline.R;
10 |
11 | import java.io.File;
12 |
13 | /**
14 | * Description : 图片加载工具类 使用glide框架封装
15 | */
16 | public class ImageLoaderUtils {
17 |
18 | public static void display(Context context, ImageView imageView, String url, int placeholder, int error) {
19 | if (imageView == null) {
20 | throw new IllegalArgumentException("argument error");
21 | }
22 | Glide.with(context).load(url).placeholder(placeholder)
23 | .error(error).crossFade().into(imageView);
24 | }
25 |
26 | public static void display(Context context, ImageView imageView, String url) {
27 | if (imageView == null) {
28 | throw new IllegalArgumentException("argument error");
29 | }
30 | Glide.with(context).load(url)
31 | .diskCacheStrategy(DiskCacheStrategy.ALL)
32 | .centerCrop()
33 | .placeholder(R.drawable.ic_image_loading)
34 | .error(R.drawable.ic_empty_picture)
35 | .crossFade().into(imageView);
36 | }
37 |
38 | public static void display(Context context, ImageView imageView, File url) {
39 | if (imageView == null) {
40 | throw new IllegalArgumentException("argument error");
41 | }
42 | Glide.with(context).load(url)
43 | .diskCacheStrategy(DiskCacheStrategy.ALL)
44 | .centerCrop()
45 | .placeholder(R.drawable.ic_image_loading)
46 | .error(R.drawable.ic_empty_picture)
47 | .crossFade().into(imageView);
48 | }
49 | public static void displaySmallPhoto(Context context, ImageView imageView, String url) {
50 | if (imageView == null) {
51 | throw new IllegalArgumentException("argument error");
52 | }
53 | Glide.with(context).load(url).asBitmap()
54 | .diskCacheStrategy(DiskCacheStrategy.ALL)
55 | .placeholder(R.drawable.ic_image_loading)
56 | .error(R.drawable.ic_empty_picture)
57 | .thumbnail(0.5f)
58 | .into(imageView);
59 | }
60 | public static void displayBigPhoto(Context context, ImageView imageView, String url) {
61 | if (imageView == null) {
62 | throw new IllegalArgumentException("argument error");
63 | }
64 | Glide.with(context).load(url).asBitmap()
65 | .format(DecodeFormat.PREFER_ARGB_8888)
66 | .diskCacheStrategy(DiskCacheStrategy.ALL)
67 | .placeholder(R.drawable.ic_image_loading)
68 | .error(R.drawable.ic_empty_picture)
69 | .into(imageView);
70 | }
71 | public static void display(Context context, ImageView imageView, int url) {
72 | if (imageView == null) {
73 | throw new IllegalArgumentException("argument error");
74 | }
75 | Glide.with(context).load(url)
76 | .diskCacheStrategy(DiskCacheStrategy.ALL)
77 | .centerCrop()
78 | .placeholder(R.drawable.ic_image_loading)
79 | .error(R.drawable.ic_empty_picture)
80 | .crossFade().into(imageView);
81 | }
82 | public static void displayRound(Context context, ImageView imageView, String url) {
83 | if (imageView == null) {
84 | throw new IllegalArgumentException("argument error");
85 | }
86 | Glide.with(context).load(url)
87 | .diskCacheStrategy(DiskCacheStrategy.ALL)
88 | .error(R.drawable.toux2)
89 | .centerCrop().transform(new GlideRoundTransformUtil(context)).into(imageView);
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/utils/RealmOperationHelper.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.utils;
2 |
3 | import java.lang.reflect.InvocationTargetException;
4 | import java.lang.reflect.Method;
5 | import java.util.List;
6 |
7 | import io.realm.Realm;
8 | import io.realm.RealmAsyncTask;
9 | import io.realm.RealmObject;
10 | import io.realm.RealmResults;
11 | import io.realm.Sort;
12 |
13 | /**
14 | * Created by lvr on 2017/4/20.
15 | */
16 |
17 | public class RealmOperationHelper {
18 | private static Realm mRealm;
19 |
20 | private static class SingletonHolder {
21 | private static RealmOperationHelper INSTANCE = new RealmOperationHelper(
22 | mRealm);
23 | }
24 |
25 | private RealmOperationHelper(Realm realm) {
26 | this.mRealm = realm;
27 |
28 | }
29 |
30 | /**
31 | * 获取RealmOperation的单例
32 | *
33 | * @param realm 传入realm实例对象
34 | * @return 返回RealmOperation的单例
35 | */
36 | public static RealmOperationHelper getInstance(Realm realm) {
37 | if (realm != null) {
38 | mRealm = realm;
39 | }
40 | return SingletonHolder.INSTANCE;
41 | }
42 |
43 | /**
44 | * 增加单条数据到数据库中
45 | *
46 | * @param bean 数据对象,必须继承了RealmObject
47 | */
48 | public void add(final RealmObject bean) {
49 | mRealm.executeTransaction(new Realm.Transaction() {
50 | @Override
51 | public void execute(Realm realm) {
52 |
53 | realm.copyToRealm(bean);
54 |
55 | }
56 | });
57 |
58 | }
59 |
60 | /**
61 | * 增加多条数据到数据库中
62 | *
63 | * @param beans 数据集合,其中元素必须继承了RealmObject
64 | */
65 | public void add(final List extends RealmObject> beans) {
66 | mRealm.executeTransaction(new Realm.Transaction() {
67 | @Override
68 | public void execute(Realm realm) {
69 | realm.copyToRealm(beans);
70 |
71 | }
72 | });
73 |
74 | }
75 | /**
76 | * 增加多条数据到数据库中
77 | *
78 | * @param beans 数据集合,其中元素必须继承了RealmObject
79 | */
80 | public void addAsync(final List extends RealmObject> beans) {
81 | mRealm.executeTransactionAsync(new Realm.Transaction() {
82 | @Override
83 | public void execute(Realm realm) {
84 | realm.copyToRealm(beans);
85 | }
86 | });
87 |
88 | }
89 |
90 | /**
91 | * 删除数据库中clazz类所属所有元素
92 | *
93 | * @param clazz
94 | */
95 | public void deleteAll(Class extends RealmObject> clazz) {
96 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).findAll();
97 |
98 | mRealm.executeTransaction(new Realm.Transaction() {
99 | @Override
100 | public void execute(Realm realm) {
101 | beans.deleteAllFromRealm();
102 |
103 | }
104 | });
105 |
106 | }
107 | /**
108 | * 删除数据库中clazz类所属所有元素
109 | *
110 | * @param clazz
111 | */
112 | public void deleteAllAsync(Class extends RealmObject> clazz) {
113 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).findAll();
114 |
115 | mRealm.executeTransactionAsync(new Realm.Transaction() {
116 | @Override
117 | public void execute(Realm realm) {
118 | beans.deleteAllFromRealm();
119 |
120 | }
121 | });
122 |
123 |
124 | }
125 |
126 | /**
127 | * 删除数据库中clazz类所属第一个元素
128 | *
129 | * @param clazz
130 | */
131 | public void deleteFirst(Class extends RealmObject> clazz) {
132 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).findAll();
133 |
134 | mRealm.executeTransaction(new Realm.Transaction() {
135 | @Override
136 | public void execute(Realm realm) {
137 | beans.deleteFirstFromRealm();
138 |
139 | }
140 | });
141 |
142 | }
143 |
144 | /**
145 | * 删除数据库中clazz类所属最后一个元素
146 | *
147 | * @param clazz
148 | */
149 | public void deleteLast(Class extends RealmObject> clazz) {
150 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).findAll();
151 |
152 | mRealm.executeTransaction(new Realm.Transaction() {
153 | @Override
154 | public void execute(Realm realm) {
155 | beans.deleteLastFromRealm();
156 |
157 | }
158 | });
159 |
160 | }
161 |
162 | /**
163 | * 删除数据库中clazz类所属数据中某一位置的元素
164 | *
165 | * @param clazz
166 | * @param position
167 | */
168 | public void deleteElement(Class extends RealmObject> clazz, final int position) {
169 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).findAll();
170 |
171 | mRealm.executeTransaction(new Realm.Transaction() {
172 | @Override
173 | public void execute(Realm realm) {
174 | beans.deleteFromRealm(position);
175 |
176 | }
177 | });
178 |
179 | }
180 |
181 | /**
182 | * 查询数据库中clazz类所属所有数据
183 | *
184 | * @param clazz
185 | * @return
186 | */
187 | public RealmResults extends RealmObject> queryAll(Class extends RealmObject> clazz) {
188 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).findAll();
189 |
190 | return beans;
191 | }
192 | /**
193 | * 查询数据库中clazz类所属所有数据
194 | *
195 | * @param clazz
196 | * @return
197 | */
198 | public RealmResults extends RealmObject> queryAllAsync(Class extends RealmObject> clazz) {
199 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).findAllAsync();
200 |
201 | return beans;
202 | }
203 |
204 | /**
205 | * 查询满足条件的第一个数据
206 | *
207 | * @param clazz
208 | * @param fieldName
209 | * @param value
210 | * @return
211 | * @throws NoSuchFieldException
212 | */
213 | public RealmObject queryByFieldFirst(Class extends RealmObject> clazz, String fieldName, String value) throws NoSuchFieldException {
214 |
215 | final RealmObject bean = mRealm.where(clazz).equalTo(fieldName, value).findFirst();
216 |
217 | return bean;
218 | }
219 |
220 | /**
221 | * 查询满足条件的所有数据
222 | *
223 | * @param clazz
224 | * @param fieldName
225 | * @param value
226 | * @return
227 | * @throws NoSuchFieldException
228 | */
229 | public RealmResults extends RealmObject> queryByFieldAll(Class extends RealmObject> clazz, String fieldName, String value) throws NoSuchFieldException {
230 |
231 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).equalTo(fieldName, value).findAll();
232 |
233 | return beans;
234 | }
235 | /**
236 | * 查询满足条件的所有数据
237 | *
238 | * @param clazz
239 | * @param fieldName
240 | * @param value
241 | * @return
242 | * @throws NoSuchFieldException
243 | */
244 | public RealmResults extends RealmObject> queryByFieldAllAsync(Class extends RealmObject> clazz, String fieldName, String value) throws NoSuchFieldException {
245 |
246 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).equalTo(fieldName, value).findAllAsync();
247 |
248 | return beans;
249 | }
250 |
251 | /**
252 | * 查询满足条件的第一个数据
253 | *
254 | * @param clazz
255 | * @param fieldName
256 | * @param value
257 | * @return
258 | * @throws NoSuchFieldException
259 | */
260 | public RealmObject queryByFieldFirst(Class extends RealmObject> clazz, String fieldName, int value) throws NoSuchFieldException {
261 | final RealmObject bean = mRealm.where(clazz).equalTo(fieldName, value).findFirst();
262 |
263 | return bean;
264 | }
265 |
266 | /**
267 | * 查询满足条件的所有数据
268 | *
269 | * @param clazz
270 | * @param fieldName
271 | * @param value
272 | * @return
273 | * @throws NoSuchFieldException
274 | */
275 | public RealmResults extends RealmObject> queryByFieldAll(Class extends RealmObject> clazz, String fieldName, int value) throws NoSuchFieldException {
276 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).equalTo(fieldName, value).findAll();
277 | return beans;
278 | }
279 | /**
280 | * 查询满足条件的所有数据
281 | *
282 | * @param clazz
283 | * @param fieldName
284 | * @param value
285 | * @return
286 | * @throws NoSuchFieldException
287 | */
288 | public RealmResults extends RealmObject> queryByFieldAllAsync(Class extends RealmObject> clazz, String fieldName, int value) throws NoSuchFieldException {
289 |
290 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).equalTo(fieldName, value).findAllAsync();
291 | return beans;
292 | }
293 |
294 | /**
295 | * 查询数据,按增量排序
296 | *
297 | * @param clazz
298 | * @param fieldName
299 | * @return
300 | */
301 | public List extends RealmObject> queryAllByAscending(Class extends RealmObject> clazz, String fieldName) {
302 | RealmResults extends RealmObject> beans = mRealm.where(clazz).findAll();
303 | RealmResults extends RealmObject> results = beans.sort(fieldName, Sort.ASCENDING);
304 | return mRealm.copyFromRealm(results);
305 | }
306 |
307 |
308 | /**
309 | * 查询数据,按降量排序
310 | *
311 | * @param clazz
312 | * @param fieldName
313 | * @return
314 | */
315 | public List extends RealmObject> queryAllByDescending(Class extends RealmObject> clazz, String fieldName) {
316 | RealmResults extends RealmObject> beans = mRealm.where(clazz).findAll();
317 | RealmResults extends RealmObject> results = beans.sort(fieldName, Sort.DESCENDING);
318 | return mRealm.copyFromRealm(results);
319 | }
320 |
321 | /**
322 | * 更新满足某个条件的第一个数据的属性值
323 | * @param clazz
324 | * @param fieldName
325 | * @param oldValue
326 | * @param newValue
327 | * @throws NoSuchMethodException
328 | * @throws InvocationTargetException
329 | * @throws IllegalAccessException
330 | */
331 | public void updateFirstByField(Class extends RealmObject> clazz, String fieldName,String oldValue,String newValue) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
332 | final RealmObject bean = mRealm.where(clazz).equalTo(fieldName, oldValue).findFirst();
333 | mRealm.beginTransaction();
334 | Method method = clazz.getMethod(fieldName, String.class);
335 | method.invoke(bean,newValue);
336 | mRealm.commitTransaction();
337 |
338 | }
339 | /**
340 | * 更新满足某个条件的第一个数据的属性值
341 | * @param clazz
342 | * @param fieldName
343 | * @param oldValue
344 | * @param newValue
345 | * @throws NoSuchMethodException
346 | * @throws InvocationTargetException
347 | * @throws IllegalAccessException
348 | */
349 | public void updateFirstByField(Class extends RealmObject> clazz, String fieldName,int oldValue,int newValue) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
350 | final RealmObject bean = mRealm.where(clazz).equalTo(fieldName, oldValue).findFirst();
351 | mRealm.beginTransaction();
352 | Method method = clazz.getMethod(fieldName, int.class);
353 | method.invoke(bean,newValue);
354 | mRealm.commitTransaction();
355 |
356 | }
357 | /**
358 | * 更新满足某个条件的第一个数据的属性值
359 | * @param clazz
360 | * @param fieldName
361 | * @param oldValue
362 | * @param newValue
363 | * @throws NoSuchMethodException
364 | * @throws InvocationTargetException
365 | * @throws IllegalAccessException
366 | */
367 | public void updateAllByField(Class extends RealmObject> clazz, String fieldName,String oldValue,String newValue) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
368 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).equalTo(fieldName, oldValue).findAll();
369 | mRealm.beginTransaction();
370 | Method method = clazz.getMethod(fieldName, String.class);
371 | for(int i=0;i clazz, String fieldName,int oldValue,int newValue) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
389 | final RealmResults extends RealmObject> beans = mRealm.where(clazz).equalTo(fieldName, oldValue).findAll();
390 | mRealm.beginTransaction();
391 | Method method = clazz.getMethod(fieldName, int.class);
392 | for(int i=0;i= Build.VERSION_CODES.LOLLIPOP) {
49 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
50 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
51 | activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));
52 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
53 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
54 | ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
55 | View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID);
56 | if (fakeStatusBarView != null) {
57 | if (fakeStatusBarView.getVisibility() == View.GONE) {
58 | fakeStatusBarView.setVisibility(View.VISIBLE);
59 | }
60 | fakeStatusBarView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
61 | } else {
62 | decorView.addView(createStatusBarView(activity, color, statusBarAlpha));
63 | }
64 | setRootView(activity);
65 | }
66 | }
67 |
68 | /**
69 | * 为滑动返回界面设置状态栏颜色
70 | *
71 | * @param activity 需要设置的activity
72 | * @param color 状态栏颜色值
73 | */
74 | public static void setColorForSwipeBack(Activity activity, int color) {
75 | setColorForSwipeBack(activity, color, DEFAULT_STATUS_BAR_ALPHA);
76 | }
77 |
78 | /**
79 | * 为滑动返回界面设置状态栏颜色
80 | *
81 | * @param activity 需要设置的activity
82 | * @param color 状态栏颜色值
83 | * @param statusBarAlpha 状态栏透明度
84 | */
85 | public static void setColorForSwipeBack(Activity activity, @ColorInt int color, int statusBarAlpha) {
86 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
87 |
88 | ViewGroup contentView = ((ViewGroup) activity.findViewById(android.R.id.content));
89 | View rootView = contentView.getChildAt(0);
90 | int statusBarHeight = getStatusBarHeight(activity);
91 | if (rootView != null && rootView instanceof CoordinatorLayout) {
92 | final CoordinatorLayout coordinatorLayout = (CoordinatorLayout) rootView;
93 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
94 | coordinatorLayout.setFitsSystemWindows(false);
95 | contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
96 | boolean isNeedRequestLayout = contentView.getPaddingTop() < statusBarHeight;
97 | if (isNeedRequestLayout) {
98 | contentView.setPadding(0, statusBarHeight, 0, 0);
99 | coordinatorLayout.post(new Runnable() {
100 | @Override
101 | public void run() {
102 | coordinatorLayout.requestLayout();
103 | }
104 | });
105 | }
106 | } else {
107 | coordinatorLayout.setStatusBarBackgroundColor(calculateStatusColor(color, statusBarAlpha));
108 | }
109 | } else {
110 | contentView.setPadding(0, statusBarHeight, 0, 0);
111 | contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
112 | }
113 | setTransparentForWindow(activity);
114 | }
115 | }
116 |
117 | /**
118 | * 设置状态栏纯色 不加半透明效果
119 | *
120 | * @param activity 需要设置的 activity
121 | * @param color 状态栏颜色值
122 | */
123 | public static void setColorNoTranslucent(Activity activity, @ColorInt int color) {
124 | setColor(activity, color, 0);
125 | }
126 |
127 | /**
128 | * 设置状态栏颜色(5.0以下无半透明效果,不建议使用)
129 | *
130 | * @param activity 需要设置的 activity
131 | * @param color 状态栏颜色值
132 | */
133 | @Deprecated
134 | public static void setColorDiff(Activity activity, @ColorInt int color) {
135 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
136 | return;
137 | }
138 | transparentStatusBar(activity);
139 | ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
140 | // 移除半透明矩形,以免叠加
141 | View fakeStatusBarView = contentView.findViewById(FAKE_STATUS_BAR_VIEW_ID);
142 | if (fakeStatusBarView != null) {
143 | if (fakeStatusBarView.getVisibility() == View.GONE) {
144 | fakeStatusBarView.setVisibility(View.VISIBLE);
145 | }
146 | fakeStatusBarView.setBackgroundColor(color);
147 | } else {
148 | contentView.addView(createStatusBarView(activity, color));
149 | }
150 | setRootView(activity);
151 | }
152 |
153 | /**
154 | * 使状态栏半透明
155 | *
156 | * 适用于图片作为背景的界面,此时需要图片填充到状态栏
157 | *
158 | * @param activity 需要设置的activity
159 | */
160 | public static void setTranslucent(Activity activity) {
161 | setTranslucent(activity, DEFAULT_STATUS_BAR_ALPHA);
162 | }
163 |
164 | /**
165 | * 使状态栏半透明
166 | *
167 | * 适用于图片作为背景的界面,此时需要图片填充到状态栏
168 | *
169 | * @param activity 需要设置的activity
170 | * @param statusBarAlpha 状态栏透明度
171 | */
172 | public static void setTranslucent(Activity activity, int statusBarAlpha) {
173 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
174 | return;
175 | }
176 | setTransparent(activity);
177 | addTranslucentView(activity, statusBarAlpha);
178 | }
179 |
180 | /**
181 | * 针对根布局是 CoordinatorLayout, 使状态栏半透明
182 | *
183 | * 适用于图片作为背景的界面,此时需要图片填充到状态栏
184 | *
185 | * @param activity 需要设置的activity
186 | * @param statusBarAlpha 状态栏透明度
187 | */
188 | public static void setTranslucentForCoordinatorLayout(Activity activity, int statusBarAlpha) {
189 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
190 | return;
191 | }
192 | transparentStatusBar(activity);
193 | addTranslucentView(activity, statusBarAlpha);
194 | }
195 |
196 | /**
197 | * 设置状态栏全透明
198 | *
199 | * @param activity 需要设置的activity
200 | */
201 | public static void setTransparent(Activity activity) {
202 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
203 | return;
204 | }
205 | transparentStatusBar(activity);
206 | setRootView(activity);
207 | }
208 |
209 | /**
210 | * 使状态栏透明(5.0以上半透明效果,不建议使用)
211 | *
212 | * 适用于图片作为背景的界面,此时需要图片填充到状态栏
213 | *
214 | * @param activity 需要设置的activity
215 | */
216 | @Deprecated
217 | public static void setTranslucentDiff(Activity activity) {
218 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
219 | // 设置状态栏透明
220 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
221 | setRootView(activity);
222 | }
223 | }
224 |
225 | /**
226 | * 为DrawerLayout 布局设置状态栏变色
227 | *
228 | * @param activity 需要设置的activity
229 | * @param drawerLayout DrawerLayout
230 | * @param color 状态栏颜色值
231 | */
232 | public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
233 | setColorForDrawerLayout(activity, drawerLayout, color, DEFAULT_STATUS_BAR_ALPHA);
234 | }
235 |
236 | /**
237 | * 为DrawerLayout 布局设置状态栏颜色,纯色
238 | *
239 | * @param activity 需要设置的activity
240 | * @param drawerLayout DrawerLayout
241 | * @param color 状态栏颜色值
242 | */
243 | public static void setColorNoTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
244 | setColorForDrawerLayout(activity, drawerLayout, color, 0);
245 | }
246 |
247 | /**
248 | * 为DrawerLayout 布局设置状态栏变色
249 | *
250 | * @param activity 需要设置的activity
251 | * @param drawerLayout DrawerLayout
252 | * @param color 状态栏颜色值
253 | * @param statusBarAlpha 状态栏透明度
254 | */
255 | public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color,
256 | int statusBarAlpha) {
257 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
258 | return;
259 | }
260 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
261 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
262 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
263 | activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));
264 | } else {
265 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
266 | // 生成一个状态栏大小的矩形
267 | // 添加 statusBarView 到布局中
268 | ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
269 | View fakeStatusBarView = contentLayout.findViewById(FAKE_STATUS_BAR_VIEW_ID);
270 | if (fakeStatusBarView != null) {
271 | if (fakeStatusBarView.getVisibility() == View.GONE) {
272 | fakeStatusBarView.setVisibility(View.VISIBLE);
273 | }
274 | fakeStatusBarView.setBackgroundColor(color);
275 | } else {
276 | contentLayout.addView(createStatusBarView(activity, color), 0);
277 | }
278 | // 内容布局不是 LinearLayout 时,设置padding top
279 | if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
280 | contentLayout.getChildAt(1)
281 | .setPadding(contentLayout.getPaddingLeft(), getStatusBarHeight(activity) + contentLayout.getPaddingTop(),
282 | contentLayout.getPaddingRight(), contentLayout.getPaddingBottom());
283 | }
284 | // 设置属性
285 | setDrawerLayoutProperty(drawerLayout, contentLayout);
286 | addTranslucentView(activity, statusBarAlpha);
287 | }
288 |
289 | }
290 |
291 | /**
292 | * 设置 DrawerLayout 属性
293 | *
294 | * @param drawerLayout DrawerLayout
295 | * @param drawerLayoutContentLayout DrawerLayout 的内容布局
296 | */
297 | private static void setDrawerLayoutProperty(DrawerLayout drawerLayout, ViewGroup drawerLayoutContentLayout) {
298 | ViewGroup drawer = (ViewGroup) drawerLayout.getChildAt(1);
299 | drawerLayout.setFitsSystemWindows(false);
300 | drawerLayoutContentLayout.setFitsSystemWindows(false);
301 | drawerLayoutContentLayout.setClipToPadding(true);
302 | drawer.setFitsSystemWindows(false);
303 | }
304 |
305 | /**
306 | * 为DrawerLayout 布局设置状态栏变色(5.0以下无半透明效果,不建议使用)
307 | *
308 | * @param activity 需要设置的activity
309 | * @param drawerLayout DrawerLayout
310 | * @param color 状态栏颜色值
311 | */
312 | @Deprecated
313 | public static void setColorForDrawerLayoutDiff(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
314 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
315 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
316 | // 生成一个状态栏大小的矩形
317 | ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
318 | View fakeStatusBarView = contentLayout.findViewById(FAKE_STATUS_BAR_VIEW_ID);
319 | if (fakeStatusBarView != null) {
320 | if (fakeStatusBarView.getVisibility() == View.GONE) {
321 | fakeStatusBarView.setVisibility(View.VISIBLE);
322 | }
323 | fakeStatusBarView.setBackgroundColor(calculateStatusColor(color, DEFAULT_STATUS_BAR_ALPHA));
324 | } else {
325 | // 添加 statusBarView 到布局中
326 | contentLayout.addView(createStatusBarView(activity, color), 0);
327 | }
328 | // 内容布局不是 LinearLayout 时,设置padding top
329 | if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
330 | contentLayout.getChildAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0);
331 | }
332 | // 设置属性
333 | setDrawerLayoutProperty(drawerLayout, contentLayout);
334 | }
335 | }
336 |
337 | /**
338 | * 为 DrawerLayout 布局设置状态栏透明
339 | *
340 | * @param activity 需要设置的activity
341 | * @param drawerLayout DrawerLayout
342 | */
343 | public static void setTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout) {
344 | setTranslucentForDrawerLayout(activity, drawerLayout, DEFAULT_STATUS_BAR_ALPHA);
345 | }
346 |
347 | /**
348 | * 为 DrawerLayout 布局设置状态栏透明
349 | *
350 | * @param activity 需要设置的activity
351 | * @param drawerLayout DrawerLayout
352 | */
353 | public static void setTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, int statusBarAlpha) {
354 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
355 | return;
356 | }
357 | setTransparentForDrawerLayout(activity, drawerLayout);
358 | addTranslucentView(activity, statusBarAlpha);
359 | }
360 |
361 | /**
362 | * 为 DrawerLayout 布局设置状态栏透明
363 | *
364 | * @param activity 需要设置的activity
365 | * @param drawerLayout DrawerLayout
366 | */
367 | public static void setTransparentForDrawerLayout(Activity activity, DrawerLayout drawerLayout) {
368 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
369 | return;
370 | }
371 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
372 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
373 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
374 | activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
375 | } else {
376 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
377 | }
378 |
379 | ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
380 | // 内容布局不是 LinearLayout 时,设置padding top
381 | if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
382 | contentLayout.getChildAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0);
383 | }
384 |
385 | // 设置属性
386 | setDrawerLayoutProperty(drawerLayout, contentLayout);
387 | }
388 |
389 | /**
390 | * 为 DrawerLayout 布局设置状态栏透明(5.0以上半透明效果,不建议使用)
391 | *
392 | * @param activity 需要设置的activity
393 | * @param drawerLayout DrawerLayout
394 | */
395 | @Deprecated
396 | public static void setTranslucentForDrawerLayoutDiff(Activity activity, DrawerLayout drawerLayout) {
397 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
398 | // 设置状态栏透明
399 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
400 | // 设置内容布局属性
401 | ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
402 | contentLayout.setFitsSystemWindows(true);
403 | contentLayout.setClipToPadding(true);
404 | // 设置抽屉布局属性
405 | ViewGroup vg = (ViewGroup) drawerLayout.getChildAt(1);
406 | vg.setFitsSystemWindows(false);
407 | // 设置 DrawerLayout 属性
408 | drawerLayout.setFitsSystemWindows(false);
409 | }
410 | }
411 |
412 | /**
413 | * 为头部是 ImageView 的界面设置状态栏全透明
414 | *
415 | * @param activity 需要设置的activity
416 | * @param needOffsetView 需要向下偏移的 View
417 | */
418 | public static void setTransparentForImageView(Activity activity, View needOffsetView) {
419 | setTranslucentForImageView(activity, 0, needOffsetView);
420 | }
421 |
422 | /**
423 | * 为头部是 ImageView 的界面设置状态栏透明(使用默认透明度)
424 | *
425 | * @param activity 需要设置的activity
426 | * @param needOffsetView 需要向下偏移的 View
427 | */
428 | public static void setTranslucentForImageView(Activity activity, View needOffsetView) {
429 | setTranslucentForImageView(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView);
430 | }
431 |
432 | /**
433 | * 为头部是 ImageView 的界面设置状态栏透明
434 | *
435 | * @param activity 需要设置的activity
436 | * @param statusBarAlpha 状态栏透明度
437 | * @param needOffsetView 需要向下偏移的 View
438 | */
439 | public static void setTranslucentForImageView(Activity activity, int statusBarAlpha, View needOffsetView) {
440 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
441 | return;
442 | }
443 | setTransparentForWindow(activity);
444 | addTranslucentView(activity, statusBarAlpha);
445 | if (needOffsetView != null) {
446 | ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams();
447 | layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin + getStatusBarHeight(activity),
448 | layoutParams.rightMargin, layoutParams.bottomMargin);
449 | }
450 | }
451 |
452 | /**
453 | * 为 fragment 头部是 ImageView 的设置状态栏透明
454 | *
455 | * @param activity fragment 对应的 activity
456 | * @param needOffsetView 需要向下偏移的 View
457 | */
458 | public static void setTranslucentForImageViewInFragment(Activity activity, View needOffsetView) {
459 | setTranslucentForImageViewInFragment(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView);
460 | }
461 |
462 | /**
463 | * 为 fragment 头部是 ImageView 的设置状态栏透明
464 | *
465 | * @param activity fragment 对应的 activity
466 | * @param needOffsetView 需要向下偏移的 View
467 | */
468 | public static void setTransparentForImageViewInFragment(Activity activity, View needOffsetView) {
469 | setTranslucentForImageViewInFragment(activity, 0, needOffsetView);
470 | }
471 |
472 | /**
473 | * 为 fragment 头部是 ImageView 的设置状态栏透明
474 | *
475 | * @param activity fragment 对应的 activity
476 | * @param statusBarAlpha 状态栏透明度
477 | * @param needOffsetView 需要向下偏移的 View
478 | */
479 | public static void setTranslucentForImageViewInFragment(Activity activity, int statusBarAlpha, View needOffsetView) {
480 | setTranslucentForImageView(activity, statusBarAlpha, needOffsetView);
481 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
482 | clearPreviousSetting(activity);
483 | }
484 | }
485 |
486 | /**
487 | * 隐藏伪状态栏 View
488 | *
489 | * @param activity 调用的 Activity
490 | */
491 | public static void hideFakeStatusBarView(Activity activity) {
492 | ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
493 | View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID);
494 | if (fakeStatusBarView != null) {
495 | fakeStatusBarView.setVisibility(View.GONE);
496 | }
497 | View fakeTranslucentView = decorView.findViewById(FAKE_TRANSLUCENT_VIEW_ID);
498 | if (fakeTranslucentView != null) {
499 | fakeTranslucentView.setVisibility(View.GONE);
500 | }
501 | }
502 |
503 | ///////////////////////////////////////////////////////////////////////////////////
504 |
505 | @TargetApi(Build.VERSION_CODES.KITKAT)
506 | private static void clearPreviousSetting(Activity activity) {
507 | ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
508 | View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID);
509 | if (fakeStatusBarView != null) {
510 | decorView.removeView(fakeStatusBarView);
511 | ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
512 | rootView.setPadding(0, 0, 0, 0);
513 | }
514 | }
515 |
516 | /**
517 | * 添加半透明矩形条
518 | *
519 | * @param activity 需要设置的 activity
520 | * @param statusBarAlpha 透明值
521 | */
522 | private static void addTranslucentView(Activity activity, int statusBarAlpha) {
523 | ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
524 | View fakeTranslucentView = contentView.findViewById(FAKE_TRANSLUCENT_VIEW_ID);
525 | if (fakeTranslucentView != null) {
526 | if (fakeTranslucentView.getVisibility() == View.GONE) {
527 | fakeTranslucentView.setVisibility(View.VISIBLE);
528 | }
529 | fakeTranslucentView.setBackgroundColor(Color.argb(statusBarAlpha, 0, 0, 0));
530 | } else {
531 | contentView.addView(createTranslucentStatusBarView(activity, statusBarAlpha));
532 | }
533 | }
534 |
535 | /**
536 | * 生成一个和状态栏大小相同的彩色矩形条
537 | *
538 | * @param activity 需要设置的 activity
539 | * @param color 状态栏颜色值
540 | * @return 状态栏矩形条
541 | */
542 | private static StatusBarView createStatusBarView(Activity activity, @ColorInt int color) {
543 | return createStatusBarView(activity, color, 0);
544 | }
545 |
546 | /**
547 | * 生成一个和状态栏大小相同的半透明矩形条
548 | *
549 | * @param activity 需要设置的activity
550 | * @param color 状态栏颜色值
551 | * @param alpha 透明值
552 | * @return 状态栏矩形条
553 | */
554 | private static StatusBarView createStatusBarView(Activity activity, @ColorInt int color, int alpha) {
555 | // 绘制一个和状态栏一样高的矩形
556 | StatusBarView statusBarView = new StatusBarView(activity);
557 | LinearLayout.LayoutParams params =
558 | new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
559 | statusBarView.setLayoutParams(params);
560 | statusBarView.setBackgroundColor(calculateStatusColor(color, alpha));
561 | statusBarView.setId(FAKE_STATUS_BAR_VIEW_ID);
562 | return statusBarView;
563 | }
564 |
565 | /**
566 | * 设置根布局参数
567 | */
568 | private static void setRootView(Activity activity) {
569 | ViewGroup parent = (ViewGroup) activity.findViewById(android.R.id.content);
570 | for (int i = 0, count = parent.getChildCount(); i < count; i++) {
571 | View childView = parent.getChildAt(i);
572 | if (childView instanceof ViewGroup) {
573 | childView.setFitsSystemWindows(true);
574 | ((ViewGroup) childView).setClipToPadding(true);
575 | }
576 | }
577 | }
578 |
579 | /**
580 | * 设置透明
581 | */
582 | private static void setTransparentForWindow(Activity activity) {
583 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
584 | activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
585 | activity.getWindow()
586 | .getDecorView()
587 | .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
588 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
589 | activity.getWindow()
590 | .setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
591 | }
592 | }
593 |
594 | /**
595 | * 使状态栏透明
596 | */
597 | @TargetApi(Build.VERSION_CODES.KITKAT)
598 | private static void transparentStatusBar(Activity activity) {
599 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
600 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
601 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
602 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
603 | activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
604 | } else {
605 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
606 | }
607 | }
608 |
609 | /**
610 | * 创建半透明矩形 View
611 | *
612 | * @param alpha 透明值
613 | * @return 半透明 View
614 | */
615 | private static StatusBarView createTranslucentStatusBarView(Activity activity, int alpha) {
616 | // 绘制一个和状态栏一样高的矩形
617 | StatusBarView statusBarView = new StatusBarView(activity);
618 | LinearLayout.LayoutParams params =
619 | new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
620 | statusBarView.setLayoutParams(params);
621 | statusBarView.setBackgroundColor(Color.argb(alpha, 0, 0, 0));
622 | statusBarView.setId(FAKE_TRANSLUCENT_VIEW_ID);
623 | return statusBarView;
624 | }
625 |
626 | /**
627 | * 获取状态栏高度
628 | *
629 | * @param context context
630 | * @return 状态栏高度
631 | */
632 | private static int getStatusBarHeight(Context context) {
633 | // 获得状态栏高度
634 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
635 | return context.getResources().getDimensionPixelSize(resourceId);
636 | }
637 |
638 | /**
639 | * 计算状态栏颜色
640 | *
641 | * @param color color值
642 | * @param alpha alpha值
643 | * @return 最终的状态栏颜色
644 | */
645 | private static int calculateStatusColor(@ColorInt int color, int alpha) {
646 | if (alpha == 0) {
647 | return color;
648 | }
649 | float a = 1 - alpha / 255f;
650 | int red = color >> 16 & 0xff;
651 | int green = color >> 8 & 0xff;
652 | int blue = color & 0xff;
653 | red = (int) (red * a + 0.5);
654 | green = (int) (green * a + 0.5);
655 | blue = (int) (blue * a + 0.5);
656 | return 0xff << 24 | red << 16 | green << 8 | blue;
657 | }
658 |
659 | }
660 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/utils/TUtil.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.utils;
2 |
3 | import java.lang.reflect.ParameterizedType;
4 |
5 | /**
6 | * 类转换初始化
7 | */
8 | public class TUtil {
9 | public static T getT(Object o, int i) {
10 | try {
11 | return ((Class) ((ParameterizedType) (o.getClass()
12 | .getGenericSuperclass())).getActualTypeArguments()[i])
13 | .newInstance();
14 | } catch (InstantiationException e) {
15 | e.printStackTrace();
16 | } catch (IllegalAccessException e) {
17 | e.printStackTrace();
18 | } catch (ClassCastException e) {
19 | e.printStackTrace();
20 | }
21 | return null;
22 | }
23 |
24 | public static Class> forName(String className) {
25 | try {
26 | return Class.forName(className);
27 | } catch (ClassNotFoundException e) {
28 | e.printStackTrace();
29 | }
30 | return null;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/widget/CircleImageView.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.widget;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapShader;
7 | import android.graphics.Canvas;
8 | import android.graphics.Color;
9 | import android.graphics.Matrix;
10 | import android.graphics.Paint;
11 | import android.graphics.RectF;
12 | import android.graphics.Shader;
13 | import android.graphics.drawable.BitmapDrawable;
14 | import android.graphics.drawable.ColorDrawable;
15 | import android.graphics.drawable.Drawable;
16 | import android.util.AttributeSet;
17 | import android.widget.ImageView;
18 |
19 | import com.lvr.timeline.R;
20 |
21 | /**
22 | * Created by lvr on 2017/4/7.
23 | */
24 |
25 | public class CircleImageView extends ImageView {
26 | /**
27 | * 圆形头像默认,CENTER_CROP!=系统默认的CENTER_CROP;
28 | * 将图片等比例缩放,让图像的长边边与ImageView的边长度相同,短边不够的留空白,缩放后截取圆形部分进行显示。
29 | */
30 | private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
31 | /**
32 | * 图片的压缩质量
33 | * ALPHA_8就是Alpha由8位组成,------ALPHA_8 代表8位Alpha位图
34 | * ARGB_4444就是由4个4位组成即16位,------ARGB_4444 代表16位ARGB位图
35 | * ARGB_8888就是由4个8位组成即32位,------ARGB_8888 代表32位ARGB位图
36 | * RGB_565就是R为5位,G为6位,B为5位共16位,------ARGB_565 代表8位RGB位图
37 | */
38 | private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
39 | /**
40 | * 默认ColorDrawable的宽和高
41 | */
42 | private static final int COLORDRAWABLE_DIMENSION = 1;
43 | /**
44 | * 默认边框宽度
45 | */
46 | private static final int DEFAULT_BORDER_WIDTH = 0;
47 | /**
48 | * 默认边框颜色
49 | */
50 | private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
51 | /**
52 | * 画图片的矩形
53 | */
54 | private final RectF mDrawableRect = new RectF();
55 | /**
56 | * 画边框的矩形
57 | */
58 | private final RectF mBorderRect = new RectF();
59 | /**
60 | * 对图片进行缩放和移动的矩阵
61 | */
62 | private final Matrix mShaderMatrix = new Matrix();
63 | /**
64 | * 画图片的画笔
65 | */
66 | private final Paint mBitmapPaint = new Paint();
67 | /**
68 | * 画边框的画笔
69 | */
70 | private final Paint mBorderPaint = new Paint();
71 | /**
72 | * 默认边框颜色
73 | */
74 | private int mBorderColor = DEFAULT_BORDER_COLOR;
75 | /**
76 | * 默认边框宽度
77 | */
78 | private int mBorderWidth = DEFAULT_BORDER_WIDTH;
79 |
80 | private Bitmap mBitmap;
81 | /**
82 | * 产生一个画有一个位图的渲染器(Shader)
83 | */
84 | private BitmapShader mBitmapShader;
85 | /**
86 | * 图片的实际宽度
87 | */
88 | private int mBitmapWidth;
89 | /**
90 | * 图片实际高度
91 | */
92 | private int mBitmapHeight;
93 | /**
94 | * 图片半径
95 | */
96 | private float mDrawableRadius;
97 | /**
98 | * 边框半径
99 | */
100 | private float mBorderRadius;
101 | /**
102 | * 是否初始化准备好
103 | */
104 | private boolean mReady;
105 | /**
106 | * 内边距
107 | */
108 | private boolean mSetupPending;
109 |
110 | public CircleImageView(Context context) {
111 | super(context);
112 | }
113 |
114 | public CircleImageView(Context context, AttributeSet attrs) {
115 | this(context, attrs, 0);
116 | }
117 |
118 | public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
119 | super(context, attrs, defStyle);
120 | super.setScaleType(SCALE_TYPE);
121 | /**
122 | * 获取在xml中声明的属性
123 | */
124 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);//获取xml中的属性
125 |
126 | mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);
127 | mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
128 |
129 | a.recycle();
130 |
131 | mReady = true;
132 |
133 | if (mSetupPending) {
134 | setup();
135 | mSetupPending = false;
136 | }
137 | }
138 |
139 | @Override
140 | public ScaleType getScaleType() {
141 | return SCALE_TYPE;
142 | }
143 |
144 | @Override
145 | protected void onDraw(Canvas canvas) {
146 | if (getDrawable() == null) {
147 | return;
148 | }
149 | /**
150 | * 画圆形图片
151 | */
152 | canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
153 | /**
154 | * 画圆形边框
155 | */
156 | canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint);
157 | }
158 |
159 | @Override
160 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
161 | super.onSizeChanged(w, h, oldw, oldh);
162 | setup();
163 | }
164 |
165 | /**
166 | * 获取边框颜色
167 | *
168 | * @return
169 | */
170 | public int getBorderColor() {
171 | return mBorderColor;
172 | }
173 |
174 | /**
175 | * 设置边框颜色
176 | *
177 | * @param borderColor
178 | */
179 | public void setBorderColor(int borderColor) {
180 | if (borderColor == mBorderColor) {
181 | return;
182 | }
183 |
184 | mBorderColor = borderColor;
185 | mBorderPaint.setColor(mBorderColor);
186 | invalidate();
187 | }
188 |
189 | /**
190 | * 获取边框宽度
191 | *
192 | * @return
193 | */
194 | public int getBorderWidth() {
195 | return mBorderWidth;
196 | }
197 |
198 | /**
199 | * 设置边框宽度
200 | *
201 | * @param borderWidth
202 | */
203 | public void setBorderWidth(int borderWidth) {
204 | if (borderWidth == mBorderWidth) {
205 | return;
206 | }
207 |
208 | mBorderWidth = borderWidth;
209 | setup();
210 | }
211 |
212 | /**
213 | * 设置资源图片
214 | *
215 | * @param bm
216 | */
217 | @Override
218 | public void setImageBitmap(Bitmap bm) {
219 | super.setImageBitmap(bm);
220 | mBitmap = bm;
221 | setup();
222 | }
223 |
224 | /**
225 | * 设置资源图片
226 | *
227 | * @param drawable
228 | */
229 | @Override
230 | public void setImageDrawable(Drawable drawable) {
231 | super.setImageDrawable(drawable);
232 | mBitmap = getBitmapFromDrawable(drawable);
233 | setup();
234 | }
235 |
236 | /**
237 | * 设置资源id
238 | *
239 | * @param resId
240 | */
241 | @Override
242 | public void setImageResource(int resId) {
243 | super.setImageResource(resId);
244 | mBitmap = getBitmapFromDrawable(getDrawable());
245 | setup();
246 | }
247 |
248 | /**
249 | * 获取资源图片
250 | *
251 | * @param drawable
252 | * @return
253 | */
254 | private Bitmap getBitmapFromDrawable(Drawable drawable) {
255 | if (drawable == null) {
256 | return null;
257 | }
258 |
259 | if (drawable instanceof BitmapDrawable) {
260 | return ((BitmapDrawable) drawable).getBitmap();
261 | }
262 |
263 | try {
264 | Bitmap bitmap;
265 |
266 | if (drawable instanceof ColorDrawable) {
267 | bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
268 | } else {
269 | bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
270 | }
271 |
272 | Canvas canvas = new Canvas(bitmap);
273 | drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
274 | drawable.draw(canvas);
275 | return bitmap;
276 | } catch (OutOfMemoryError e) {
277 | return null;
278 | }
279 | }
280 |
281 | /**
282 | * 画圆形图的方法
283 | */
284 | private void setup() {
285 | if (!mReady) {
286 | mSetupPending = true;
287 | return;
288 | }
289 |
290 | if (mBitmap == null) {
291 | return;
292 | }
293 | /**
294 | *调用这个方法来产生一个画有一个位图的渲染器(Shader)。
295 | bitmap 在渲染器内使用的位图
296 | tileX The tiling mode for x to draw the bitmap in. 在位图上X方向花砖模式
297 | tileY The tiling mode for y to draw the bitmap in. 在位图上Y方向花砖模式
298 | TileMode:(一共有三种)
299 | CLAMP :如果渲染器超出原始边界范围,会复制范围内边缘染色。
300 | REPEAT :横向和纵向的重复渲染器图片,平铺。
301 | MIRROR :横向和纵向的重复渲染器图片,这个和REPEAT 重复方式不一样,他是以镜像方式平铺。
302 | */
303 | mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
304 | /**
305 | * 设置画圆形的画笔
306 | */
307 | mBitmapPaint.setAntiAlias(true);//设置抗锯齿
308 | mBitmapPaint.setShader(mBitmapShader);//绘制图形时的图形变换
309 |
310 | mBorderPaint.setStyle(Paint.Style.STROKE);
311 | mBorderPaint.setAntiAlias(true);
312 | mBorderPaint.setColor(mBorderColor);
313 | mBorderPaint.setStrokeWidth(mBorderWidth);
314 |
315 | mBitmapHeight = mBitmap.getHeight();
316 | mBitmapWidth = mBitmap.getWidth();
317 | /**
318 | * 设置边框矩形的坐标
319 | */
320 | mBorderRect.set(0, 0, getWidth(), getHeight());
321 | /**
322 | * 设置边框圆形的半径为图片的宽度和高度的一半的最大值
323 | */
324 | mBorderRadius = Math.max((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2);
325 | /**
326 | * 设置图片矩形的坐标
327 | */
328 | mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
329 | /**
330 | * 设置图片圆形的半径为图片的宽度和高度的一半的最大值
331 | */
332 | mDrawableRadius = Math.max(mDrawableRect.height() / 2, mDrawableRect.width() / 2);
333 |
334 | updateShaderMatrix();
335 | /**
336 | * 调用onDraw()方法进行绘画
337 | */
338 | invalidate();
339 | }
340 |
341 | /**
342 | * 更新位图渲染
343 | */
344 | private void updateShaderMatrix() {
345 | float scale;
346 | float dx = 0;
347 | float dy = 0;
348 | /**
349 | * 重置
350 | */
351 | mShaderMatrix.set(null);
352 | /**
353 | *计算缩放比,因为如果图片的尺寸超过屏幕,那么就会自动匹配到屏幕的尺寸去显示。
354 | * 确定移动的xy坐标
355 | *
356 | */
357 | if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
358 | scale = mDrawableRect.width() / (float) mBitmapWidth;
359 | dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
360 | } else {
361 | scale = mDrawableRect.height() / (float) mBitmapHeight;
362 | dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
363 | }
364 |
365 | mShaderMatrix.setScale(scale, scale);
366 | mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth);
367 | /**
368 | * 设置shader的本地矩阵
369 | */
370 | mBitmapShader.setLocalMatrix(mShaderMatrix);
371 | }
372 | }
373 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/widget/CircleTextView.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.util.AttributeSet;
8 | import android.widget.TextView;
9 |
10 | /**
11 | * Created by lvr on 2017/4/8.
12 | */
13 |
14 | public class CircleTextView extends TextView {
15 | private Paint mBgPaint;
16 |
17 | public CircleTextView(Context context) {
18 | super(context);
19 | init();
20 | }
21 |
22 |
23 | public CircleTextView(Context context, AttributeSet attrs, int defStyleAttr) {
24 | super(context, attrs, defStyleAttr);
25 | init();
26 | }
27 |
28 | public CircleTextView(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 | init();
31 | }
32 |
33 | private void init() {
34 | mBgPaint = new Paint();
35 | mBgPaint.setAntiAlias(true);
36 | mBgPaint.setColor(Color.WHITE);
37 | }
38 |
39 | @Override
40 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
41 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
42 | int measuredWidth = getMeasuredWidth();
43 | int measuredHeight = getMeasuredHeight();
44 | int max = Math.max(measuredWidth, measuredHeight);
45 | setMeasuredDimension(max, max);
46 | }
47 |
48 | @Override
49 | public void setBackgroundColor(int color) {
50 | mBgPaint.setColor(color);
51 | }
52 |
53 | @Override
54 | protected void onDraw(Canvas canvas) {
55 | canvas.drawCircle(getWidth()/2,getHeight()/2,Math.max(getWidth(),getHeight())/2,mBgPaint);
56 | super.onDraw(canvas);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/widget/ItemDragHelperCallback.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 咖枯
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 | package com.lvr.timeline.widget;
18 |
19 | import android.support.v7.widget.GridLayoutManager;
20 | import android.support.v7.widget.LinearLayoutManager;
21 | import android.support.v7.widget.RecyclerView;
22 | import android.support.v7.widget.StaggeredGridLayoutManager;
23 | import android.support.v7.widget.helper.ItemTouchHelper;
24 |
25 | public class ItemDragHelperCallback extends ItemTouchHelper.Callback {
26 | private OnItemMoveListener mOnItemMoveListener;
27 | private OnItemSwipeListener mOnItemSwipeListener;
28 |
29 | public interface OnItemMoveListener {
30 | void onItemMove(int fromPosition, int toPosition);
31 | }
32 | public interface OnItemSwipeListener {
33 | void onItemSwipe(int position);
34 | }
35 |
36 | //相当于 set 设置监听 传入TimeAdapter中的OnItemMoveListener对象
37 | public ItemDragHelperCallback(OnItemMoveListener onItemMoveListener,OnItemSwipeListener onItemSwipeListener) {
38 | mOnItemMoveListener = onItemMoveListener;
39 | mOnItemSwipeListener = onItemSwipeListener;
40 | }
41 | //返回true 允许拖拽
42 | @Override
43 | public boolean isLongPressDragEnabled() {
44 | return true;
45 | }
46 | //返回true 允许滑动
47 | @Override
48 | public boolean isItemViewSwipeEnabled() {
49 | return true;
50 | }
51 |
52 | @Override
53 | public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
54 | //根据recyclerView的布局,进行设置拖拽的方向
55 | int dragFlags = setDragFlags(recyclerView);
56 | //不允许进行滑动
57 | int swipeFlags = setSwipeFlags(recyclerView);
58 | return makeMovementFlags(dragFlags, swipeFlags);
59 | }
60 |
61 | private int setSwipeFlags(RecyclerView recyclerView) {
62 | int swipeFlags = 0;
63 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
64 | if (layoutManager instanceof LinearLayoutManager ) {
65 | swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
66 | }
67 | return swipeFlags;
68 | }
69 |
70 | private int setDragFlags(RecyclerView recyclerView) {
71 | int dragFlags;
72 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
73 | if (layoutManager instanceof GridLayoutManager || layoutManager instanceof StaggeredGridLayoutManager) {
74 | dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
75 | } else {
76 | dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
77 | }
78 | return dragFlags;
79 | }
80 |
81 | @Override
82 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
83 | mOnItemMoveListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
84 | return false;
85 |
86 | }
87 |
88 |
89 | @Override
90 | public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
91 | super.clearView(recyclerView, viewHolder);
92 |
93 | }
94 |
95 | @Override
96 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
97 |
98 | mOnItemSwipeListener.onItemSwipe(viewHolder.getAdapterPosition());
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/java/com/lvr/timeline/widget/StatusBarView.java:
--------------------------------------------------------------------------------
1 | package com.lvr.timeline.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 |
7 | /**
8 | * Created by Jaeger on 16/6/8.
9 | *
10 | * Email: chjie.jaeger@gmail.com
11 | * GitHub: https://github.com/laobie
12 | */
13 | public class StatusBarView extends View {
14 | public StatusBarView(Context context, AttributeSet attrs) {
15 | super(context, attrs);
16 | }
17 |
18 | public StatusBarView(Context context) {
19 | super(context);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/about.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/calender.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/calender.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/change.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/change.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/fb_plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/fb_plus.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/habbit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/habbit.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/ic_empty_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/ic_empty_picture.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/ic_image_loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/ic_image_loading.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/ic_search_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/ic_search_menu.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/item_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/item_delete.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/mn_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/mn_back.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/mn_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/mn_edit.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/mn_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/mn_right.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/moddy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/moddy.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/nav_header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/nav_header.jpg
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/nav_photo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/nav_photo.jpg
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/out.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/progress.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/select_time_online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/select_time_online.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/select_today.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/select_today.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/select_yesterday.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/select_yesterday.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/sorry_hint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/sorry_hint.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/thing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/thing.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/time_online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/time_online.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/today.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/today.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/toux2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/toux2.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable-xxhdpi/yesterday.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/drawable-xxhdpi/yesterday.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable/select_button_countdown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable/select_button_today.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/drawable/select_button_yesterday.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/layout/activity_edit.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
15 |
21 |
22 |
31 |
32 |
33 |
39 |
40 |
41 |
50 |
51 |
52 |
57 |
58 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/layout/activity_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
12 |
13 |
20 |
21 |
26 |
27 |
34 |
35 |
40 |
41 |
42 |
50 |
51 |
60 |
61 |
71 |
72 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
95 |
96 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/layout/app_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/layout/dialog_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
17 |
18 |
27 |
30 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/layout/fragment_countdown.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/layout/fragment_today.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/layout/fragment_yesterday.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/layout/item_line.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
17 |
18 |
19 |
23 |
24 |
30 |
31 |
41 |
42 |
43 |
54 |
55 |
65 |
66 |
71 |
72 |
79 |
80 |
89 |
90 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
109 |
110 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/layout/view_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
18 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/menu/menu_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/menu/menu_toolabr.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/mipmap-xxhdpi/time.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/mipmap-xxhdpi/time.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/values-w820dp/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #2196f3
4 | #303F9F
5 | #FF4081
6 | #e57a00
7 | #ffffff
8 | #E7E7E7
9 | #CCCCCC
10 | #FF000000
11 | #FFFFFFFF
12 | #deffffff
13 | #FFFF0000
14 | #FF00FF00
15 | #FFF0F0F0
16 | #c9000000
17 | #00000000
18 | #929292
19 | #33CC99
20 | #EBEBEB
21 | #1296db
22 | #90EE90
23 | #8DB6CD
24 | #8FBC8F
25 | #9ACD32
26 | #A020F0
27 | #8B814C
28 | #87CEFA
29 | #8B2500
30 | #8470FF
31 | #7D26CD
32 | #7CFC00
33 | #7CCD7C
34 | #68838B
35 | #4F94CD
36 | #DB7093
37 | #DC143C
38 | #CDCD00
39 | #CD96CD
40 | #EE3A8C
41 | #FF7F24
42 | #0D0D0D
43 | #008B00
44 | #0000CD
45 | #6B6B6B
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TimeLine
3 |
4 |
--------------------------------------------------------------------------------
/Timeline/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Timeline/app/src/test/java/com/lvr/timeline/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.lvr.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() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/Timeline/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 | //这里配置 apt 供butterknife使用
10 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | classpath "io.realm:realm-gradle-plugin:3.0.0"
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | maven { url "https://jitpack.io" }
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
27 |
--------------------------------------------------------------------------------
/Timeline/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/Timeline/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRH1993/TimeLine/1c6adbba28633a2c0347538e704ef7bae8b273d1/Timeline/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Timeline/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
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-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/Timeline/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/Timeline/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/Timeline/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------