animations;
42 | private ViewGroup mDecorView;
43 | private int[] mDecorViewLocation;
44 |
45 |
46 | public OverlapRecycleView(Context context) {
47 | super(context);
48 | initView();
49 | }
50 |
51 | public OverlapRecycleView(Context context, @Nullable AttributeSet attrs) {
52 | super(context, attrs);
53 | initView();
54 | }
55 |
56 | public OverlapRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
57 | super(context, attrs, defStyle);
58 | initView();
59 | }
60 |
61 | private void initView() {
62 | // setLayoutManager(new OverlapManager(getContext()));
63 |
64 | downY = downX = -1;
65 | mDecorViewLocation = new int[2];
66 | mDecorView = (FrameLayout) ((Activity) getContext()).getWindow().getDecorView();
67 |
68 |
69 | mDecorView.getLocationOnScreen(mDecorViewLocation);
70 | animations = new ArrayList<>();
71 | }
72 |
73 | @Override
74 | public boolean onTouchEvent(MotionEvent e) {
75 |
76 | if (getChildCount() == 0) {
77 | return super.onTouchEvent(e);
78 | }
79 |
80 | if (downX == -1 || downY == -1) {
81 | downX = e.getX();
82 | downY = e.getY();
83 | }
84 |
85 |
86 | ViewGroup topView = (ViewGroup) getChildAt(getChildCount() - 1);
87 | TextView at = (TextView) topView.getChildAt(0);
88 | JLog.i(getChildCount() + "------" + at.getText());
89 |
90 |
91 | float x = topView.getX();
92 | float y = topView.getY();
93 | if (childTop == 0 || childLeft == 0) {
94 | childTop = topView.getTop();
95 | childLeft = topView.getLeft();
96 | }
97 |
98 | switch (e.getAction()) {
99 | case MotionEvent.ACTION_DOWN:
100 | downX = e.getX();
101 | downY = e.getY();
102 |
103 | break;
104 | case MotionEvent.ACTION_MOVE:
105 | float currentX = e.getX();
106 | float currentY = e.getY();
107 | topView.setX(x + currentX - downX);
108 | topView.setY(y + currentY - downY);
109 | nextChildScale(getChildCount() - 2, getCurrentScaleByTopView(topView));
110 | downX = currentX;
111 | downY = currentY;
112 | break;
113 |
114 | case MotionEvent.ACTION_UP:
115 |
116 | default:
117 | upAction(topView);
118 | downY = downX = -1;
119 | break;
120 | }
121 |
122 |
123 | return super.onTouchEvent(e);
124 | }
125 |
126 | private float caculateExitY(float x1, float y1, float x2, float y2, float x3) {
127 | return (y2 - y1) * (x3 - x1) / (x2 - x1) + y1;
128 | }
129 |
130 | private void upAction(final View topView) {
131 | float targtX = childLeft;
132 | float targtY = childTop;
133 | final boolean isChange;
134 | TimeInterpolator interpolator = new LinearInterpolator();
135 | View view = topView;
136 | if (getCurrentScaleByTopView(topView) < 1) {
137 | interpolator = new OvershootInterpolator();
138 | isChange = true;
139 | } else {
140 | //获取一个镜像
141 | view = getMirror(topView);
142 | isChange = false;
143 | if (topView.getX() > childLeft) {
144 | targtX = Apputils.getScreenWidth(getContext()) * 2;
145 | } else {
146 | targtX = -topView.getWidth() - Apputils.getScreenWidth(getContext());
147 | }
148 |
149 |
150 | float offsetX = getX() - mDecorView.getX();
151 | float offsetY = getY() - mDecorView.getY();
152 | targtY = caculateExitY(childLeft + offsetX, childTop + offsetY, view.getX(), view.getY(), targtX);
153 | }
154 |
155 |
156 | final View finalView = view;
157 | finalView.animate().setDuration(500).x(targtX).y(targtY).setInterpolator(interpolator).setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
158 | @Override
159 | public void onAnimationUpdate(ValueAnimator animation) {
160 |
161 | if (isChange) {
162 | nextChildScale(getChildCount() - 2, getCurrentScaleByTopView(topView));
163 | }
164 | }
165 | }).setListener(new AnimatorListenerAdapter() {
166 |
167 | @Override
168 | public void onAnimationEnd(Animator animation) {
169 | super.onAnimationEnd(animation);
170 | if (!isChange) {
171 | mDecorView.removeView(finalView);
172 | }
173 | }
174 | });
175 | }
176 |
177 |
178 | private ImageView getMirror(View view) {
179 | view.setDrawingCacheEnabled(true);
180 | Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
181 | ImageView img = new ImageView(getContext());
182 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(bitmap.getWidth(), bitmap.getHeight());
183 | img.setImageBitmap(bitmap);
184 | view.setDrawingCacheEnabled(false);
185 | int[] imgs = new int[2];
186 | view.getLocationOnScreen(imgs);
187 | img.setX(imgs[0] - mDecorViewLocation[0]);
188 | img.setY(imgs[1] - mDecorViewLocation[1]);
189 | view.setVisibility(GONE);
190 | delTopView();
191 | mDecorView.addView(img, params);
192 | return img;
193 | }
194 |
195 | private void delTopView() {
196 |
197 |
198 | if (getAdapter().getItemCount() < 1) {
199 | return;
200 | }
201 | List bodyLists = ((BasicAdapter) getAdapter()).getBodyLists();
202 | Object o = bodyLists.get(bodyLists.size()- 1);
203 | bodyLists.remove(o);
204 | // bodyLists.add(0,o);
205 | getAdapter().notifyDataSetChanged();
206 | }
207 |
208 | private float getCurrentScaleByTopView(View topView) {
209 | float h = Math.abs((topView.getX() - childLeft) / topView.getWidth());
210 | float v = Math.abs((topView.getY() - childTop) / topView.getHeight());
211 | return (float) (0.9 + Math.max(h, v) / 4);
212 | }
213 |
214 | private void nextChildScale(int index, float scale) {
215 | if (scale >= 1) {
216 | scale = 1;
217 | }
218 | if (index < 0) {
219 | return;
220 | }
221 | View child = getChildAt(index);
222 |
223 | child.setScaleX(scale);
224 | child.setScaleY(scale);
225 | int gap = Apputils.dip2px(getContext(), 5);
226 | float off = child.getHeight() * (1 - scale) / 2;
227 | child.setTranslationY(gap + off);
228 |
229 | if (index < 1) {
230 | return;
231 | }
232 | View thirldView = getChildAt(index - 1);
233 | thirldView.setScaleY(scale - 0.1f);
234 | thirldView.setScaleX(scale - 0.1f);
235 | off = thirldView.getHeight() * (1 - scale + 0.1f) / 2;
236 | thirldView.setTranslationY(off + gap * 2);
237 | }
238 |
239 |
240 | public float getChildLeft() {
241 | return childLeft;
242 | }
243 |
244 | public float getChildTop() {
245 | return childTop;
246 | }
247 |
248 |
249 | }
250 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/RefrushRecycleView.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.Nullable;
5 | import android.util.AttributeSet;
6 | import android.view.ViewGroup;
7 | import android.widget.LinearLayout;
8 |
9 | import com.sang.viewfractory.utils.Apputils;
10 | import com.sang.viewfractory.utils.DeviceUtils;
11 | import com.sang.viewfractory.utils.JLog;
12 | import com.sang.viewfractory.view.RefrushLinearLayout;
13 |
14 | import em.sang.com.allrecycleview.adapter.BasicAdapter;
15 | import em.sang.com.allrecycleview.holder.SimpleHolder;
16 |
17 |
18 | /**
19 | * Description:上拉刷新和下拉加载控件,默认没有上拉加载
20 | *
21 | * Author:桑小年
22 | * Data:2016/12/1 14:42
23 | */
24 | public class RefrushRecycleView extends BasicRefrushRecycleView {
25 |
26 | @Override
27 | public void setAdapter(Adapter adapter) {
28 | super.setAdapter(adapter);
29 | }
30 |
31 | public RefrushRecycleView(Context context) {
32 | super(context);
33 |
34 | }
35 |
36 | public RefrushRecycleView(Context context, @Nullable AttributeSet attrs) {
37 | super(context, attrs);
38 |
39 | }
40 |
41 | public RefrushRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
42 | super(context, attrs, defStyle);
43 |
44 | }
45 |
46 | @Override
47 | protected void initView(Context context, @Nullable AttributeSet attrs, int defStyle) {
48 | super.initView(context, attrs, defStyle);
49 | downY = -1;
50 | topView = new RefrushLinearLayout(context);
51 | boomView = new RefrushLinearLayout(context);
52 | setStyle(style);
53 | mearchTop = Apputils.getWidthAndHeight(topView)[1];
54 | mearchBoom = Apputils.getWidthAndHeight(boomView)[1];
55 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
56 | params.height = (int) min;
57 | topView.setLayoutParams(params);
58 |
59 | LinearLayout.LayoutParams boom = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
60 | boom.height = (int) min;
61 | boomView.setLayoutParams(boom);
62 | hasTop = true;
63 | hasBoom = false;
64 |
65 |
66 | }
67 |
68 |
69 | @Override
70 | protected int upChangeStateByHeight(int height) {
71 | int state;
72 | if (height > mearchTop) {
73 | state = LOAD_BEFOR;
74 | } else {
75 | state = LOAD_OVER;
76 |
77 | }
78 | return state;
79 | }
80 |
81 | @Override
82 | protected boolean isDownChangeStateByHeight() {
83 | if (style == STYLE_PULL) {
84 | return super.isDownChangeStateByHeight();
85 | } else {
86 | return false;
87 | }
88 | }
89 |
90 | private long lastTime;
91 |
92 | @Override
93 | public void onScrolled(int dx, int dy) {
94 | super.onScrolled(dx, dy);
95 | if (downstate != LOADING_DOWN) {
96 | synchronized (RefrushRecycleView.class) {
97 | if (dy > DeviceUtils.getMinTouchSlop(getContext()) && style == STYLE_SLIPE) {
98 | if (!isFirst() && isLast() && downstate != LOADING_DOWN) {
99 | long l = System.currentTimeMillis() - lastTime;
100 | if (l > 1000) {
101 | JLog.i("-------------被叫用了---------------------");
102 | lastTime = System.currentTimeMillis();
103 | downRefrushState(LOADING_DOWN);
104 | }
105 | }
106 | }
107 | }
108 | }
109 | }
110 |
111 |
112 | @Override
113 | protected float getDownHeightByState(int upState) {
114 | if (style == STYLE_PULL) {
115 | return super.getDownHeightByState(upState);
116 | } else {
117 | return mearchBoom;
118 | }
119 | }
120 |
121 | @Override
122 | protected int downChangeStateByHeight(int height) {
123 | int state;
124 | if (height > mearchBoom) {
125 | state = LOAD_DOWN_BEFOR;
126 | } else {
127 | state = LOAD_DOWN_OVER;
128 |
129 | }
130 | return state;
131 | }
132 |
133 | @Override
134 | protected int getNextState(int refrush_state) {
135 | int load = refrush_state;
136 | switch (refrush_state) {
137 | case LOAD_DOWN_BEFOR:
138 | if (isNoTouch) {
139 | load = LOADING_DOWN;
140 | }
141 | break;
142 | case LOAD_BEFOR:
143 | if (isNoTouch) {
144 | load = LOADING;
145 | }
146 | break;
147 | case LOAD_SUCCESS:
148 | case LOAD_FAIL:
149 | load = LOAD_OVER;
150 | break;
151 | case LOADING:
152 | case LOADING_DOWN:
153 | case LOAD_OVER:
154 | case LOAD_DOWN_OVER:
155 | break;
156 |
157 | case LOAD_DOWN_SUCCESS:
158 | case LOAD_DOWN_FAIL:
159 | if (style != STYLE_SLIPE) {
160 | load = LOAD_DOWN_OVER;
161 | }
162 | break;
163 | }
164 | return load;
165 | }
166 |
167 | @Override
168 | public void addUpDataItem(Adapter adapter) {
169 | if (adapter instanceof BasicAdapter) {
170 | BasicAdapter basicAdapter = (BasicAdapter) adapter;
171 | if (getHasBoom()) {
172 | basicAdapter.addBoom(new SimpleHolder(boomView));
173 | }
174 | if (getHasTop()) {
175 | basicAdapter.addTop(new SimpleHolder(topView));
176 | }
177 | }
178 | }
179 |
180 |
181 | @Override
182 | public boolean canDrag() {
183 | return isLast() || isFirst();
184 | }
185 |
186 |
187 | }
188 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/adapter/BasicAdapter.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.GridLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.support.v7.widget.StaggeredGridLayoutManager;
7 | import android.view.ViewGroup;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | import em.sang.com.allrecycleview.holder.CustomHolder;
13 | import em.sang.com.allrecycleview.holder.CustomPeakHolder;
14 | import em.sang.com.allrecycleview.inter.CustomAdapterListener;
15 |
16 |
17 | /**
18 | * Description:
19 | *
20 | * Author: 桑小年
21 | *
22 | * Data: 2016/11/7 16:43
23 | */
24 | public class BasicAdapter extends RecyclerView.Adapter {
25 | protected List lists = new ArrayList<>();
26 | public int itemID;
27 | protected List heards = new ArrayList();
28 | protected List foots = new ArrayList();
29 | protected List tops = new ArrayList();
30 | protected List booms = new ArrayList<>();
31 | public CustomAdapterListener listener;
32 |
33 | public Context context;
34 |
35 | public static final int BODY = 100000;
36 | public static final int TOP = 100001;
37 | public static final int FOOT = 100002;
38 |
39 |
40 |
41 |
42 | protected BasicAdapter(Context context, List lists, int itemID, CustomAdapterListener listener) {
43 | if (lists != null) {
44 | this.lists = lists;
45 | }
46 | this.itemID = itemID;
47 | this.listener = listener;
48 | this.context = context;
49 | }
50 |
51 | @Override
52 | public int getItemViewType(int position) {
53 | if (listener != null) {
54 | return listener.getItemTypeByPosition();
55 | }
56 | return 0;
57 | }
58 |
59 | @Override
60 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
61 | CustomHolder holder = null;
62 | if (listener != null) {
63 | holder = listener.getHolderByViewType(context, lists, viewType);
64 | }
65 | return holder;
66 | }
67 |
68 | @Override
69 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
70 | if (listener != null) {
71 | listener.onBindViewHolder(holder, position);
72 | }
73 | }
74 |
75 | @Override
76 | public int getItemCount() {
77 | return lists.size() + heards.size() + foots.size() + tops.size() + booms.size();
78 | }
79 |
80 |
81 | /**
82 | * 添加头布局
83 | *
84 | * @param heardHolder 头布局的holder
85 | */
86 | public void addHead(CustomPeakHolder heardHolder) {
87 | heards.add(heardHolder);
88 | }
89 |
90 | /**
91 | * 添加头布局
92 | *
93 | * @param heardHolder 头布局的holder
94 | */
95 | public void addHead(int index, CustomPeakHolder heardHolder) {
96 |
97 | heards.add(index, heardHolder);
98 | }
99 |
100 | /**
101 | * 添加脚布局
102 | *
103 | * @param footHolder
104 | */
105 | public void addFoots(CustomPeakHolder footHolder) {
106 | foots.add(footHolder);
107 | }
108 |
109 | /**
110 | * 添加顶部刷新局
111 | *
112 | * @param topHolder
113 | */
114 | public void addTop(CustomPeakHolder topHolder) {
115 | tops.clear();
116 | tops.add(topHolder);
117 | }
118 |
119 |
120 |
121 | /**
122 | * 添加顶部刷新局
123 | *
124 | * @param boomHolder
125 | */
126 | public void addBoom(CustomPeakHolder boomHolder) {
127 | booms.clear();
128 | booms.add(boomHolder);
129 | }
130 |
131 |
132 |
133 | public void onAttachedToRecyclerView(RecyclerView recyclerView) {
134 | super.onAttachedToRecyclerView(recyclerView);
135 | RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
136 | if (manager instanceof GridLayoutManager) {
137 | final GridLayoutManager gridManager = ((GridLayoutManager) manager);
138 | gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
139 | @Override
140 | public int getSpanSize(int position) {
141 | return (isHeader(position) || isFooter(position))
142 | ? gridManager.getSpanCount() : 1;
143 | }
144 |
145 |
146 | });
147 | }
148 | }
149 |
150 | @Override
151 | public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
152 | super.onViewAttachedToWindow(holder);
153 | ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
154 | if (lp != null
155 | && lp instanceof StaggeredGridLayoutManager.LayoutParams
156 | && (isHeader(holder.getLayoutPosition()) || isFooter(holder.getLayoutPosition()))) {
157 | StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
158 | p.setFullSpan(true);
159 | }
160 | }
161 |
162 |
163 | public boolean isFooter(int position) {
164 | return position >= heards.size() + lists.size() + tops.size() && position < tops.size() + heards.size() + lists.size() + foots.size() + booms.size();
165 | }
166 |
167 | public boolean isHeader(int position) {
168 | return position >= 0 && position < heards.size() + tops.size();
169 | }
170 |
171 | public List getBodyLists() {
172 | return lists;
173 | }
174 |
175 | public void upData(List list) {
176 | this.lists = list;
177 | notifyDataSetChanged();
178 |
179 | }
180 |
181 | public List getHeards(){
182 | return heards;
183 | }
184 |
185 | public List getFoots() {
186 | return foots;
187 | }
188 |
189 | public List getTops() {
190 | return tops;
191 | }
192 |
193 | public List getBooms() {
194 | return booms;
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/adapter/CustomBasicAdapter.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.ViewGroup;
6 |
7 | import java.util.List;
8 |
9 | import em.sang.com.allrecycleview.holder.CustomHolder;
10 | import em.sang.com.allrecycleview.holder.CustomPeakHolder;
11 | import em.sang.com.allrecycleview.inter.DefaultAdapterViewLisenter;
12 |
13 |
14 | /**
15 | * Description:
16 | *
17 | * @Author:桑小年
18 | * @Data:2016/11/7 16:43
19 | */
20 | public class CustomBasicAdapter extends BasicAdapter {
21 | protected CustomBasicAdapter(Context context, List lists, int itemID, DefaultAdapterViewLisenter lisenter) {
22 | super(context, lists, itemID, lisenter);
23 | }
24 |
25 | @Override
26 | public int getItemViewType(int position) {
27 | if (listener != null) {
28 | return listener.getItemTypeByPosition();
29 | }
30 | return 0;
31 | }
32 |
33 | @Override
34 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
35 | CustomHolder holder = null;
36 | if (listener!=null) {
37 | holder = listener.getHolderByViewType(context, lists, itemID);
38 | }
39 | return holder;
40 | }
41 |
42 | @Override
43 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
44 | if (position < heards.size()) {
45 | ((CustomHolder) holder).initView(position,lists,context);
46 |
47 | } else if (position < heards.size() + lists.size()) {
48 | ((CustomPeakHolder) holder).initView(position - heards.size(),context);
49 |
50 | } else {
51 | ((CustomPeakHolder) holder).initView(position - heards.size() - lists.size(),context);
52 | }
53 |
54 | }
55 |
56 |
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/adapter/DefaultAdapter.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.ViewGroup;
6 |
7 | import java.util.List;
8 |
9 | import em.sang.com.allrecycleview.holder.CustomHolder;
10 | import em.sang.com.allrecycleview.holder.CustomPeakHolder;
11 | import em.sang.com.allrecycleview.inter.DefaultAdapterViewLisenter;
12 |
13 |
14 | /**
15 | * Description:带有头布局的Adapter
16 | *
17 | * @Author:桑小年
18 | * @Data:2016/11/8 9:50
19 | */
20 | public class DefaultAdapter extends CustomBasicAdapter {
21 |
22 |
23 | public DefaultAdapter(Context context, List lists, int itemID, DefaultAdapterViewLisenter lisenter) {
24 | super(context, lists, itemID, lisenter);
25 | }
26 |
27 | @Override
28 | public int getItemViewType(int position) {
29 | if (position < tops.size()) {
30 | return TOP;
31 | } else if (position < heards.size()+tops.size()) {
32 | return position;
33 | } else if (position < heards.size() + lists.size() + tops.size()) {
34 | return BODY;
35 | } else if (position extends DefaultAdapter {
23 |
24 | private int refrushPosition=0;
25 |
26 | public RefrushAdapter(Context context, List lists, int itemID, DefaultAdapterViewLisenter lisenter) {
27 | super(context, lists, itemID, lisenter);
28 | }
29 |
30 | public void setRefrushPosition(int position){
31 | this.refrushPosition=position;
32 | }
33 |
34 | @Override
35 | public int getItemViewType(int position) {
36 | if (position == refrushPosition&&tops.size()>0) {
37 | return TOP;
38 | } else if (position < heards.size()+tops.size()) {
39 | if (positionrefrushPosition&&tops.size()>0){
42 | return position;
43 | }else {
44 | return position;
45 | }
46 | } else if (position < heards.size() + lists.size() + tops.size()) {
47 | return BODY;
48 | } else if (position0) {
61 | id=position;
62 | ((CustomPeakHolder) holder).initView(id, context);
63 | } else if (position < heards.size()+tops.size()) {
64 | id= position-tops.size();
65 | if (positionrefrushPosition&&tops.size()>0){
68 | id= position-1;
69 | }
70 | ((CustomPeakHolder) holder).initView(id, context);
71 | } else if (position < heards.size() + lists.size() + tops.size()) {
72 | id=position-heards.size()-tops.size();
73 | ((CustomHolder) holder).initView(id,lists, context);
74 | } else if (positionrefrushPosition&&tops.size()>0) {
96 | holder = (RecyclerView.ViewHolder) heards.get(viewType - tops.size());
97 | }else {
98 | holder = (RecyclerView.ViewHolder) heards.get(viewType);
99 | }
100 | } else if (viewType == BODY) {
101 | holder= ((DefaultAdapterViewLisenter) listener).getBodyHolder(context, lists, itemID);
102 | } else if (viewType= childCount)// 如果是最后一列,则不需要绘制右边
126 | return true;
127 | }
128 | }
129 | return false;
130 | }
131 |
132 | private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
133 | int childCount) {
134 |
135 | LayoutManager layoutManager = parent.getLayoutManager();
136 | if (layoutManager instanceof GridLayoutManager) {
137 | childCount = childCount - (childCount ) % spanCount;
138 | if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
139 | return true;
140 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
141 | int orientation = ((StaggeredGridLayoutManager) layoutManager)
142 | .getOrientation();
143 | // StaggeredGridLayoutManager 且纵向滚动
144 | if (orientation == StaggeredGridLayoutManager.VERTICAL) {
145 | childCount = childCount - childCount % spanCount;
146 | // 如果是最后一行,则不需要绘制底部
147 | if (pos >= childCount)
148 | return true;
149 | } else
150 | // StaggeredGridLayoutManager 且横向滚动
151 | {
152 | // 如果是最后一行,则不需要绘制底部
153 | if ((pos + 1) % spanCount == 0) {
154 | return true;
155 | }
156 | }
157 | }
158 | return false;
159 | }
160 |
161 | @Override
162 | public void getItemOffsets(Rect outRect, int itemPosition,
163 | RecyclerView parent) {
164 | int spanCount = getSpanCount(parent);
165 | int childCount = parent.getAdapter().getItemCount();
166 | int heardSize = 0;
167 | if (parent.getAdapter() instanceof BasicAdapter) {
168 | BasicAdapter adapter = (BasicAdapter) parent.getAdapter();
169 | heardSize = adapter.getTops().size() + adapter.getHeards().size();
170 | }
171 | if (isLastRaw(parent, itemPosition-heardSize, spanCount, childCount))// 如果是最后一行,则不需要绘制底部
172 | {
173 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
174 | } else if (isLastColum(parent, itemPosition-heardSize, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
175 | {
176 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
177 | } else {
178 | outRect.set(0, 0, mDivider.getIntrinsicWidth(),
179 | mDivider.getIntrinsicHeight());
180 | }
181 | }
182 | }
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/cutline/RecycleViewDivider.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.cutline;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.graphics.Rect;
8 | import android.graphics.drawable.Drawable;
9 | import android.support.v4.content.ContextCompat;
10 | import android.support.v7.widget.LinearLayoutManager;
11 | import android.support.v7.widget.RecyclerView;
12 | import android.view.View;
13 |
14 | public class RecycleViewDivider extends RecyclerView.ItemDecoration {
15 |
16 | private Paint mPaint;
17 | private Drawable mDivider;
18 | private int mDividerHeight = 2;//分割线高度,默认为1px
19 | private int mOrientation;//列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL
20 | private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
21 |
22 | /**
23 | * 默认分割线:高度为2px,颜色为灰色
24 | *
25 | * @param context
26 | * @param orientation 列表方向
27 | */
28 | public RecycleViewDivider(Context context, int orientation) {
29 | if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
30 | throw new IllegalArgumentException("请输入正确的参数!");
31 | }
32 | mOrientation = orientation;
33 |
34 | final TypedArray a = context.obtainStyledAttributes(ATTRS);
35 | mDivider = a.getDrawable(0);
36 |
37 | a.recycle();
38 | }
39 |
40 | /**
41 | * 自定义分割线
42 | *
43 | * @param context
44 | * @param orientation 列表方向
45 | * @param drawableId 分割线图片
46 | */
47 | public RecycleViewDivider(Context context, int orientation, int drawableId) {
48 | this(context, orientation);
49 | mDivider = ContextCompat.getDrawable(context, drawableId);
50 |
51 | mDividerHeight = mDivider.getIntrinsicHeight();
52 | }
53 |
54 | /**
55 | * 自定义分割线
56 | *
57 | * @param context
58 | * @param orientation 列表方向
59 | * @param dividerHeight 分割线高度
60 | * @param dividerColor 分割线颜色
61 | */
62 | public RecycleViewDivider(Context context, int orientation, int dividerHeight, int dividerColor) {
63 | this(context, orientation);
64 | mDividerHeight = dividerHeight;
65 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
66 | mPaint.setColor(dividerColor);
67 | mPaint.setStyle(Paint.Style.FILL);
68 | }
69 |
70 |
71 | //获取分割线尺寸
72 | @Override
73 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
74 | super.getItemOffsets(outRect, view, parent, state);
75 | outRect.set(0, 0, 0, mDividerHeight);
76 | }
77 |
78 | //绘制分割线
79 | @Override
80 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
81 | super.onDraw(c, parent, state);
82 |
83 |
84 | if (mOrientation == LinearLayoutManager.VERTICAL) {
85 | drawVertical(c, parent);
86 | } else {
87 | drawHorizontal(c, parent);
88 | }
89 | }
90 |
91 | //绘制横向 item 分割线
92 | private void drawHorizontal(Canvas canvas, RecyclerView parent) {
93 | final int left = parent.getPaddingLeft();
94 | final int right = parent.getMeasuredWidth() - parent.getPaddingRight();
95 | final int childSize = parent.getChildCount();
96 | for (int i = 0; i < childSize; i++) {
97 | final View child = parent.getChildAt(i);
98 | RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
99 | final int top = child.getBottom() + layoutParams.bottomMargin;
100 | final int bottom = top + mDividerHeight;
101 | if (mDivider != null) {
102 | mDivider.setBounds(left, top, right, bottom);
103 | mDivider.draw(canvas);
104 | }
105 | if (mPaint != null) {
106 | canvas.drawRect(left, top, right, bottom, mPaint);
107 | }
108 | }
109 | }
110 |
111 | //绘制纵向 item 分割线
112 | private void drawVertical(Canvas canvas, RecyclerView parent) {
113 | final int top = parent.getPaddingTop();
114 | final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();
115 | final int childSize = parent.getChildCount();
116 | for (int i = 0; i < childSize; i++) {
117 | final View child = parent.getChildAt(i);
118 | RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
119 | final int left = child.getRight() + layoutParams.rightMargin;
120 | final int right = left + mDividerHeight;
121 | if (mDivider != null) {
122 | mDivider.setBounds(left, top, right, bottom);
123 | mDivider.draw(canvas);
124 | }
125 | if (mPaint != null) {
126 | canvas.drawRect(left, top, right, bottom, mPaint);
127 | }
128 | }
129 | }
130 | }
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/holder/CustomHolder.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.holder;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 |
8 | import java.util.List;
9 |
10 | import em.sang.com.allrecycleview.listener.OnToolsItemClickListener;
11 |
12 | /**
13 | * Description:
14 | *
15 | * @Author:桑小年
16 | * @Data:2016/11/7 16:46
17 | */
18 | public class CustomHolder extends RecyclerView.ViewHolder {
19 |
20 |
21 | public Context context;
22 | public View itemView;
23 | protected List datas;
24 | protected int itemID;
25 | public OnToolsItemClickListener listener;
26 | public void setOnTOnToolsItemClickListener(OnToolsItemClickListener listener){
27 | this.listener=listener;
28 | }
29 |
30 |
31 | public CustomHolder(View itemView) {
32 | super(itemView);
33 | }
34 |
35 | public CustomHolder(List datas, View itemView ){
36 | this(itemView);
37 | this.datas = datas;
38 | this.itemView = itemView;
39 |
40 | }
41 |
42 | public CustomHolder(Context context, List lists, int itemID) {
43 | this(lists,LayoutInflater.from(context).inflate(itemID,null));
44 | this.context =context;
45 | this.itemID=itemID;
46 | }
47 |
48 | /**
49 | * body中使用的初始化方法
50 | * @param position
51 | * @param datas
52 | * @param context
53 | */
54 | public void initView(int position,List datas,Context context) {
55 |
56 | }
57 |
58 |
59 |
60 |
61 | /**
62 | * 获取跟布局
63 | * @return
64 | */
65 | public View getItemView(){
66 | return itemView;
67 | }
68 |
69 | public Context getContext() {
70 | return context;
71 | }
72 |
73 | public List getDatas() {
74 | return datas;
75 | }
76 |
77 | public int getItemID() {
78 | return itemID;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/holder/CustomPeakHolder.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.holder;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Description:头布局和叫布局使用的类
12 | *
13 | * @Author:桑小年
14 | * @Data:2016/11/7 16:46
15 | */
16 | public class CustomPeakHolder extends CustomHolder {
17 |
18 |
19 | public CustomPeakHolder(View itemView) {
20 | super(itemView);
21 | }
22 |
23 | public CustomPeakHolder(List datas, View itemView) {
24 | super(datas, itemView);
25 | }
26 |
27 | public CustomPeakHolder(Context context, List lists, int itemID) {
28 | super(context, lists, itemID);
29 | }
30 |
31 | /**
32 | * 叫布局和头布局使用的方法
33 | * @param position
34 | * @param context
35 | */
36 | public void initView(int position,Context context) {
37 |
38 | }
39 |
40 |
41 | /**
42 | * 获取跟布局
43 | * @return
44 | */
45 | public View getItemView(){
46 | return itemView;
47 | }
48 |
49 |
50 |
51 |
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/holder/FootHolder.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.holder;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Description:
10 | *
11 | * @Author:桑小年
12 | * @Data:2016/11/8 11:58
13 | */
14 | public class FootHolder extends CustomPeakHolder {
15 |
16 |
17 | public FootHolder(View itemView) {
18 | super(itemView);
19 | }
20 |
21 | public FootHolder(List datas, View itemView) {
22 | super(datas, itemView);
23 | }
24 |
25 | public FootHolder(Context context, List lists, int itemID) {
26 | super(context, lists, itemID);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/holder/HeardHolder.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.holder;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 |
6 | import java.util.List;
7 |
8 | import static android.R.attr.data;
9 |
10 | /**
11 | * Description:
12 | *
13 | * @Author:桑小年
14 | * @Data:2016/11/8 11:58
15 | */
16 | public class HeardHolder extends CustomPeakHolder {
17 | public HeardHolder(View itemView) {
18 | super(itemView);
19 | }
20 |
21 | public HeardHolder(List datas, View itemView) {
22 | super(datas, itemView);
23 | }
24 |
25 | public HeardHolder(Context context, List lists, int itemID) {
26 | super(context, lists, itemID);
27 | }
28 |
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/holder/SimpleHolder.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.holder;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 |
7 | /**
8 | * Description:
9 | *
10 | * @Author:桑小年
11 | * @Data:2016/12/2 11:46
12 | */
13 | public class SimpleHolder extends CustomPeakHolder {
14 | public SimpleHolder(View itemView) {
15 | super(itemView);
16 | }
17 | public SimpleHolder(Context context,int itemId) {
18 | super(LayoutInflater.from(context).inflate(itemId,null));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/inter/BodyInitListener.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.inter;
2 |
3 | import android.content.Context;
4 |
5 | import java.util.List;
6 |
7 | import em.sang.com.allrecycleview.holder.CustomHolder;
8 |
9 | public interface BodyInitListener {
10 |
11 | public CustomHolder getHolderByViewType(Context context, List lists, int itemID);
12 | }
13 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/inter/CustomAdapterListener.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.inter;
2 |
3 |
4 | import android.content.Context;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.View;
7 |
8 | import java.util.List;
9 |
10 | import em.sang.com.allrecycleview.holder.CustomHolder;
11 |
12 | public interface CustomAdapterListener extends BodyInitListener{
13 |
14 | void initView(T data,View itemView);
15 |
16 | /**
17 | * 根据position获取itemType
18 | * @return itemType
19 | */
20 | int getItemTypeByPosition();
21 |
22 | /**
23 | * 根据类型获取相应的ViewHolder
24 | * @param context 上下文
25 | * @param lists 数据集合
26 | * @param itemID 布局ID
27 | * @return
28 | */
29 | CustomHolder getHolderByViewType(Context context, List lists, int itemID);
30 |
31 | /**
32 | * 绑定holder
33 | * @param holder
34 | * @param position
35 | */
36 | void onBindViewHolder(RecyclerView.ViewHolder holder, int position);
37 | }
38 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/inter/DefaultAdapterViewLisenter.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.inter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 |
7 | import java.util.List;
8 |
9 | import em.sang.com.allrecycleview.holder.CustomHolder;
10 | import em.sang.com.allrecycleview.holder.CustomPeakHolder;
11 |
12 | /**
13 | * Description:
14 | *
15 | * @Author:桑小年
16 | * @Data:2016/11/8 16:10
17 | */
18 | public class DefaultAdapterViewLisenter implements CustomAdapterListener {
19 | @Override
20 | public void initView(T data, View itemView) {
21 |
22 | }
23 |
24 | @Override
25 | public int getItemTypeByPosition() {
26 | return 0;
27 | }
28 |
29 |
30 | @Override
31 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
32 |
33 | }
34 |
35 | /**
36 | * 获取头布局holder
37 | * @param context 上下文
38 | * @param position 位置
39 | * @return holder
40 | */
41 | public CustomPeakHolder getHeardHolder(Context context, int position){return null;}
42 | /**
43 | * 获取普通布局holder
44 | * @param context 上下文
45 | * @param lists 数据
46 | * @param itemID 布局ID
47 | * @return holder
48 | */
49 | public CustomHolder getBodyHolder(Context context, List lists, int itemID){return null;}
50 | /**
51 | * 获取脚局holder
52 | * @param context 上下文
53 | * @param position 脚布局位置,从0开始
54 | * @return holder
55 | */
56 | public CustomHolder getFootdHolder(Context context, int position){return null;}
57 |
58 | @Override
59 | public CustomHolder getHolderByViewType(Context context, List lists, int itemID) {
60 | return null;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/inter/DefaultRefrushListener.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.inter;
2 |
3 | /**
4 | * Description:
5 | *
6 | * @Author:桑小年
7 | * @Data:2016/12/6 16:55
8 | */
9 | public class DefaultRefrushListener implements RefrushListener {
10 | @Override
11 | public void onLoading() {
12 | }
13 |
14 | @Override
15 | public void onLoadDowning() {
16 |
17 | }
18 |
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/inter/OverlapListener.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.inter;
2 |
3 |
4 | public interface OverlapListener {
5 |
6 | void remove();
7 | }
8 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/inter/RefrushListener.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.inter;
2 |
3 |
4 | public interface RefrushListener {
5 | /**
6 | * 下拉刷新
7 | */
8 | void onLoading();
9 |
10 | /**
11 | * 下拉加载
12 | */
13 | void onLoadDowning();
14 | }
15 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/layoutmanager/OverlapManager.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.layoutmanager;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.LinearLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 |
9 | import com.sang.viewfractory.utils.Apputils;
10 |
11 |
12 | /**
13 | * Description:
14 | *
15 | * @ Author :桑小年
16 | * @ Data :2016/12/22 15:52
17 | */
18 | public class OverlapManager extends LinearLayoutManager {
19 |
20 | private int offSet;
21 |
22 | public OverlapManager(Context context) {
23 | super(context);
24 | initView(context);
25 | }
26 |
27 | public OverlapManager(Context context, int orientation, boolean reverseLayout) {
28 | super(context, orientation, reverseLayout);
29 | initView(context);
30 | }
31 |
32 | public OverlapManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
33 | super(context, attrs, defStyleAttr, defStyleRes);
34 | initView(context);
35 | }
36 |
37 | private void initView(Context context) {
38 | offSet = Apputils.dip2px(context, 5);
39 | }
40 |
41 | @Override
42 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
43 | super.onLayoutChildren(recycler, state);
44 | detachAndScrapAttachedViews(recycler);
45 | int childCount = getItemCount();
46 | for (int i = 0; i < childCount; i++) {
47 | View child = recycler.getViewForPosition(i);
48 | measureChildWithMargins(child, 0, 0);
49 | int childWidth = getDecoratedMeasuredWidth(child);
50 | int childHeight = getDecoratedMeasuredHeight(child);
51 | int startX = (getWidth() - childWidth) / 2;
52 | int startY = (getHeight() - childHeight) / 2;
53 |
54 | if (i < childCount - 1) {
55 | child.setScaleX(0.8f);
56 | child.setScaleY(0.8f);
57 | }
58 | addView(child);
59 | layoutDecorated(child, startX, startY, startX + childWidth, startY + childHeight);
60 | if (i == childCount - 1) {
61 | child.setTranslationY(0);
62 | } else if (i == childCount - 2) {
63 | child.setScaleX(0.9f);
64 | child.setScaleY(0.9f);
65 | child.setTranslationY(childHeight * 0.1f / 2 + offSet);
66 | } else if (i == childCount - 3) {
67 | child.setScaleX(0.8f);
68 | child.setScaleY(0.8f);
69 | child.setTranslationY(childHeight * 0.2f / 2 + offSet * 2);
70 | }
71 |
72 |
73 | }
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/java/em/sang/com/allrecycleview/listener/OnToolsItemClickListener.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview.listener;
2 |
3 |
4 | public interface OnToolsItemClickListener {
5 |
6 | void onItemClick(int position, T item);
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/res/layout/heard_refrush.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
--------------------------------------------------------------------------------
/allrecycleview/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AllRecycleView
3 | 没有更多数据了
4 | 没有数据
5 |
6 |
--------------------------------------------------------------------------------
/allrecycleview/src/test/java/em/sang/com/allrecycleview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package em.sang.com.allrecycleview;
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 | }
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.3"
6 | defaultConfig {
7 | applicationId "com.xiaonian.sang.alibehaver"
8 | minSdkVersion 21
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.3.1'
28 | compile 'com.android.support.constraint:constraint-layout:1.0.1'
29 | testCompile 'junit:junit:4.12'
30 | compile 'com.android.support:design:26.0.0-alpha1'
31 | compile project(':allrecycleview')
32 | }
33 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\workSoft\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/xiaonian/sang/alibehaver/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.xiaonian.sang.alibehaver;
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.xiaonian.sang.alibehaver", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaonian/sang/alibehaver/CustomBehavior.java:
--------------------------------------------------------------------------------
1 | package com.xiaonian.sang.alibehaver;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.content.Context;
5 | import android.support.design.widget.CoordinatorLayout;
6 | import android.support.v4.view.ViewCompat;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.RelativeLayout;
11 |
12 |
13 | import java.lang.ref.WeakReference;
14 |
15 | import em.sang.com.allrecycleview.BasicRefrushRecycleView;
16 |
17 | /**
18 | * Description:用于首页,模仿支付宝效果
19 | *
20 | * @Author:桑小年
21 | * @Data:2016/12/28 11:53
22 | */
23 | public class CustomBehavior extends CoordinatorLayout.Behavior {
24 |
25 |
26 | private WeakReference dependentView;
27 | private WeakReference childeView;
28 | private boolean isScroll;
29 | private boolean isExpand;
30 | private int heardSize = -1;
31 | private int minHeard = -1;
32 |
33 | public CustomBehavior(Context context, AttributeSet attrs) {
34 | super(context, attrs);
35 |
36 | }
37 |
38 | @Override
39 | public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
40 | if (child != null) {
41 | childeView = new WeakReference(child);
42 | }
43 | if (dependency != null && dependency instanceof RelativeLayout) {
44 | dependentView = new WeakReference<>(dependency);
45 | return true;
46 | }
47 | return super.layoutDependsOn(parent, child, dependency);
48 | }
49 |
50 | @Override
51 | public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
52 |
53 |
54 | child.layout(0, 0, parent.getWidth(), (parent.getHeight() - dependentView.get().getHeight()));
55 | if (heardSize == -1) {
56 | heardSize = dependentView.get().getHeight();
57 | minHeard = dependentView.get().findViewById(R.id.rl_icon).getHeight();
58 | child.setTranslationY(heardSize);
59 | }
60 |
61 | return true;
62 |
63 | }
64 |
65 | @Override
66 | public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
67 | View view = dependentView.get();
68 |
69 | float translationY = child.getTranslationY();
70 |
71 | float min = minHeard*1.0f/heardSize;
72 | float pro = (translationY) / heardSize;
73 | View child1 = view.findViewById(R.id.ll);
74 | child1.setPivotY(0);
75 | child1.setPivotX(0);
76 | View titleView = dependentView.get().findViewById(R.id.rl_icon);
77 | titleView.setPivotY(0);
78 | titleView.setPivotX(0);
79 | titleView.setAlpha(1 - pro);
80 | if (pro<=min+0.1){
81 | titleView.setAlpha(1);
82 | }
83 | if (pro>0.95){
84 | titleView.setVisibility(View.GONE);
85 | }else {
86 | titleView.setVisibility(View.VISIBLE);
87 |
88 | }
89 | if (pro >= min && pro <= 1) {
90 |
91 | child1.setAlpha(pro);
92 | if (pro < 0.7) {
93 | child1.setVisibility(View.GONE);
94 | } else {
95 | child1.setVisibility(View.VISIBLE);
96 | }
97 |
98 | return true;
99 | }
100 |
101 | return super.onDependentViewChanged(parent, child, dependency);
102 | }
103 |
104 | @Override
105 | public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
106 |
107 | return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
108 | }
109 |
110 | @Override
111 | public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
112 | clearAnimotor();
113 | isScroll = false;
114 | }
115 |
116 | @Override
117 | public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
118 | View view = dependentView.get();
119 | ViewGroup.LayoutParams params = view.getLayoutParams();
120 | int height = (int) child.getTranslationY();
121 | if (dy > 0 && height > minHeard) {
122 | if (height <= heardSize) {
123 | int h = height - dy;
124 | int H = (h < minHeard) ? minHeard : h;
125 | params.height = H;
126 | view.setLayoutParams(params);
127 | child.setTranslationY(H);
128 | consumed[1] = dy;
129 | }
130 |
131 |
132 | }
133 |
134 |
135 | }
136 |
137 | @Override
138 | public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
139 | if (dyUnconsumed > 0) {
140 | return;
141 | }
142 | View view = dependentView.get();
143 | ViewGroup.LayoutParams params = view.getLayoutParams();
144 | int height = (int) child.getTranslationY();
145 | if (dyUnconsumed < 0&¶ms!=null) {
146 | int h = height - dyUnconsumed;
147 |
148 | if (h >= 0 &&h<= heardSize) {
149 | params.height = h;
150 | view.setLayoutParams(params);
151 | child.setTranslationY(h);
152 | if (child instanceof BasicRefrushRecycleView){
153 | BasicRefrushRecycleView recycleView = (BasicRefrushRecycleView) child;
154 | recycleView.setViewHeight(recycleView.getEndView(),0);
155 | }
156 | }
157 |
158 | }
159 | }
160 |
161 | @Override
162 | public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY) {
163 | return onStopDrag(child, velocityY);
164 |
165 | }
166 |
167 | private boolean onStopDrag(View child, float velocityY) {
168 | int height = dependentView.get().getHeight();
169 | if (height>minHeard){
170 | return true;
171 | }else {
172 | return false;
173 | }
174 |
175 | }
176 |
177 |
178 | @Override
179 | public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) {
180 | return true;
181 | }
182 |
183 |
184 | @Override
185 | public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
186 |
187 | int height = dependentView.get().getHeight();
188 | float translationY = childeView.get().getTranslationY();
189 | if (translationY > height) {
190 | isExpand = true;
191 | } else {
192 | isExpand = false;
193 | }
194 |
195 | if (isExpand) {
196 | float pro = ((translationY - height) * 1.0f / heardSize);
197 | creatExpendAnimator(translationY, height, (int) (500 * pro));
198 | }
199 |
200 |
201 | if (!isScroll && height > minHeard && height < heardSize) {
202 | childeView.get().setScrollY(0);
203 | if (height < 0.7 * heardSize) {//上滑
204 | float pro = (height - minHeard) * 1.0f / (heardSize - minHeard);
205 | creatAnimation(height, minHeard, (int) (500 * pro));
206 | } else {//下滑
207 | float pro = (heardSize - height) * 1.0f / (heardSize - minHeard);
208 | creatAnimation(height, heardSize, (int) (500 * pro));
209 | }
210 | isScroll = true;
211 | }
212 |
213 |
214 | }
215 |
216 |
217 | private ValueAnimator animator;
218 |
219 | private void creatAnimation(float start, float end, int duration) {
220 | clearAnimotor();
221 | animator = ValueAnimator.ofFloat(start, end);
222 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
223 | @Override
224 | public void onAnimationUpdate(ValueAnimator animation) {
225 | float value = (float) animation.getAnimatedValue();
226 | View view = dependentView.get();
227 | ViewGroup.LayoutParams params = view.getLayoutParams();
228 | params.height = (int) value;
229 | view.setLayoutParams(params);
230 | childeView.get().setTranslationY(value);
231 |
232 | }
233 | });
234 | animator.setDuration(duration);
235 | animator.start();
236 |
237 |
238 | }
239 |
240 | private void creatExpendAnimator(float start, float end, int duration) {
241 | clearAnimotor();
242 | animator = ValueAnimator.ofFloat(start, end);
243 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
244 | @Override
245 | public void onAnimationUpdate(ValueAnimator animation) {
246 | float value = (float) animation.getAnimatedValue();
247 | // View view = dependentView.get();
248 | // ViewGroup.LayoutParams params = view.getLayoutParams();
249 | // params.height = (int) value;
250 | // view.setLayoutParams(params);
251 | childeView.get().setTranslationY(value);
252 |
253 | }
254 | });
255 | animator.setDuration(duration);
256 | animator.start();
257 | }
258 |
259 |
260 | private void clearAnimotor() {
261 | if (animator != null) {
262 | animator.cancel();
263 | }
264 |
265 |
266 | isScroll = false;
267 | }
268 |
269 | }
270 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaonian/sang/alibehaver/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.xiaonian.sang.alibehaver;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.os.SystemClock;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.os.Bundle;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.widget.TextView;
10 |
11 | import com.sang.viewfractory.utils.ToastUtil;
12 | import com.xiaonian.sang.alibehaver.bean.GrideBean;
13 | import com.xiaonian.sang.alibehaver.holder.GrideHolder;
14 | import com.xiaonian.sang.alibehaver.holder.HomeCarouselHolder;
15 | import com.xiaonian.sang.alibehaver.holder.ItemHolder;
16 |
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | import em.sang.com.allrecycleview.RefrushRecycleView;
21 | import em.sang.com.allrecycleview.adapter.RefrushAdapter;
22 | import em.sang.com.allrecycleview.holder.CustomHolder;
23 | import em.sang.com.allrecycleview.inter.DefaultAdapterViewLisenter;
24 | import em.sang.com.allrecycleview.inter.DefaultRefrushListener;
25 | import em.sang.com.allrecycleview.listener.OnToolsItemClickListener;
26 |
27 | import static android.drm.DrmStore.Playback.STOP;
28 | import static java.lang.reflect.Modifier.NATIVE;
29 |
30 | public class MainActivity extends AppCompatActivity implements OnToolsItemClickListener {
31 |
32 | private RefrushRecycleView refrushRecycleView;
33 | private RefrushAdapter adapter;
34 | private List lists;
35 | private GrideHolder holder_up;
36 | private HomeCarouselHolder carouselHolder;
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_main);
42 | ToastUtil.init(this);
43 | initView();
44 | }
45 |
46 | private void initView() {
47 | refrushRecycleView = (RefrushRecycleView) findViewById(R.id.rc_home);
48 | lists=new ArrayList<>();
49 | for (int i = 0; i < 20; i++) {
50 | lists.add("ITEM"+i);
51 | }
52 |
53 | adapter = new RefrushAdapter<>(this, lists, R.layout.item, new DefaultAdapterViewLisenter() {
54 | @Override
55 | public CustomHolder getBodyHolder(Context context, List lists, int itemID) {
56 | return new ItemHolder( context, lists, itemID);
57 | }
58 | });
59 |
60 |
61 | //显示下拉刷新
62 | refrushRecycleView.setHasTop(true);
63 | refrushRecycleView.setRefrushListener(new DefaultRefrushListener() {
64 | @Override
65 | public void onLoading() {
66 | super.onLoading();
67 | new Thread(new Runnable() {
68 | @Override
69 | public void run() {
70 | SystemClock.sleep(1000);
71 | refrushRecycleView.post(new Runnable() {
72 | @Override
73 | public void run() {
74 | refrushRecycleView.loadSuccess();
75 | }
76 | });
77 |
78 | }
79 | }).start();
80 |
81 | }
82 | });
83 | /**
84 | * 设置下拉刷新位置
85 | */
86 | adapter.setRefrushPosition(1);
87 |
88 | //上侧九宫格
89 |
90 | List UP = new ArrayList<>();
91 | UP.add(new GrideBean(getString(R.string.phone), R.mipmap.phone_recharge));
92 | UP.add(new GrideBean(getString(R.string.life_recharge), R.mipmap.life_recharge));
93 | UP.add(new GrideBean(getString(R.string.traffic), R.mipmap.phone_recharge));
94 | UP.add(new GrideBean(getString(R.string.tick), R.mipmap.life_recharge));
95 | UP.add(new GrideBean(getString(R.string.game_recharge), R.mipmap.phone_recharge));
96 | UP.add(new GrideBean(getString(R.string.gas_recharge), R.mipmap.life_recharge));
97 | UP.add(new GrideBean(getString(R.string.lottery), R.mipmap.phone_recharge));
98 | UP.add(new GrideBean(getString(R.string.gongyi), R.mipmap.life_recharge));
99 | UP.add(new GrideBean(getString(R.string.share_media), R.mipmap.phone_recharge));
100 | UP.add(new GrideBean(getString(R.string.credit_payment), R.mipmap.life_recharge));
101 | UP.add(new GrideBean(getString(R.string.train), R.mipmap.phone_recharge));
102 |
103 | holder_up = new GrideHolder(this, UP, R.layout.item);
104 | holder_up.setOnTOnToolsItemClickListener(this);
105 | adapter.addHead(holder_up);
106 |
107 |
108 | List list = new ArrayList<>();
109 | list.add(new GrideBean("", R.mipmap.home_banner1));
110 | list.add(new GrideBean("", R.mipmap.home_banner2));
111 | list.add(new GrideBean("", R.mipmap.home_banner3));
112 | list.add(new GrideBean("", R.mipmap.home_banner4));
113 | list.add(new GrideBean("", R.mipmap.home_banner5));
114 |
115 | //中间广告条
116 | carouselHolder = new HomeCarouselHolder(this, list, R.layout.item_home_carousel);
117 | adapter.addHead(carouselHolder);
118 |
119 |
120 | LinearLayoutManager manager = new LinearLayoutManager(this);
121 | manager.setOrientation(LinearLayoutManager.VERTICAL);
122 | refrushRecycleView.setLayoutManager(manager);
123 | refrushRecycleView.setAdapter(adapter);
124 | }
125 |
126 |
127 | @Override
128 | public void onItemClick(int position, GrideBean item) {
129 | ToastUtil.showTextToast(item.title);
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaonian/sang/alibehaver/bean/GrideBean.java:
--------------------------------------------------------------------------------
1 | package com.xiaonian.sang.alibehaver.bean;
2 |
3 |
4 | /**
5 | * 是时候撸点真正的代码了!!!
6 | *
7 | * 创建人:桑小年
8 | * 日期: 2017/6/2.
9 | *
10 | * 功能描述:用于在九宫格时候使用的bean,两个变量分别代表文字和图片
11 | */
12 |
13 | public class GrideBean {
14 | public String title;
15 | public int imgId;
16 |
17 |
18 | public GrideBean(String title, int imgId) {
19 | this.title = title;
20 | this.imgId = imgId;
21 | }
22 |
23 |
24 | public GrideBean() {
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaonian/sang/alibehaver/holder/GrideHolder.java:
--------------------------------------------------------------------------------
1 | package com.xiaonian.sang.alibehaver.holder;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.support.v4.content.ContextCompat;
6 | import android.support.v7.widget.GridLayoutManager;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.view.View;
10 | import android.widget.TextView;
11 |
12 |
13 | import com.xiaonian.sang.alibehaver.R;
14 | import com.xiaonian.sang.alibehaver.bean.GrideBean;
15 |
16 | import java.util.List;
17 |
18 | import em.sang.com.allrecycleview.adapter.DefaultAdapter;
19 | import em.sang.com.allrecycleview.holder.CustomHolder;
20 | import em.sang.com.allrecycleview.holder.HeardHolder;
21 | import em.sang.com.allrecycleview.inter.DefaultAdapterViewLisenter;
22 |
23 | /**
24 | * 是时候撸点真正的代码了!!!
25 | *
26 | * 创建人:桑小年
27 | * 日期: 2017/6/2.
28 | *
29 | * 功能描述:
30 | */
31 |
32 | public class GrideHolder extends HeardHolder {
33 |
34 |
35 | public GrideHolder(View itemView) {
36 | super(itemView);
37 | }
38 |
39 | public GrideHolder(List datas, View itemView) {
40 | super(datas, itemView);
41 | }
42 |
43 | public GrideHolder(Context context, List lists, int itemID) {
44 | super(context, lists, R.layout.recycleview_gride);
45 | this.itemID = itemID;
46 | }
47 |
48 | int span = 4;
49 |
50 | public void setSpan(int span) {
51 | this.span = span;
52 | }
53 |
54 | @Override
55 | public void initView(int position, Context context) {
56 | RecyclerView view = (RecyclerView) itemView.findViewById(R.id.rc_gv);
57 | GridLayoutManager manager = new GridLayoutManager(context, span);
58 | manager.setOrientation(LinearLayoutManager.VERTICAL);
59 | view.setLayoutManager(manager);
60 |
61 | view.setAdapter(new DefaultAdapter(context, getDatas(), getItemID(), new DefaultAdapterViewLisenter() {
62 | @Override
63 | public CustomHolder getBodyHolder(Context context, List lists, int itemID) {
64 | return new CustomHolder(context, lists, itemID) {
65 | @Override
66 | public void initView(final int position, List datas, Context context) {
67 | final T data = datas.get(position);
68 | initItemView(itemView,data);
69 | itemView.setOnClickListener(new View.OnClickListener() {
70 | @Override
71 | public void onClick(View v) {
72 | if (GrideHolder.this.listener != null) {
73 | GrideHolder.this.listener.onItemClick(position, data);
74 | }
75 | }
76 | });
77 | }
78 | };
79 | }
80 | }));
81 |
82 | }
83 |
84 | public void initItemView(View itemView,T data){
85 | if (data instanceof GrideBean) {
86 | GrideBean bean = (GrideBean) data;
87 | TextView view = (TextView) itemView.findViewById(R.id.tv);
88 | if (bean.title != null) {
89 | view.setText(bean.title);
90 | }
91 | if (bean.imgId > 0) {
92 | Drawable drawable = ContextCompat.getDrawable(context, bean.imgId);
93 | drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
94 | view.setCompoundDrawables(null, drawable, null, null);
95 | }
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaonian/sang/alibehaver/holder/HomeCarouselHolder.java:
--------------------------------------------------------------------------------
1 | package com.xiaonian.sang.alibehaver.holder;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Message;
6 | import android.support.v4.view.PagerAdapter;
7 | import android.support.v4.view.ViewPager;
8 | import android.view.MotionEvent;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.ImageView;
12 | import android.widget.LinearLayout;
13 |
14 | import com.sang.viewfractory.utils.Apputils;
15 | import com.xiaonian.sang.alibehaver.R;
16 | import com.xiaonian.sang.alibehaver.bean.GrideBean;
17 |
18 | import java.util.List;
19 |
20 | import em.sang.com.allrecycleview.holder.CustomPeakHolder;
21 |
22 | /**
23 | * Description:首页轮播图
24 | *
25 | * @Author:桑小年
26 | * @Data:2017/1/3 11:17
27 | */
28 | public class HomeCarouselHolder extends CustomPeakHolder {
29 |
30 | ViewPager vp;
31 | LinearLayout ll_tag;
32 | private Handler handler = new Handler() {
33 | @Override
34 | public void handleMessage(Message msg) {
35 | super.handleMessage(msg);
36 | int count = vp.getCurrentItem() + 1;
37 | if (count >= vp.getAdapter().getCount()) {
38 | count = 0;
39 | }
40 |
41 | try {
42 | vp.setCurrentItem(count);
43 | } catch (Exception e) {
44 | e.printStackTrace();
45 | }
46 |
47 | handler.sendEmptyMessageDelayed(0, 5 * 1000);
48 | }
49 | };
50 |
51 | public HomeCarouselHolder(Context context, List lists, int itemID) {
52 | super(context, lists, itemID);
53 |
54 | }
55 |
56 |
57 |
58 | CarousAdapter adapter;
59 | // @Override
60 | public void initView(int position, Context context) {
61 |
62 | if (datas == null || datas.size() == 0) {
63 | return;
64 | }
65 | vp = (ViewPager) itemView.findViewById(R.id.vp_home_carousel);
66 | ll_tag = (LinearLayout) itemView.findViewById(R.id.ll_home_tag);
67 | ll_tag.removeAllViews();
68 | for (int i = 0; i < datas.size(); i++) {
69 | ImageView tag = new ImageView(context);
70 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
71 | params.setMargins(0, 0, Apputils.dip2px(context, 7), 0);
72 | tag.setLayoutParams(params);
73 | tag.setImageResource(R.drawable.tag_carousel);
74 | ll_tag.addView(tag);
75 | }
76 | adapter = new CarousAdapter();
77 | vp.setAdapter(adapter);
78 | vp.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
79 | @Override
80 | public void onPageSelected(int position) {
81 | super.onPageSelected(position);
82 | for (int i = 0; i < ll_tag.getChildCount(); i++) {
83 | if (i == position) {
84 | ll_tag.getChildAt(i).setEnabled(true);
85 | } else {
86 | ll_tag.getChildAt(i).setEnabled(false);
87 | }
88 |
89 | }
90 | }
91 | });
92 |
93 | vp.setOnTouchListener(new View.OnTouchListener() {
94 | @Override
95 | public boolean onTouch(View v, MotionEvent event) {
96 | switch (event.getAction()) {
97 | case MotionEvent.ACTION_DOWN:
98 | case MotionEvent.ACTION_MOVE:
99 | stopCarousel();
100 | break;
101 | default:
102 | startCarousel();
103 | break;
104 |
105 | }
106 |
107 | return false;
108 | }
109 | });
110 | for (int i = 0; i < ll_tag.getChildCount(); i++) {
111 | if (i == vp.getCurrentItem()) {
112 | ll_tag.getChildAt(i).setEnabled(true);
113 | } else {
114 | ll_tag.getChildAt(i).setEnabled(false);
115 | }
116 |
117 | }
118 |
119 | startCarousel();
120 |
121 | }
122 |
123 | public void stopCarousel() {
124 | if (handler != null && handler.hasMessages(0)) {
125 | handler.removeMessages(0);
126 | }
127 | }
128 |
129 | public void startCarousel() {
130 | if (handler != null) {
131 | if (handler.hasMessages(0)) {
132 | handler.removeMessages(0);
133 | }
134 | handler.sendEmptyMessageDelayed(0, 1000);
135 | }
136 | }
137 |
138 |
139 | public class CarousAdapter extends PagerAdapter {
140 |
141 |
142 | @Override
143 | public int getCount() {
144 | return datas.size();
145 | }
146 |
147 | @Override
148 | public boolean isViewFromObject(View view, Object object) {
149 | return view == object;
150 | }
151 |
152 | @Override
153 | public void destroyItem(ViewGroup container, int position, Object object) {
154 | container.removeView((View) object);
155 | }
156 |
157 | @Override
158 | public Object instantiateItem(ViewGroup container, int position) {
159 | ImageView imageView = new ImageView(context);
160 |
161 | imageView.setImageResource(((List)datas).get(position).imgId);
162 | imageView.setScaleType(ImageView.ScaleType.FIT_XY);
163 | ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
164 |
165 |
166 | imageView.setLayoutParams(layoutParams);
167 | // final Set_Item item= (Set_Item) datas.get(position);
168 | //
169 | // if (!TextUtils.isEmpty(item.img_url)) {
170 | // GlideUtils.loadImage(context,imageView,item.img_url);
171 | // }else {
172 | // GlideUtils.loadImage(context,imageView,item.icon_id);
173 | //
174 | // }
175 | imageView.setEnabled(true);
176 | // imageView.setOnClickListener(new View.OnClickListener() {
177 | // @Override
178 | // public void onClick(View v) {
179 | // if (!TextUtils.isEmpty(item.describe)){
180 | // Intent intent = new Intent(context, ShowDetailActivity.class);
181 | // TranInfor infor = new TranInfor();
182 | // infor.title = item.title;
183 | // infor.type = 1;
184 | // infor.content = item.describe;
185 | // infor.describe = item.describe;
186 | // intent.putExtra(Config.infors, infor);
187 | // context. startActivity(intent);
188 | // }
189 | // }
190 | // });
191 |
192 | container.addView(imageView);
193 | return imageView;
194 | }
195 | }
196 |
197 | }
198 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaonian/sang/alibehaver/holder/ItemHolder.java:
--------------------------------------------------------------------------------
1 | package com.xiaonian.sang.alibehaver.holder;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.view.View;
6 | import android.widget.TextView;
7 |
8 | import com.sang.viewfractory.utils.ToastUtil;
9 | import com.xiaonian.sang.alibehaver.R;
10 |
11 | import java.util.List;
12 |
13 | import em.sang.com.allrecycleview.holder.CustomHolder;
14 |
15 | /**
16 | * 是时候撸点真正的代码了!!!
17 | *
18 | * 创建人:桑小年
19 | * 日期: 2017/7/10.
20 | *
21 | * 功能描述:
22 | */
23 |
24 | public class ItemHolder extends CustomHolder {
25 | public ItemHolder(View itemView) {
26 | super(itemView);
27 | }
28 |
29 | public ItemHolder(List datas, View itemView) {
30 | super(datas, itemView);
31 | }
32 |
33 | public ItemHolder(Context context, List lists, int itemID) {
34 | super(context, lists, itemID);
35 | }
36 |
37 | @Override
38 | public void initView(int position, List datas, Context context) {
39 | TextView textView = (TextView) itemView.findViewById(R.id.tv);
40 | final String msg = (String) datas.get(position);
41 | textView.setText(msg);
42 | textView.setHeight(300);
43 | textView.setPadding(20, 10, 20, 10);
44 | if (position % 2 == 0) {
45 | textView.setBackgroundColor(Color.parseColor("#abcdef"));
46 | } else {
47 | textView.setBackgroundColor(Color.parseColor("#fedcba"));
48 | }
49 | itemView.setOnClickListener(new View.OnClickListener() {
50 | @Override
51 | public void onClick(View v) {
52 | ToastUtil.showTextToast(msg);
53 | }
54 | });
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaonian/sang/alibehaver/utils/ToastUtil.java:
--------------------------------------------------------------------------------
1 | package com.xiaonian.sang.alibehaver.utils;
2 |
3 | import android.content.Context;
4 | import android.widget.Toast;
5 |
6 |
7 | public class ToastUtil {
8 | private static Toast toast = null;
9 | private static Context context;
10 |
11 | public static void init(Context cnt){
12 | context=cnt;
13 | }
14 | public static void showTextToast( String msg) {
15 | if (toast == null) {
16 | toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
17 | } else {
18 | toast.setText(msg);
19 | }
20 | toast.show();
21 | }
22 | public static void showTextToastById( int msg) {
23 | if (toast == null) {
24 | toast = Toast.makeText(context, context.getResources().getString(msg), Toast.LENGTH_SHORT);
25 | } else {
26 | toast.setText(msg);
27 | }
28 | toast.show();
29 | }
30 |
31 | public static void showTextToast(Context context, String msg) {
32 | if (toast == null) {
33 | toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
34 | } else {
35 | toast.setText(msg);
36 | }
37 | toast.show();
38 | }
39 | public static void showTextToastById(Context context, int msg) {
40 | if (toast == null) {
41 | toast = Toast.makeText(context, context.getResources().getString(msg), Toast.LENGTH_SHORT);
42 | } else {
43 | toast.setText(msg);
44 | }
45 | toast.show();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/selector_color_gay.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tag_carousel.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tag_gray.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tag_red.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
14 |
21 |
22 |
31 |
32 |
33 |
45 |
46 |
47 |
53 |
54 |
55 |
56 |
60 |
61 |
69 |
73 |
78 |
79 |
83 |
84 |
89 |
90 |
94 |
95 |
100 |
101 |
105 |
106 |
111 |
115 |
116 |
117 |
118 |
119 |
120 |
124 |
125 |
126 |
136 |
137 |
144 |
145 |
149 |
156 |
157 |
161 |
168 |
172 |
179 |
183 |
184 |
192 |
193 |
199 |
200 |
201 |
202 |
203 |
209 |
210 |
211 |
212 |
213 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_home_carousel.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
15 |
16 |
17 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycleview_gride.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/add.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/home_banner1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/home_banner1.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/home_banner2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/home_banner2.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/home_banner3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/home_banner3.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/home_banner4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/home_banner4.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/home_banner5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/home_banner5.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/life_recharge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/life_recharge.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/main_card_bag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/main_card_bag.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/main_pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/main_pay.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/main_recive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/main_recive.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/main_scan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/main_scan.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/phone_recharge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/phone_recharge.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xhdpi/search.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
8 | #eaeeef
9 | #00000000
10 | #ffffff
11 | #aaaaaa
12 | #efefef
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 10dp
4 | 10dp
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AliBehaver
3 | 手机充值
4 | 生活缴费
5 | 交通罚款
6 | 飞机票
7 | 火车票
8 | 游戏充值
9 | 加油卡充值
10 | 彩票服务
11 | 沃富公益
12 | 共享媒体
13 | 信用卡还款
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/test/java/com/xiaonian/sang/alibehaver/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.xiaonian.sang.alibehaver;
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 | }
--------------------------------------------------------------------------------
/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.3.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangxiaonian/AliBehaver/7a2342486dcb459518e6d950bac54557b84bc18f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Jul 10 09:05:15 CST 2017
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-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':allrecycleview', ':viewfractory'
2 |
--------------------------------------------------------------------------------
/viewfractory/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/viewfractory/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "25.0.0"
6 |
7 | defaultConfig {
8 | minSdkVersion 17
9 | targetSdkVersion 24
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | compile 'com.android.support:appcompat-v7:24.2.1'
30 | testCompile 'junit:junit:4.12'
31 | }
32 |
--------------------------------------------------------------------------------
/viewfractory/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\develop\SDK/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/viewfractory/src/androidTest/java/com/sang/viewfractory/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory;
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.sang.viewfractory.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/viewfractory/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/BasicView.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.ValueAnimator;
6 | import android.content.Context;
7 | import android.graphics.Bitmap;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.Paint;
11 | import android.graphics.Path;
12 | import android.util.AttributeSet;
13 | import android.view.View;
14 |
15 | import com.sang.viewfractory.factory.ShapFactory;
16 | import com.sang.viewfractory.utils.Apputils;
17 | import com.sang.viewfractory.utils.UnOverWriteException;
18 |
19 |
20 | /**
21 | * Description:
22 | *
23 | * @Author:桑小年
24 | * @Data:2016/12/6 10:49
25 | */
26 | public class BasicView extends View {
27 |
28 | /**
29 | * 正在加载
30 | */
31 | public static final int LOADING = 0;
32 | /**
33 | * 加载成功
34 | */
35 | public static final int LOAD_SUCCESS = 1;//加载成功
36 |
37 | /**
38 | * 加载失败
39 | */
40 | public static final int LOAD_FAIL = 2;//加载失败
41 | /**
42 | * 箭头向下
43 | */
44 | public static final int LOAD_OVER = 4;//正常状态
45 | /**
46 | * 箭头向上
47 | */
48 | public static final int LOAD_BEFOR = 5;//即将开始加载
49 |
50 | /**
51 | * 加载中旋转图像
52 | */
53 | public static final int STYLE_LOAD = 6;
54 |
55 | /**
56 | * 加载中正方形图像
57 | */
58 | public static final int STYLE_SQUARE = 7;
59 | /**
60 | * 没有更多数据了
61 | */
62 | public static final int LOAD_NO_MORE=8;
63 |
64 | /**
65 | * 当前状态
66 | */
67 | protected int state;
68 |
69 | /**
70 | * 间隙
71 | */
72 | protected int gap;
73 | protected Paint mPaint;
74 | protected Path mPath;
75 | /**
76 | * 画笔颜色
77 | */
78 | protected int color;
79 |
80 | /**
81 | * 宽高
82 | */
83 | protected int mWidth, mHeight;
84 |
85 |
86 | /**
87 | * 图形绘制工厂
88 | */
89 | protected ShapFactory factory;
90 |
91 |
92 | public BasicView(Context context) {
93 | super(context);
94 | initView(context, null, 0);
95 | }
96 |
97 | public BasicView(Context context, AttributeSet attrs) {
98 | super(context, attrs);
99 | initView(context, attrs, 0);
100 | }
101 |
102 | public BasicView(Context context, AttributeSet attrs, int defStyleAttr) {
103 | super(context, attrs, defStyleAttr);
104 | initView(context, attrs, defStyleAttr);
105 | }
106 |
107 | private void initView(Context context, AttributeSet attrs, int defStyleAttr) {
108 | style=STYLE_SQUARE;
109 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
110 | mPaint.setStrokeWidth(1);
111 | color = Color.parseColor("#B8B7B8");
112 | mPaint.setColor(color);
113 | mPaint.setStyle(Paint.Style.FILL);
114 | upState(LOAD_BEFOR);
115 | gap = Apputils.dip2px(getContext(), 5);
116 | mPath = new Path();
117 | factory = ShapFactory.getInstance(mPath, mPaint,context);
118 | style=STYLE_SQUARE;
119 | }
120 |
121 | @Override
122 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
123 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
124 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
125 | int widthSize = MeasureSpec.getSize(widthMeasureSpec);
126 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
127 | int heightSize = MeasureSpec.getSize(heightMeasureSpec);
128 |
129 | int width, heitht;
130 | if (widthMode == MeasureSpec.EXACTLY) {
131 | width = widthSize;
132 | } else {
133 | width = (getPaddingLeft() + Apputils.dip2px(getContext(), 40) + getPaddingRight());
134 | }
135 | if (heightMode == MeasureSpec.EXACTLY) {
136 | heitht = heightSize;
137 | } else {
138 | heitht = (getPaddingTop() + Apputils.dip2px(getContext(), 40) + getPaddingBottom());
139 | }
140 | setMeasuredDimension(width, heitht);
141 | }
142 |
143 |
144 | @Override
145 | protected void onDraw(Canvas canvas) {
146 | super.onDraw(canvas);
147 | if (mWidth == 0) {
148 | mHeight = mWidth = Math.max(getMeasuredWidth(), getMeasuredHeight());
149 | }
150 | Bitmap bitmap = creatBitmap(state);
151 | if (bitmap != null) {
152 | canvas.drawBitmap(bitmap, 0, 0, mPaint);
153 | bitmap.recycle();
154 | }
155 | }
156 |
157 |
158 | /**
159 | * 根据当前所处状态来绘制不同的图形
160 | *
161 | * @param state
162 | * @eturn
163 | */
164 | private Bitmap creatBitmap(int state) {
165 | Bitmap bitmap = null;
166 | switch (state) {
167 | case LOAD_BEFOR:
168 | case LOAD_OVER:
169 | bitmap = factory.creatArrows(mWidth, mHeight, 12);
170 | break;
171 | case LOADING:
172 | setShapRotation(0);
173 | bitmap = creatShape(mWidth, mHeight);
174 | break;
175 | case LOAD_SUCCESS:
176 | setShapRotation(0);
177 | bitmap = factory.creatCorrect(mWidth, mHeight);
178 | break;
179 | case LOAD_FAIL:
180 | setShapRotation(0);
181 | bitmap = factory.creatError(mWidth, mHeight);
182 | break;
183 | case LOAD_NO_MORE:
184 | setShapRotation(0);
185 |
186 | break;
187 |
188 | }
189 | mPath.reset();
190 | return bitmap;
191 | }
192 |
193 |
194 | /**
195 | * 绘制加载中的动画,必须重写
196 | *
197 | * @param mWidth 高度
198 | * @param mHeight 宽度
199 | */
200 | protected Bitmap creatShape(int mWidth, int mHeight) {
201 | throw new UnOverWriteException("No OverWrite creatShap()");
202 |
203 | }
204 |
205 |
206 | protected ValueAnimator rota, flip;
207 |
208 | private float startAng, endAng;
209 |
210 | /**
211 | * 箭头变化动画
212 | *
213 | * @param state
214 | */
215 | private void round(final int state) {
216 |
217 | if (state == this.state) {
218 | return;
219 | }
220 |
221 | clearViewAnimation();
222 | startAng = getRotation();
223 | switch (state) {
224 | case LOAD_OVER:
225 | endAng = 0;
226 | if (rota != null && rota.isRunning()) {
227 | startAng = (float) rota.getAnimatedValue();
228 | rota.cancel();
229 | }
230 | break;
231 | case LOAD_BEFOR:
232 | endAng = 180;
233 | if (rota != null && rota.isRunning()) {
234 | startAng = (float) rota.getAnimatedValue();
235 | rota.cancel();
236 | }
237 | break;
238 | default:
239 | startAng = 0;
240 | endAng = 0;
241 | break;
242 | }
243 |
244 | rota = ValueAnimator.ofFloat(startAng, endAng);
245 | rota.setDuration(200);
246 | rota.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
247 | @Override
248 | public void onAnimationUpdate(ValueAnimator animation) {
249 |
250 | setShapRotation((Float) animation.getAnimatedValue());
251 | }
252 | });
253 | rota.addListener(new AnimatorListenerAdapter() {
254 | @Override
255 | public void onAnimationCancel(Animator animation) {
256 | super.onAnimationCancel(animation);
257 |
258 | setShapRotation(0);
259 | }
260 | });
261 |
262 | if (startAng != endAng) {
263 | rota.start();
264 | }
265 |
266 | }
267 |
268 |
269 | private void flip(final int state) {
270 | if (state == this.state) {
271 | return;
272 | }
273 | clearViewAnimation();
274 | switch (state) {
275 | case LOADING:
276 | flipAnimation();
277 | break;
278 | case LOAD_SUCCESS:
279 | if (flip != null || flip.isRunning()) {
280 | flip.cancel();
281 | }
282 | break;
283 | }
284 |
285 |
286 | }
287 |
288 |
289 |
290 |
291 | /**
292 | * 加载状态时候的动画
293 | */
294 | protected void flipAnimation() {
295 | clearViewAnimation();
296 | }
297 |
298 | public void upState(int state) {
299 | if (this.state == state) {
300 | return;
301 | }
302 | clearViewAnimation();
303 |
304 | if (state == LOAD_BEFOR || state == LOAD_OVER) {
305 | round(state);
306 | } else if (state == LOADING) {
307 | flip(state);
308 | }else if (state==LOAD_SUCCESS){
309 | clearViewAnimation();
310 | }
311 | this.state = state;
312 | postInvalidate();
313 | }
314 |
315 | protected void clearViewAnimation(){
316 | if (flip != null && flip.isRunning()) {
317 | flip.cancel();
318 |
319 | }
320 | if (rota != null && rota.isRunning()) {
321 | rota.cancel();
322 | }
323 | }
324 |
325 |
326 | protected void setShapRotation(float rotation) {
327 | setPivotX(mWidth / 2);
328 | setPivotY(mHeight / 2);
329 | setRotation(rotation);
330 | }
331 |
332 |
333 | @Override
334 | protected void onAttachedToWindow() {
335 | super.onAttachedToWindow();
336 | if (state == LOADING) {
337 | flipAnimation();
338 | }
339 | }
340 |
341 |
342 |
343 | @Override
344 | protected void onDetachedFromWindow() {
345 | super.onDetachedFromWindow();
346 | if (flip != null && flip.isRunning()) {
347 | flip.cancel();
348 | }
349 | clearViewAnimation();
350 | }
351 |
352 | protected int style;
353 | public void setStyle(int style) {
354 | this.style=style;
355 | }
356 | }
357 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/factory/ShapFactory.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.factory;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.graphics.Path;
9 | import android.graphics.RectF;
10 |
11 | import com.sang.viewfractory.utils.DeviceUtils;
12 |
13 | /**
14 | * Description:
15 | *
16 | * @Author:桑小年
17 | * @Data:2016/12/8 17:38
18 | */
19 | public class ShapFactory {
20 |
21 | private Path mPath;
22 | private Paint mPaint;
23 | private static ShapFactory factory;
24 | private Context context;
25 |
26 | public static ShapFactory getInstance(Path mPath, Paint mPaint) {
27 | factory = new ShapFactory(mPath, mPaint);
28 | return factory;
29 | }
30 | public static ShapFactory getInstance(Path mPath, Paint mPaint,Context context) {
31 | factory = new ShapFactory(mPath, mPaint,context);
32 | return factory;
33 | }
34 |
35 | private ShapFactory(Path mPath, Paint mPaint) {
36 | this.mPaint = mPaint;
37 | this.mPath = mPath;
38 | }
39 | private ShapFactory(Path mPath, Paint mPaint,Context context) {
40 | this.mPaint = mPaint;
41 | this.mPath = mPath;
42 | this.context = context;
43 |
44 | }
45 |
46 | /**
47 | * 绘制一个箭头
48 | *
49 | * @param mWidth 控件高度
50 | * @param mHeight 控件宽
51 | * @param den 箭头杆空格数量
52 | * @return 一个向下的箭头
53 | */
54 | public Bitmap creatArrows(int mWidth, int mHeight, int den) {
55 | Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_4444);
56 | Canvas canvas = new Canvas(bitmap);
57 | mPath.reset();
58 | mPaint.setStyle(Paint.Style.FILL);
59 | int amount = 0;
60 | for (int i = 1; i <= den; i++) {
61 | amount += i;
62 | }
63 | float start = mHeight * 2 / 3;
64 | float l = (float) ((mHeight - start) / (Math.sin(60 * Math.PI / 180) * 2));
65 | mPath.moveTo(mWidth / 2, mHeight);
66 | mPath.lineTo(mWidth / 2 - l, start);
67 | mPath.lineTo(mWidth / 2 + l, start);
68 | mPath.lineTo(mWidth / 2, mHeight);
69 | int count = 0;
70 | int last = 0;
71 | float left = mWidth / 2 - l / 2;
72 | float right = mWidth / 2 + l / 2;
73 | for (int i = den; i > 0; i--) {
74 | last = count;
75 | count += i;
76 | if (i % 2 == 0) {
77 | float top = start - start * last / (amount);
78 | float boom = start - start * count / (amount);
79 | mPath.addRect(left, top, right, boom, Path.Direction.CCW);
80 | }
81 | }
82 | canvas.drawPath(mPath, mPaint);
83 | return bitmap;
84 | }
85 |
86 | /**
87 | * 绘制一个方块
88 | *
89 | * @param mWidth 宽
90 | * @param mHeight 高
91 | * @return 一个四方形的Bitmap
92 | */
93 | public Bitmap creatShap(int mWidth, int mHeight) {
94 | Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_4444);
95 | Canvas canvas = new Canvas(bitmap);
96 | mPath.reset();
97 | mPaint.setStyle(Paint.Style.FILL);
98 | mPath.addRect(0, 0, mWidth , mHeight, Path.Direction.CCW);
99 | canvas.drawPath(mPath, mPaint);
100 | return bitmap;
101 | }
102 |
103 | /**
104 | * 绘制对号
105 | * @param mWidth
106 | * @param mHeight
107 | * @return
108 | */
109 | public Bitmap creatCorrect(int mWidth, int mHeight) {
110 | Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_4444);
111 | Canvas canvas = new Canvas(bitmap);
112 | mPath.reset();
113 | mPaint.setStyle(Paint.Style.STROKE);
114 | mPaint.setStrokeWidth(2);
115 | int radius = mWidth /2-2;
116 | mPath.moveTo(mWidth/8,mHeight/3);
117 | mPath.lineTo(mWidth/4,mHeight/4);
118 | mPath.lineTo(mWidth*3/8,mHeight/3);
119 | mPath.moveTo(mWidth*5/8,mHeight/3);
120 | mPath.lineTo(mWidth*3/4,mHeight/4);
121 | mPath.lineTo(mWidth*7/8,mHeight/3);
122 |
123 | mPath.moveTo(mWidth/4,mHeight*3/5);
124 | mPath.cubicTo(mWidth/4,mHeight*3/5,mWidth/2,mHeight,mWidth*3/4,mHeight*3/5);
125 | int centerX = mWidth / 2;
126 | int centerY = mHeight / 2;
127 | mPath.addCircle(centerX,centerY,radius, Path.Direction.CCW);
128 | canvas.drawPath(mPath, mPaint);
129 | return bitmap;
130 | }
131 |
132 | /**
133 | * 绘制错号
134 | * @param mWidth
135 | * @param mHeight
136 | * @return
137 | */
138 | public Bitmap creatError(int mWidth, int mHeight) {
139 | Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_4444);
140 | Canvas canvas = new Canvas(bitmap);
141 | mPath.reset();
142 | mPaint.setStyle(Paint.Style.STROKE);
143 | mPaint.setStrokeWidth(3);
144 | mPath.moveTo(mWidth/3,mHeight/3);
145 | mPath.lineTo(mWidth*2/3,mHeight*2/3);
146 | mPath.moveTo(mWidth*2/3,mHeight/3);
147 | mPath.lineTo(mWidth/3,mHeight*2/3);
148 | canvas.drawPath(mPath, mPaint);
149 | return bitmap;
150 | }
151 |
152 | /**
153 | * 绘制加载
154 | * @param mWidth
155 | * @param mHeight
156 | * @return
157 | */
158 | public Bitmap creatLoading(int mWidth, int mHeight) {
159 | Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_4444);
160 | Canvas canvas = new Canvas(bitmap);
161 |
162 | mPaint.setStyle(Paint.Style.STROKE);
163 | mPaint.setColor( Color.GRAY);
164 | mPaint.setStrokeWidth( DeviceUtils.dip2px(context,4));
165 | int radius = mWidth / 4;
166 | int centerX = mWidth / 2;
167 | int centerY = mHeight / 2;
168 | RectF rectF = new RectF();
169 | rectF.left=centerX-radius;
170 | rectF.top=centerY-radius;
171 | rectF.right=centerX+radius;
172 | rectF.bottom=centerY+radius;
173 | for (int i = 0; i < 120; i++) {
174 | if (i%10==0){
175 | canvas.drawArc(rectF, 3*i,3,false,mPaint);
176 | }
177 | }
178 | return bitmap;
179 | }
180 |
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/listener/OnScrollSelectListener.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.listener;
2 |
3 |
4 | public interface OnScrollSelectListener {
5 |
6 | void onPositionChenge(int position,T data);
7 | void onStopPosition(int position,T data);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/utils/Apputils.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.utils;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 |
6 | /**
7 | * Description:
8 | *
9 | * @Author:桑小年
10 | * @Data:2016/11/11 15:03
11 | */
12 | public class Apputils {
13 | /**
14 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
15 | */
16 | public static int dip2px(Context context, float dpValue) {
17 | final float scale = context.getResources().getDisplayMetrics().density;
18 | return (int) (dpValue * scale + 0.5f);
19 | }
20 |
21 | /**
22 | * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
23 | */
24 | public static int px2dip(Context context, float pxValue) {
25 | final float scale = context.getResources().getDisplayMetrics().density;
26 | return (int) (pxValue / scale + 0.5f);
27 | }
28 |
29 | /**
30 | * 将px值转换为sp值,保证文字大小不变
31 | *
32 | * @param pxValue
33 | * @return
34 | */
35 | public static int px2sp(Context context, float pxValue) {
36 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
37 | return (int) (pxValue / fontScale + 0.5f);
38 | }
39 |
40 | /**
41 | * 将sp值转换为px值,保证文字大小不变
42 | *
43 | * @param spValue
44 | * @return
45 | */
46 | public static int sp2px(Context context, float spValue) {
47 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
48 | return (int) (spValue * fontScale + 0.5f);
49 | }
50 |
51 | /**
52 | * 获取控件宽高
53 | * @param view
54 | * @return 0为宽
55 | */
56 | public static int[] getWidthAndHeight(View view){
57 | int[] res = new int[2];
58 | int w = View.MeasureSpec.makeMeasureSpec(0,
59 | View.MeasureSpec.UNSPECIFIED);
60 | int h = View.MeasureSpec.makeMeasureSpec(0,
61 | View.MeasureSpec.UNSPECIFIED);
62 | view.measure(w, h);
63 | res[1] = view.getMeasuredHeight();
64 | res[0]= view.getMeasuredWidth();
65 | return res;
66 | }
67 |
68 | /**
69 | * 获取屏幕的高度
70 | * @param context
71 | * @return
72 | */
73 | public static float getScreenWidth(Context context) {
74 | return context.getResources().getDisplayMetrics().widthPixels;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/utils/Config.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.utils;
2 |
3 | /**
4 | * Description:
5 | *
6 | * @Author:桑小年
7 | * @Data:2017/2/20 10:33
8 | */
9 | public class Config {
10 | public static final String sp_name = "AllRecycleView";
11 | public static final String sp_time = "up_time";
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/utils/DeviceUtils.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.utils;
2 |
3 | import android.content.Context;
4 | import android.view.ViewConfiguration;
5 |
6 | import java.lang.reflect.Field;
7 |
8 | /**
9 | * Description:
10 | *
11 | * @Author:桑小年
12 | * @Data:2017/1/4 10:44
13 | */
14 | public class DeviceUtils {
15 | /**
16 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
17 | */
18 | public static int dip2px(Context context, float dpValue) {
19 |
20 | final float scale = context.getResources().getDisplayMetrics().density;
21 | return (int) (dpValue * scale + 0.5f);
22 | }
23 |
24 | /**
25 | * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
26 | */
27 | public static int px2dip(Context context, float pxValue) {
28 | final float scale = context.getResources().getDisplayMetrics().density;
29 | return (int) (pxValue / scale + 0.5f);
30 | }
31 | /**
32 | * 将px值转换为sp值,保证文字大小不变
33 | *
34 | * @param context
35 | * @param pxValue
36 | * (DisplayMetrics类中属性scaledDensity)
37 | * @return
38 | */
39 | public static int px2sp(Context context, float pxValue) {
40 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
41 | return (int) (pxValue / fontScale + 0.5f);
42 | }
43 |
44 | /**
45 | * 将sp值转换为px值,保证文字大小不变
46 | *
47 | * @param spValue
48 | * @param spValue
49 | * (DisplayMetrics类中属性scaledDensity)
50 | * @return
51 | */
52 | public static int sp2px(Context context, float spValue) {
53 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
54 | return (int) (spValue * fontScale + 0.5f);
55 | }
56 |
57 | /**
58 | * 获取判断滑动的最小滑动距离
59 | * @param context
60 | * @return
61 | */
62 | public static int getMinTouchSlop(Context context){
63 | return ViewConfiguration.get(context).getScaledTouchSlop();
64 | }
65 |
66 | /**
67 | * 获取屏幕密度
68 | * @param context
69 | * @return
70 | */
71 | public static float getInch(Context context){
72 | float density = context.getResources().getDisplayMetrics().density;
73 | return density;
74 | }
75 | /**
76 | * 获取屏幕宽度
77 | * @param context
78 | * @return
79 | */
80 | public static float getScreenWidth(Context context){
81 | float density = context.getResources().getDisplayMetrics().widthPixels;
82 | return density;
83 | }
84 | /**
85 | * 获取屏幕密度
86 | * @param context
87 | * @return
88 | */
89 | public static float getScreenHeight(Context context){
90 | float density = context.getResources().getDisplayMetrics().heightPixels;
91 | return density;
92 | }
93 | /**
94 | * 获取状态栏高度
95 | * @param context
96 | * @return
97 | */
98 | public static int getStatuBarHeight(Context context) {
99 | try {
100 | Class> c = Class.forName("com.android.internal.R$dimen");
101 | Object obj = c.newInstance();
102 | Field field = c.getField("status_bar_height");
103 | int x = Integer.parseInt(field.get(obj).toString());
104 | return context.getResources().getDimensionPixelSize(x);
105 | } catch (ClassNotFoundException e) {
106 | e.printStackTrace();
107 | } catch (InstantiationException e) {
108 | e.printStackTrace();
109 | } catch (IllegalAccessException e) {
110 | e.printStackTrace();
111 | } catch (NoSuchFieldException e) {
112 | e.printStackTrace();
113 | }
114 | return 0;
115 | }
116 |
117 |
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/utils/JLog.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.utils;
2 |
3 | import android.util.Log;
4 |
5 | public class JLog {
6 | /**
7 | * tag
8 | */
9 | public static String tag = "view";
10 |
11 |
12 | /**
13 | * 是否屏蔽log日志,当为false时,系统不再打印
14 | */
15 | private static boolean needLog = true;
16 |
17 |
18 | public static void i(String content) {
19 | if (needLog) {
20 | Log.i(tag, getLogInfo() + content);
21 | }
22 | }
23 |
24 | public static void i(String tag, String content) {
25 | if (needLog) {
26 | Log.i(tag, getLogInfo() + content);
27 | }
28 | }
29 |
30 | public static void d(String content) {
31 | if (needLog) {
32 | Log.d(tag, getLogInfo() + content);
33 | }
34 | }
35 |
36 | public static void d(String tag, String content) {
37 | if (needLog) {
38 | Log.d(tag, getLogInfo() + content);
39 | }
40 | }
41 |
42 | public static void e(String content) {
43 | if (needLog) {
44 | Log.e(tag, getLogInfo() + content);
45 | }
46 | }
47 |
48 | public static void e(String tag, String content) {
49 | if (needLog) {
50 | Log.e(tag, getLogInfo() + content);
51 | }
52 | }
53 |
54 | public static void v(String content) {
55 | if (needLog) {
56 | Log.v(tag, getLogInfo() + content);
57 | }
58 | }
59 |
60 | public static void v(String tag, String content) {
61 | if (needLog) {
62 | Log.v(tag, getLogInfo() + content);
63 | }
64 | }
65 |
66 | public static void w(String content) {
67 | if (needLog) {
68 | Log.w(tag, getLogInfo() + content);
69 | }
70 | }
71 |
72 | public static void w(String tag, String content) {
73 | if (needLog) {
74 | Log.w(tag, getLogInfo() + content);
75 | }
76 | }
77 |
78 | private static String getLogInfo() {
79 |
80 | StackTraceElement targetStackTraceElement = getTargetStackTraceElement();
81 |
82 | return "(" + targetStackTraceElement.getFileName() + ":"
83 | + targetStackTraceElement.getLineNumber() + ")\n";
84 | }
85 |
86 |
87 | private static StackTraceElement getTargetStackTraceElement() {
88 | // find the target invoked method
89 | StackTraceElement targetStackTrace = null;
90 | boolean shouldTrace = false;
91 | StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
92 | for (StackTraceElement stackTraceElement : stackTrace) {
93 | boolean isLogMethod = stackTraceElement.getClassName().equals(JLog.class.getName());
94 | if (shouldTrace && !isLogMethod) {
95 | targetStackTrace = stackTraceElement;
96 | break;
97 | }
98 | shouldTrace = isLogMethod;
99 | }
100 | return targetStackTrace;
101 | }
102 |
103 | /**
104 | * 获取类名
105 | * @return
106 | */
107 | private static String getClassName() {
108 | try {
109 | String classPath = Thread.currentThread().getStackTrace()[5].getClassName();
110 | return classPath.substring(classPath.lastIndexOf(".") + 1);
111 | } catch (Exception e) {
112 | e.printStackTrace();
113 | }
114 |
115 | return null;
116 | }
117 |
118 | /**
119 | * 获取方法名
120 | * @return
121 | */
122 | private static String getMethodName() {
123 | try {
124 | return Thread.currentThread().getStackTrace()[5].getMethodName();
125 | } catch (Exception e) {
126 | e.printStackTrace();
127 | }
128 |
129 | return null;
130 | }
131 |
132 | /**
133 | * 打印log的行号
134 | *
135 | * @return
136 | */
137 | private static int getLineNumber() {
138 | try {
139 | return Thread.currentThread().getStackTrace()[5].getLineNumber();
140 | } catch (Exception e) {
141 | e.printStackTrace();
142 | }
143 |
144 | return 0;
145 | }
146 |
147 |
148 | }
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/utils/LockPatternUtil.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.utils;
2 |
3 | import android.content.Context;
4 |
5 |
6 | import com.sang.viewfractory.view.LockPatternView;
7 |
8 | import java.security.MessageDigest;
9 | import java.security.NoSuchAlgorithmException;
10 | import java.util.Arrays;
11 | import java.util.List;
12 |
13 | /**
14 | * Created by Sym on 2016/1/16.
15 | */
16 | public class LockPatternUtil {
17 |
18 | /**
19 | * change string value (ex: 10.0dip => 20) to int value
20 | *
21 | * @param context
22 | * @param value
23 | * @return
24 | */
25 | @Deprecated
26 | public static int changeSize(Context context, String value) {
27 | if (value.contains("dip")) {
28 | float dip = Float.valueOf(value.substring(0, value.indexOf("dip")));
29 | return LockPatternUtil.dip2px(context, dip);
30 | } else if (value.contains("px")) {
31 | float px = Float.valueOf(value.substring(0, value.indexOf("px")));
32 | return (int) px;
33 | } else if (value.contains("@")) {
34 | float px = context.getResources().getDimension(Integer.valueOf(value.replace("@", "")));
35 | return (int) px;
36 | }
37 | else {
38 | throw new IllegalArgumentException("can not use wrap_content " +
39 | "or match_parent or fill_parent or others' illegal parameter");
40 | }
41 | }
42 |
43 | /**
44 | * dip to px
45 | *
46 | * @param context
47 | * @param dpValue
48 | * @return
49 | */
50 | public static int dip2px(Context context, float dpValue) {
51 | final float scale = context.getResources().getDisplayMetrics().density;
52 | return (int) (dpValue * scale + 0.5f);
53 | }
54 |
55 | /**
56 | * check the touch cell is or not in the circle
57 | *
58 | * @param sx
59 | * @param sy
60 | * @param r the radius of circle
61 | * @param x the x position of circle's center point
62 | * @param y the y position of circle's center point
63 | * @param offset the offset to the frame of the circle
64 | * (if offset > 0 : the offset is inside the circle; if offset < 0 : the offset is outside the circle)
65 | * @return
66 | */
67 | public static boolean checkInRound(float sx, float sy, float r, float x, float y, float offset) {
68 | return Math.sqrt((sx - x + offset) * (sx - x + offset) + (sy - y + offset) * (sy - y + offset)) < r;
69 | }
70 |
71 | /**
72 | * get distance between two points
73 | *
74 | * @param fpX first point x position
75 | * @param fpY first point y position
76 | * @param spX second point x position
77 | * @param spY second point y position
78 | * @return
79 | */
80 | public static float getDistanceBetweenTwoPoints(float fpX, float fpY, float spX, float spY) {
81 | return (float) Math.sqrt((spX - fpX) * (spX - fpX) + (spY - fpY) * (spY - fpY));
82 | }
83 |
84 | /**
85 | * get the angle which the line intersect x axis
86 | *
87 | * @param fpX
88 | * @param fpY
89 | * @param spX
90 | * @param spY
91 | * @param distance
92 | * @return degrees
93 | */
94 | public static float getAngleLineIntersectX(float fpX, float fpY, float spX, float spY, float distance) {
95 | return (float) Math.toDegrees(Math.acos((spX - fpX) / distance));
96 | }
97 |
98 | /**
99 | * get the angle which the line intersect y axis
100 | *
101 | * @param fpX
102 | * @param fpY
103 | * @param spX
104 | * @param spY
105 | * @param distance
106 | * @return degrees
107 | */
108 | public static float getAngleLineIntersectY(float fpX, float fpY, float spX, float spY, float distance) {
109 | return (float) Math.toDegrees(Math.acos((spY - fpY) / distance));
110 | }
111 |
112 | /**
113 | * Generate an SHA-1 hash for the pattern. Not the most secure, but it is at
114 | * least a second level of protection. First level is that the file is in a
115 | * location only readable by the system process.
116 | *
117 | * @param pattern
118 | * @return the hash of the pattern in a byte array.
119 | */
120 | public static byte[] patternToHash(List pattern) {
121 | if (pattern == null) {
122 | return null;
123 | } else {
124 | int size = pattern.size();
125 | byte[] res = new byte[size];
126 | for (int i = 0; i < size; i++) {
127 | LockPatternView.Cell cell = pattern.get(i);
128 | res[i] = (byte) cell.getIndex();
129 | }
130 | MessageDigest md = null;
131 | try {
132 | md = MessageDigest.getInstance("SHA-1");
133 | return md.digest(res);
134 | } catch (NoSuchAlgorithmException e) {
135 | e.printStackTrace();
136 | return res;
137 | }
138 | }
139 | }
140 |
141 | /**
142 | * Check to see if a pattern matches the saved pattern. If no pattern
143 | * exists, always returns true.
144 | *
145 | * @param pattern
146 | * @param bytes
147 | * @return Whether the pattern matches the stored one.
148 | */
149 | public static boolean checkPattern(List pattern, byte[] bytes) {
150 | if (pattern == null || bytes == null) {
151 | return false;
152 | } else {
153 | byte[] bytes2 = patternToHash(pattern);
154 | return Arrays.equals(bytes, bytes2);
155 | }
156 | }
157 | }
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/utils/ScrollUtils.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.utils;
2 |
3 | import android.content.Context;
4 | import android.hardware.SensorManager;
5 | import android.view.VelocityTracker;
6 | import android.view.ViewConfiguration;
7 | import android.view.animation.Interpolator;
8 |
9 | /**
10 | * Description:关于滑动的工具类
11 | *
12 | * @Author:桑小年
13 | * @Data:2017/2/8 11:26
14 | */
15 | public class ScrollUtils {
16 |
17 | private final Context context;
18 | VelocityTracker velocityTracker;
19 | private float INFLEXION=0.35f;
20 | private float mPhysicalCoeff;
21 | private float mFlingFriction = ViewConfiguration.getScrollFriction();
22 | private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
23 | private float ppi;
24 | private float velocity;
25 |
26 | public ScrollUtils(Context context, VelocityTracker velocityTracker){
27 | this.velocityTracker=velocityTracker;
28 | this.context = context;
29 | initView(context);
30 | }
31 |
32 | private void initView(Context context){
33 | ppi = DeviceUtils.getInch(context);
34 | mPhysicalCoeff=computeDeceleration(0.85f);
35 | velocityTracker.computeCurrentVelocity(1000);
36 | float velocityX = velocityTracker.getXVelocity();
37 | float velocityY = velocityTracker.getYVelocity();
38 | velocity = (float) Math.hypot(velocityX, velocityY);
39 | }
40 |
41 |
42 |
43 | /**
44 | * 获取滑动减速
45 | * @return
46 | */
47 | private double getSplineDeceleration(int velocity) {
48 | return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
49 | }
50 |
51 | /**
52 | * 滑动时间
53 | * @return
54 | */
55 | private int getSplineFlingDuration(int velocity) {
56 | final double l = getSplineDeceleration(velocity);
57 | final double decelMinusOne = DECELERATION_RATE - 1.0;
58 | return (int) (100.0 * Math.exp(l / decelMinusOne));
59 | }
60 |
61 | /**
62 | * 获取惯性滑动的距离获取滑动速度
63 | * @param distance
64 | * @return
65 | */
66 | public double getVelocitByDistance(float distance){
67 | final double decelMinusOne = DECELERATION_RATE - 1.0;
68 | double l = Math.log(Math.abs(distance) / (mFlingFriction * mPhysicalCoeff)) / DECELERATION_RATE * decelMinusOne;
69 | return Math.exp(l)/INFLEXION* (mFlingFriction * mPhysicalCoeff) ;
70 | }
71 |
72 |
73 | public double getTiemByDistance(float distance){
74 | double speed = getVelocitByDistance(distance);
75 | float time = getSplineFlingDuration((int) Math.abs(speed));
76 | return time;
77 | }
78 |
79 |
80 | /**
81 | * 根据获取最大滑动距离
82 | * @return
83 | */
84 | public double getSplineFlingDistance(float maxDistance) {
85 | float velocityX = velocityTracker.getXVelocity();
86 | float velocityY = velocityTracker.getYVelocity();
87 | velocity = (float) Math.hypot(velocityX, velocityY);
88 | final double l = getSplineDeceleration((int) velocity);
89 | final double decelMinusOne = DECELERATION_RATE - 1.0;
90 | float coeffY = velocity == 0 ? 1.0f : velocityTracker.getYVelocity() / velocity;
91 | double totalDistance = mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
92 | int distance = (int) Math.round(totalDistance * coeffY);
93 | float finalDistance = Math.abs(maxDistance)>=Math.abs(distance)?distance:maxDistance;
94 | return finalDistance;
95 | }
96 |
97 | private float computeDeceleration(float friction) {
98 | return SensorManager.GRAVITY_EARTH // g (m/s^2)
99 | * 39.37f // inch/meter
100 | *ppi // pixels per inch
101 | * friction;
102 | }
103 |
104 | public static class ViscousFluidInterpolator implements Interpolator {
105 | /** Controls the viscous fluid effect (how much of it). */
106 | private static final float VISCOUS_FLUID_SCALE = 8.0f;
107 |
108 | private static final float VISCOUS_FLUID_NORMALIZE;
109 | private static final float VISCOUS_FLUID_OFFSET;
110 |
111 | static {
112 |
113 | // must be set to 1.0 (used in viscousFluid())
114 | VISCOUS_FLUID_NORMALIZE = 1.0f / viscousFluid(1.0f);
115 | // account for very small floating-point error
116 | VISCOUS_FLUID_OFFSET = 1.0f - VISCOUS_FLUID_NORMALIZE * viscousFluid(1.0f);
117 | }
118 |
119 | private static float viscousFluid(float x) {
120 | x *= VISCOUS_FLUID_SCALE;
121 | if (x < 1.0f) {
122 | x -= (1.0f - (float)Math.exp(-x));
123 | } else {
124 | float start = 0.36787944117f; // 1/e == exp(-1)
125 | x = 1.0f - (float)Math.exp(1.0f - x);
126 | x = start + x * (1.0f - start);
127 | }
128 | return x;
129 | }
130 |
131 | @Override
132 | public float getInterpolation(float input) {
133 | final float interpolated = VISCOUS_FLUID_NORMALIZE * viscousFluid(input);
134 | if (interpolated > 0) {
135 | return interpolated + VISCOUS_FLUID_OFFSET;
136 | }
137 | return interpolated;
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/utils/ToastUtil.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.utils;
2 |
3 | import android.content.Context;
4 | import android.widget.Toast;
5 |
6 |
7 | public class ToastUtil {
8 | private static Toast toast = null;
9 | private static Context context;
10 |
11 | public static void init(Context cnt){
12 | context=cnt;
13 | }
14 | public static void showTextToast( String msg) {
15 | if (toast == null) {
16 | toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
17 | } else {
18 | toast.setText(msg);
19 | }
20 | toast.show();
21 | }
22 | public static void showTextToastById( int msg) {
23 | if (toast == null) {
24 | toast = Toast.makeText(context, context.getResources().getString(msg), Toast.LENGTH_SHORT);
25 | } else {
26 | toast.setText(msg);
27 | }
28 | toast.show();
29 | }
30 |
31 | public static void showTextToast(Context context, String msg) {
32 | if (toast == null) {
33 | toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
34 | } else {
35 | toast.setText(msg);
36 | }
37 | toast.show();
38 | }
39 | public static void showTextToastById(Context context, int msg) {
40 | if (toast == null) {
41 | toast = Toast.makeText(context, context.getResources().getString(msg), Toast.LENGTH_SHORT);
42 | } else {
43 | toast.setText(msg);
44 | }
45 | toast.show();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/utils/UnOverWriteException.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.utils;
2 |
3 | /**
4 | * Description:
5 | *
6 | * @Author:桑小年
7 | * @Data:2016/12/9 9:36
8 | */
9 | public class UnOverWriteException extends RuntimeException {
10 | public UnOverWriteException(String s){
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/utils/ViewUtils.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.utils;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.graphics.Rect;
6 | import android.text.TextUtils;
7 | import android.view.View;
8 |
9 | import java.math.BigDecimal;
10 | import java.text.SimpleDateFormat;
11 | import java.util.Calendar;
12 | import java.util.Date;
13 | import java.util.GregorianCalendar;
14 | import java.util.Locale;
15 |
16 | /**
17 | * Description:
18 | *
19 | * @Author:桑小年
20 | * @Data:2017/2/20 10:29
21 | */
22 | public class ViewUtils {
23 |
24 | /**
25 | * 获取两位小数
26 | *
27 | * @param data
28 | * @return
29 | */
30 | public static float get2Double(double data) {
31 | BigDecimal b = new BigDecimal(data);
32 | // return b.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
33 | // b.setScale(2, BigDecimal.ROUND_HALF_UP) 表明四舍五入,保留两位小数
34 | float v = (float) Double.parseDouble(String.format("%.2f", data));
35 |
36 | return v;
37 | }
38 |
39 | public static String getTime(String flag, Context context){
40 | SharedPreferences preferences = context.getSharedPreferences(Config.sp_name, 0);
41 | String time = formatDateTime(preferences.getLong(flag, 0));
42 | return time;
43 |
44 | }
45 | public static void setTime(String flag,Context context){
46 | if (!TextUtils.isEmpty(flag)) {
47 | SharedPreferences preferences = context.getSharedPreferences(Config.sp_name, 0);
48 | preferences.edit().putLong(flag, System.currentTimeMillis()).commit();
49 | }
50 | }
51 |
52 |
53 | public static String formatDateTime(String dateTime) {
54 | long l = Long.parseLong(dateTime);
55 | return formatDateTime(l);
56 | }
57 |
58 | public static String formatDateTime(long dateTime) {
59 | String text;
60 | Date date = new Date(dateTime);
61 | if (isSameDay(dateTime)) {
62 | Calendar calendar = GregorianCalendar.getInstance();
63 | if (inOneMinute(dateTime, calendar.getTimeInMillis())) {
64 | return "刚刚";
65 | } else if (inOneHour(dateTime, calendar.getTimeInMillis())) {
66 | return String.format("%d分钟之前", Math.abs(dateTime - calendar.getTimeInMillis()) / 60000);
67 | } else {
68 | calendar.setTime(date);
69 | int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);
70 | if (hourOfDay > 17) {
71 | text = "晚上 hh:mm";
72 | } else if (hourOfDay >= 0 && hourOfDay <= 6) {
73 | text = "凌晨 hh:mm";
74 | } else if (hourOfDay > 11 && hourOfDay <= 17) {
75 | text = "下午 hh:mm";
76 | } else {
77 | text = "上午 hh:mm";
78 | }
79 | }
80 | } else if (isYesterday(dateTime)) {
81 | text = "昨天 HH:mm";
82 | } else if (isSameYear(dateTime)) {
83 | text = "M月d日 HH:mm";
84 | } else {
85 | text = "很久以前";
86 | }
87 |
88 | // 注意,如果使用android.text.format.DateFormat这个工具类,在API 17之前它只支持adEhkMmszy
89 | return new SimpleDateFormat(text, Locale.CHINA).format(date);
90 | }
91 |
92 | private static boolean inOneMinute(long time1, long time2) {
93 | return Math.abs(time1 - time2) < 60000;
94 | }
95 |
96 | private static boolean inOneHour(long time1, long time2) {
97 | return Math.abs(time1 - time2) < 3600000;
98 | }
99 |
100 | private static boolean isSameDay(long time) {
101 | long startTime = floorDay(Calendar.getInstance()).getTimeInMillis();
102 | long endTime = ceilDay(Calendar.getInstance()).getTimeInMillis();
103 | return time > startTime && time < endTime;
104 | }
105 |
106 | private static boolean isYesterday(long time) {
107 | Calendar startCal;
108 | startCal = floorDay(Calendar.getInstance());
109 | startCal.add(Calendar.DAY_OF_MONTH, -1);
110 | long startTime = startCal.getTimeInMillis();
111 |
112 | Calendar endCal;
113 | endCal = ceilDay(Calendar.getInstance());
114 | endCal.add(Calendar.DAY_OF_MONTH, -1);
115 | long endTime = endCal.getTimeInMillis();
116 | return time > startTime && time < endTime;
117 | }
118 |
119 | private static boolean isSameYear(long time) {
120 | Calendar startCal;
121 | startCal = floorDay(Calendar.getInstance());
122 | startCal.set(Calendar.MONTH, Calendar.JANUARY);
123 | startCal.set(Calendar.DAY_OF_MONTH, 1);
124 | return time >= startCal.getTimeInMillis();
125 | }
126 |
127 | private static Calendar floorDay(Calendar startCal) {
128 | startCal.set(Calendar.HOUR_OF_DAY, 0);
129 | startCal.set(Calendar.MINUTE, 0);
130 | startCal.set(Calendar.SECOND, 0);
131 | startCal.set(Calendar.MILLISECOND, 0);
132 | return startCal;
133 | }
134 |
135 | private static Calendar ceilDay(Calendar endCal) {
136 | endCal.set(Calendar.HOUR_OF_DAY, 23);
137 | endCal.set(Calendar.MINUTE, 59);
138 | endCal.set(Calendar.SECOND, 59);
139 | endCal.set(Calendar.MILLISECOND, 999);
140 | return endCal;
141 | }
142 |
143 | /**
144 | * 获取View在屏幕中的位置
145 | * @param view
146 | * @return
147 | */
148 | public static int[] getLoaction(View view){
149 | int[] position = new int[2];
150 | view.getLocationOnScreen(position);
151 | return position;
152 | }
153 |
154 |
155 | /**
156 | * 获取View在屏幕中的位置
157 | * @param view
158 | * @return
159 | */
160 | public static Rect getViewRect(View view){
161 | Rect rect = new Rect();
162 | view.getLocalVisibleRect(rect);
163 | return rect;
164 | }
165 |
166 | }
167 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/view/FloatView.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.view;
2 |
3 |
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Color;
7 | import android.text.Spanned;
8 | import android.text.TextUtils;
9 | import android.util.AttributeSet;
10 | import android.util.TypedValue;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.LinearLayout;
14 | import android.widget.TextView;
15 |
16 | import com.sang.viewfractory.R;
17 | import com.sang.viewfractory.utils.DeviceUtils;
18 |
19 |
20 | /**
21 | * 折叠view,模仿微信朋友圈,可折叠消息
22 | */
23 | public class FloatView extends LinearLayout {
24 |
25 | private TextView tv;
26 | private TextView ftv;
27 | private String showContent;
28 | private String hiden;
29 | private int color;
30 |
31 | private int lines;
32 | private OnStateChangeListener listener;
33 | private int textColor;
34 | private float textSize;
35 | private int flowTextColor;
36 | private float flowTextSize;
37 | private int flowBackground;
38 |
39 |
40 | public FloatView(Context context) {
41 | super(context);
42 | initView(context, null, 0);
43 | }
44 |
45 | public FloatView(Context context, AttributeSet attrs) {
46 | super(context, attrs);
47 | initView(context, attrs, 0);
48 | }
49 |
50 | public FloatView(Context context, AttributeSet attrs, int defStyleAttr) {
51 | super(context, attrs, defStyleAttr);
52 | initView(context, attrs, defStyleAttr);
53 | }
54 |
55 | private boolean isExpand;
56 |
57 | public interface OnStateChangeListener{
58 | void onStateChange(boolean isExpand);
59 | }
60 |
61 | public void setOnStateChangeListener(OnStateChangeListener listener){
62 | this.listener=listener;
63 | }
64 |
65 |
66 | private void initView(Context context, AttributeSet attrs, int defStyleAttr){
67 |
68 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FloatView);
69 | textColor = typedArray.getColor(R.styleable.FloatView_textColor, Color.BLACK);
70 | textSize = typedArray.getDimension(R.styleable.FloatView_textSize, 14);
71 | lines = typedArray.getInteger(R.styleable.FloatView_showLines, 5);
72 | flowTextColor = typedArray.getColor(R.styleable.FloatView_flowTextColor, Color.parseColor("#4c69c5"));
73 | flowTextSize = typedArray.getDimension(R.styleable.FloatView_flowTextSize, textSize);
74 | flowBackground = typedArray.getResourceId(R.styleable.FloatView_flowBackground, R.drawable.select_tv_bg);
75 | showContent=typedArray.getString(R.styleable.FloatView_textShow);
76 | if (TextUtils.isEmpty(showContent)){
77 | showContent=context.getString(R.string.showContent);
78 | }
79 | hiden=typedArray.getString(R.styleable.FloatView_textHide);
80 | if (TextUtils.isEmpty(hiden)){
81 | hiden=context.getString(R.string.hiden);
82 | }
83 |
84 | setOrientation(VERTICAL);
85 | LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
86 | tv = new TextView(context);
87 | tv.setTextColor(textColor);
88 | tv.setTextSize(TypedValue.COMPLEX_UNIT_PX,textSize);
89 |
90 | tv.setTextIsSelectable(true);
91 | tv.setLayoutParams(params);
92 |
93 | ftv =new TextView(context);
94 | ftv.setTextColor(flowTextColor);
95 | ftv.setTextSize(TypedValue.COMPLEX_UNIT_PX,flowTextSize);
96 | ftv.setClickable(true);
97 | ftv.setText(showContent);
98 | ftv.setBackground(getResources().getDrawable(flowBackground));
99 | ftv.setTextColor(flowTextColor);
100 | LayoutParams imgParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
101 | imgParams.setMargins(0, DeviceUtils.dip2px(context,10),0,0);
102 | ftv.setLayoutParams(imgParams);
103 | addView(tv);
104 | addView(ftv);
105 | ftv.setOnClickListener(new OnClickListener() {
106 | @Override
107 | public void onClick(View v) {
108 | if (!isExpand){
109 | int lineCount= tv.getLineCount();
110 | int height = tv.getLineHeight();
111 | changeHeight(Math.max(mheight,lineCount*height));
112 | ftv.setText(hiden);
113 | }else {
114 | ftv.setText(showContent);
115 | int height = tv.getLineHeight();
116 | changeHeight(height*lines);
117 | }
118 | if (listener!=null){
119 | listener.onStateChange(isExpand);
120 | }
121 | isExpand=!isExpand;
122 | }
123 | });
124 |
125 |
126 | }
127 |
128 |
129 | /**
130 | * 设置显示内容
131 | * @param text
132 | */
133 | public void setText(String text) {
134 | tv.setText(text);
135 | changeTv();
136 | }
137 |
138 | private float mheight;
139 |
140 | private void changeTv() {
141 | tv.post(new Runnable() {
142 | @Override
143 | public void run() {
144 | int lineCount= tv.getLineCount();
145 | int height = tv.getLineHeight();
146 | FloatView.this.mheight=tv.getHeight();
147 | if (lineCount>lines){
148 | isExpand=false;
149 | changeHeight(height*lines);
150 | ftv.setVisibility(VISIBLE);
151 | }else {
152 | isExpand=true;
153 | ftv.setVisibility(GONE);
154 | }
155 |
156 | }
157 | });
158 | }
159 |
160 |
161 | private void changeHeight(float h){
162 | ViewGroup.LayoutParams params = tv.getLayoutParams();
163 | params.height=(int) h;
164 | tv.setLayoutParams(params);
165 | }
166 |
167 |
168 | public void setText(Spanned text) {
169 | tv.setText(text);
170 | changeTv();
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/view/HorizontalProgress.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.view;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.util.AttributeSet;
8 | import android.widget.ProgressBar;
9 |
10 | import com.sang.viewfractory.R;
11 | import com.sang.viewfractory.utils.DeviceUtils;
12 | import com.sang.viewfractory.utils.ViewUtils;
13 |
14 |
15 | /**
16 | * 作者: ${桑小年} on 2016/5/22.
17 | * 努力,为梦长留
18 | */
19 | public class HorizontalProgress extends ProgressBar {
20 |
21 |
22 | private static final int DEFAULT_TEXT_SIZE = 10;
23 | private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;
24 | private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;
25 | private int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR ;
26 | private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;
27 | private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;
28 |
29 | public Paint mPaint =new Paint();
30 |
31 | /**
32 | * 到达的进度条颜色
33 | */
34 | public int recarchColor;
35 | /**
36 | * 没有到达的进度条颜色
37 | */
38 | public int unRecarchColor;
39 |
40 | /**
41 | * 字体大小
42 | */
43 | public int textSize;
44 |
45 | /**
46 | * 字体颜色
47 | */
48 | public int textColor;
49 |
50 | /**
51 | * 进度条高度
52 | */
53 | public int mHeight;
54 |
55 | /**
56 | * 字体两边的距离
57 | */
58 | public int textOffset;
59 |
60 | /**
61 | * 是否显示字体
62 | */
63 | public int textVisible ;
64 |
65 |
66 | public boolean ifDrawText=true;
67 |
68 | /**控件宽度*/
69 | public int mRealWidth;
70 |
71 | public boolean ifRech =false;
72 | public int textWidth;
73 |
74 | public HorizontalProgress(Context context) {
75 | this(context, null);
76 | }
77 |
78 | public HorizontalProgress(Context context, AttributeSet attrs) {
79 | this(context, attrs, 0);
80 | }
81 |
82 | public HorizontalProgress(Context context, AttributeSet attrs, int defStyleAttr) {
83 | super(context, attrs, defStyleAttr);
84 |
85 | setHorizontalScrollBarEnabled(true);
86 |
87 | initView(context, attrs, defStyleAttr);
88 |
89 | mPaint.setColor(textColor);
90 | mPaint.setTextSize(textSize);
91 | }
92 |
93 | /**
94 | * 初始化属性
95 | */
96 | private void initView(Context context, AttributeSet attrs, int defStyleAttr) {
97 | DEFAULT_HEIGHT_REACHED_PROGRESS_BAR= DeviceUtils.dip2px(context,2);
98 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HorizontalProgress);
99 | textColor = typedArray.getColor(R.styleable.HorizontalProgress_progress_text_color, DEFAULT_TEXT_COLOR);
100 |
101 |
102 | recarchColor = typedArray.getColor(R.styleable.HorizontalProgress_progress_reached_color, textColor);
103 | unRecarchColor =typedArray.getColor(R.styleable.HorizontalProgress_progress_unreached_color,DEFAULT_COLOR_UNREACHED_COLOR);
104 | textSize = (int) typedArray.getDimension(R.styleable.HorizontalProgress_progress_text_size,DEFAULT_TEXT_SIZE);
105 | textOffset = (int) typedArray.getDimension(R.styleable.HorizontalProgress_progress_text_offset,textOffset);
106 | mHeight = (int) typedArray.getDimension(R.styleable.HorizontalProgress_progress_height,DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
107 | textVisible=typedArray.getInt(R.styleable.HorizontalProgress_progress_text_visibility,VISIBLE);
108 |
109 | if (textVisible!=VISIBLE){
110 | ifDrawText=false;
111 | }
112 |
113 |
114 | typedArray.recycle();
115 | }
116 |
117 |
118 | @Override
119 | protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
120 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
121 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
122 |
123 | //在用户没有指定进度条高度的情况下,使用我们自定义的高度,否则就直接使用用户指定的高度了
124 | if (heightMode!=MeasureSpec.EXACTLY){
125 | //获取文本高度
126 | float textHeighe = mPaint.ascent()+mPaint.descent();
127 | //获取进度条高度,取文本和进度条之间的最大值
128 | float ecptHeitht = getPaddingTop()+getPaddingBottom()+Math.max(textHeighe,mHeight);
129 | heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) ecptHeitht,MeasureSpec.EXACTLY);
130 | }
131 |
132 | setMeasuredDimension(widthMeasureSpec,heightMeasureSpec);
133 | }
134 |
135 | @Override
136 | protected synchronized void onDraw(Canvas canvas) {
137 | super.onDraw(canvas);
138 | canvas.save();
139 |
140 |
141 | //将画笔移动到控件最左侧{getpaddintLeft,getHeight()/2},以此作为基础(0,0)
142 | canvas.translate(getPaddingLeft(),getHeight()/2);
143 |
144 | //获取当前进度
145 | float radio = getProgress()*1.0f/getMax();
146 |
147 |
148 |
149 | mRealWidth=getMeasuredWidth()-getPaddingLeft()-getPaddingRight()-textWidth;
150 | //已经到达的宽度
151 | float progressX = (mRealWidth*radio);
152 |
153 |
154 | //如果到达最后,则不再绘制未到达的进度
155 | // if (progressX+ textWidth >mRealWidth){
156 | // progressX = mRealWidth - textWidth;
157 | // ifRech=true;
158 | // }
159 | if (progressX >mRealWidth){
160 | progressX = mRealWidth ;
161 | ifRech=true;
162 | }
163 |
164 | //绘制已经到达的进度
165 | float endX = progressX-textOffset/2;
166 | if (endX>0) {
167 | mPaint.setColor(recarchColor);
168 | mPaint.setStrokeWidth(mHeight);
169 | canvas.drawLine(0,0,endX,0,mPaint);
170 | }
171 | if (ifDrawText){
172 | mPaint.setColor(textColor);
173 | //需要画出的文本
174 | String text = ViewUtils.get2Double(radio * 100) + "%";
175 |
176 |
177 | //文字的宽高
178 | textWidth = (int) mPaint.measureText(text);
179 |
180 | int textHeight = (int) (mPaint.descent() + mPaint.ascent());
181 | //绘制文本
182 | canvas.drawText(text,progressX,-textHeight/2,mPaint);
183 | }
184 |
185 |
186 | //绘制尚未到达的进度条
187 | if (!ifRech){
188 | mPaint.setColor(unRecarchColor);
189 | mPaint.setStrokeWidth(mHeight);
190 | canvas.drawLine(progressX+textOffset/2+ textWidth,0,mRealWidth+textWidth,0,mPaint);
191 | }
192 |
193 | canvas.restore();
194 |
195 |
196 |
197 | }
198 |
199 | @Override
200 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
201 | super.onSizeChanged(w, h, oldw, oldh);
202 |
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/view/RefrushLinearLayout.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.view;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.util.AttributeSet;
6 | import android.util.TypedValue;
7 | import android.view.Gravity;
8 | import android.widget.LinearLayout;
9 | import android.widget.TextView;
10 |
11 | import com.sang.viewfractory.BasicView;
12 | import com.sang.viewfractory.utils.Apputils;
13 | import com.sang.viewfractory.utils.ViewUtils;
14 |
15 |
16 | /**
17 | * Description:下拉刷新
18 | *
19 | * @Author:桑小年
20 | * @Data:2016/12/9 10:50
21 | */
22 | public class RefrushLinearLayout extends LinearLayout {
23 |
24 | public final static int STYLE_LOAD=ShapeView.STYLE_LOAD;
25 | public final static int STYLE_SQUARE=ShapeView.STYLE_SQUARE;
26 | private TextView tvMsg, tvTime;
27 | private BasicView shapeView;
28 |
29 | private String flag;
30 |
31 | public RefrushLinearLayout(Context context) {
32 | super(context);
33 | initView(context, null, 0);
34 | }
35 |
36 | public RefrushLinearLayout(Context context, AttributeSet attrs) {
37 | super(context, attrs);
38 | initView(context, attrs, 0);
39 | }
40 |
41 | public RefrushLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
42 | super(context, attrs, defStyleAttr);
43 | initView(context, attrs, defStyleAttr);
44 | }
45 |
46 | LinearLayout l;
47 | int gap;
48 | private void initView(Context context, AttributeSet attrs, int defStyleAttr) {
49 |
50 | gap = Apputils.dip2px(context, 5);
51 | setGravity(Gravity.CENTER);
52 | setOrientation(HORIZONTAL);
53 | shapeView = new ShapeView(context);
54 | LayoutParams params = new LayoutParams(Apputils.dip2px(context, 30), Apputils.dip2px(context, 30));
55 | shapeView.setLayoutParams(params);
56 | tvMsg = new TextView(context);
57 | tvMsg.setTextSize(TypedValue.COMPLEX_UNIT_PX, Apputils.sp2px(context, 16));
58 | tvMsg.setText("准备刷新数据");
59 | tvTime = new TextView(context);
60 | tvTime.setTextSize(TypedValue.COMPLEX_UNIT_PX, Apputils.sp2px(context, 12));
61 | l = new LinearLayout(context);
62 | l.addView(tvMsg);
63 | l.addView(tvTime);
64 | l.setOrientation(LinearLayout.VERTICAL);
65 | l.setPadding(gap, 0, 0, 0);
66 | addView(shapeView);
67 | addView(l);
68 | setPadding(gap, gap, gap, gap);
69 | }
70 |
71 | public void setStyle(int style){
72 | shapeView.setStyle(style);
73 | }
74 |
75 |
76 |
77 |
78 | @Override
79 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
80 | super.onLayout(changed, l, t, r, b);
81 | setOrientation(HORIZONTAL);
82 | }
83 |
84 | /**
85 | * 设置显示数据
86 | *
87 | * @param msg
88 | */
89 | public void setTvMsg(String msg) {
90 | tvMsg.setText(msg);
91 | }
92 |
93 |
94 | /**
95 | * 设置刷新时间
96 | *
97 | * @param flag 设置刷新时间的view标志
98 | * @param context 上下文
99 | */
100 | public void setTvTime(String flag, Context context) {
101 | tvTime.setText("上次刷新:" + ViewUtils.getTime(flag, context));
102 |
103 | }
104 |
105 | /**
106 | * 设置刷新时间的flag
107 | *
108 | * @param flag 用来判断当前刷新的View,如果不设置,则无法显示刷新时间
109 | */
110 | public void setFlag(String flag) {
111 | this.flag = flag;
112 | tvTime.setVisibility(VISIBLE);
113 | }
114 |
115 |
116 | public void upState(int state) {
117 | shapeView.upState(state);
118 | if (state == ShapeView.LOAD_SUCCESS) {
119 | if (!TextUtils.isEmpty(flag)) {
120 | ViewUtils.setTime(flag, getContext());
121 | }
122 | }else {
123 | if (!TextUtils.isEmpty(flag)) {
124 | setTvTime(flag,getContext());
125 | tvTime.setVisibility(VISIBLE);
126 | }else {
127 | tvTime.setVisibility(GONE);
128 |
129 | }
130 | }
131 | }
132 |
133 | public String getTest() {
134 | return tvMsg.getText().toString();
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/viewfractory/src/main/java/com/sang/viewfractory/view/ShapeView.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory.view;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.ValueAnimator;
6 | import android.content.Context;
7 | import android.graphics.Bitmap;
8 | import android.util.AttributeSet;
9 | import android.view.animation.LinearInterpolator;
10 |
11 | import com.sang.viewfractory.BasicView;
12 |
13 | /**
14 | * Description:
15 | *
16 | * @Author:桑小年
17 | * @Data:2016/12/6 10:49
18 | */
19 | public class ShapeView extends BasicView {
20 |
21 |
22 |
23 |
24 | public ShapeView(Context context) {
25 | super(context);
26 |
27 |
28 | }
29 |
30 | public ShapeView(Context context, AttributeSet attrs) {
31 | super(context, attrs);
32 |
33 | }
34 |
35 | public ShapeView(Context context, AttributeSet attrs, int defStyleAttr) {
36 | super(context, attrs, defStyleAttr);
37 |
38 | }
39 |
40 |
41 |
42 | private boolean change;
43 | protected void flipAnimation() {
44 | clearViewAnimation();
45 |
46 | flip=creatAnimotion();
47 | flip.setInterpolator(new LinearInterpolator());
48 | flip.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
49 | @Override
50 | public void onAnimationUpdate(ValueAnimator animation) {
51 | float value = (float) animation.getAnimatedValue();
52 | switch (style){
53 | case STYLE_SQUARE:
54 | if (change) {
55 | setScaleX(value);
56 | } else {
57 | setScaleY(value);
58 | }
59 | break;
60 | case STYLE_LOAD:
61 |
62 | setRotation(360*value);
63 | break;
64 | }
65 |
66 |
67 | }
68 | });
69 | flip.addListener(new AnimatorListenerAdapter() {
70 | @Override
71 | public void onAnimationRepeat(Animator animation) {
72 | super.onAnimationRepeat(animation);
73 | change = !change;
74 | }
75 |
76 | @Override
77 | public void onAnimationCancel(Animator animation) {
78 | super.onAnimationCancel(animation);
79 | setScaleX(1);
80 | setScaleY(1);
81 |
82 | }
83 | });
84 | flip.setRepeatCount(Integer.MAX_VALUE);
85 | long time = getTime();
86 | flip.setDuration(time);
87 | flip.start();
88 | }
89 |
90 | private ValueAnimator creatAnimotion() {
91 | ValueAnimator animator ;
92 | switch (style){
93 | case STYLE_LOAD:
94 | animator = ValueAnimator.ofFloat(1f,0f);
95 | break;
96 | default:
97 | animator = ValueAnimator.ofFloat(1f, 0f, 1f);
98 | break;
99 | }
100 |
101 | return animator;
102 | }
103 |
104 | /**
105 | * 动画执行时间
106 | * @return
107 | */
108 | private long getTime() {
109 | long time ;
110 | switch (style){
111 | case STYLE_LOAD:
112 | time=5000;
113 | break;
114 | default:
115 | time=1000;
116 | break;
117 | }
118 | return time;
119 | }
120 |
121 | @Override
122 | protected Bitmap creatShape(int mWidth,int mHeight) {
123 | Bitmap bitmap;
124 | switch (style){
125 | case STYLE_LOAD:
126 | bitmap = factory.creatLoading(mWidth, mHeight);
127 | break;
128 | default:
129 | bitmap= factory.creatShap(mWidth,mHeight);
130 | break;
131 | }
132 | return bitmap;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/viewfractory/src/main/res/drawable/bt_gry.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/viewfractory/src/main/res/drawable/bt_tran.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/viewfractory/src/main/res/drawable/select_tv_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/viewfractory/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | private int centerColor,otherColor,lineColor;
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/viewfractory/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #00ffffff
5 | #404040
6 | #303030
7 | #afafaf
8 | #efefef
9 | #7a7a7a
10 | #fa5559
11 | #52bf7f
12 | #bdbdbd
13 | #1798f2
14 |
15 | #f3f3f3
16 | #5b6d99
17 | #4c69c5
18 | #B2B2B2
19 | #78D2F6
20 | #01AAEE
21 | #00AAEE
22 | #F3323B
23 |
24 |
--------------------------------------------------------------------------------
/viewfractory/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ViewFractory
3 | 全文
4 | 收起
5 |
6 |
--------------------------------------------------------------------------------
/viewfractory/src/test/java/com/sang/viewfractory/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.sang.viewfractory;
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 | }
--------------------------------------------------------------------------------