list = new ArrayList<>();
51 | for (int i = 0; i < 100; i++) {
52 | list.add(String.valueOf(i));
53 | }
54 | mAdapter.fillList(list);
55 | }
56 |
57 | @OnClick({R.id.hori_btn, R.id.vert_btn, R.id.grid_h_btn, R.id.grid_v_btn})
58 | public void onClick(View view) {
59 | switch (view.getId()) {
60 | case R.id.hori_btn:
61 | if (mDecoration != null) {
62 | mDividerRv.removeItemDecoration(mDecoration);
63 | }
64 | mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
65 | mDividerRv.setLayoutManager(mLayoutManager);
66 | mDecoration = new HorizontalDividerDecoration(this, R.drawable.divider_drawable);
67 | mDividerRv.addItemDecoration(mDecoration);
68 | break;
69 | case R.id.vert_btn:
70 | if (mDecoration != null) {
71 | mDividerRv.removeItemDecoration(mDecoration);
72 | }
73 | mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
74 | mDividerRv.setLayoutManager(mLayoutManager);
75 | mDecoration = new VerticalDividerDecoration(this, R.drawable.divider_drawable);
76 | mDividerRv.addItemDecoration(mDecoration);
77 | break;
78 | case R.id.grid_h_btn:
79 | if (mDecoration != null) {
80 | mDividerRv.removeItemDecoration(mDecoration);
81 | }
82 | mLayoutManager = new GridLayoutManager(this, 4, GridLayoutManager.HORIZONTAL, false);
83 | mDividerRv.setLayoutManager(mLayoutManager);
84 | mDecoration = new GridDividerDecoration(this, GridDividerDecoration.HORIZONTAL_LIST,
85 | R.drawable.divider_drawable);
86 | mDividerRv.addItemDecoration(mDecoration);
87 | break;
88 | case R.id.grid_v_btn:
89 | if (mDecoration != null) {
90 | mDividerRv.removeItemDecoration(mDecoration);
91 | }
92 | mLayoutManager = new GridLayoutManager(this, 4, GridLayoutManager.VERTICAL, false);
93 | mDividerRv.setLayoutManager(mLayoutManager);
94 | mDecoration = new GridDividerDecoration(this, GridDividerDecoration.VERTICAL_LIST,
95 | R.drawable.divider_drawable);
96 | mDividerRv.addItemDecoration(mDecoration);
97 | break;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/app/src/main/java/net/devwiki/recyclerview/single/SingleItemClickSupport.java:
--------------------------------------------------------------------------------
1 | package net.devwiki.recyclerview.single;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.View;
5 |
6 | import net.devwiki.recyclerview.R;
7 |
8 | /**
9 | * SingleItem的点击事件
10 | * Created by zyz on 2016/7/20.
11 | */
12 |
13 | public class SingleItemClickSupport {
14 | private final RecyclerView mRecyclerView;
15 | private OnItemClickListener mOnItemClickListener;
16 | private OnItemLongClickListener mOnItemLongClickListener;
17 | private View.OnClickListener mOnClickListener = new View.OnClickListener() {
18 | @Override
19 | public void onClick(View v) {
20 | if (mOnItemClickListener != null) {
21 | RecyclerView.ViewHolder holder = mRecyclerView.findContainingViewHolder(v);
22 | if (holder != null) {
23 | if (v.getId() == R.id.name_tv) {
24 | mOnItemClickListener.onNameClicked(mRecyclerView, holder.getAdapterPosition(), v);
25 | } else {
26 | mOnItemClickListener.onAgeClicked(mRecyclerView, holder.getAdapterPosition(), v);
27 | }
28 | }
29 | }
30 | }
31 | };
32 | private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
33 | @Override
34 | public boolean onLongClick(View v) {
35 | if (mOnItemLongClickListener != null) {
36 | RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
37 | return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
38 | }
39 | return false;
40 | }
41 | };
42 | private RecyclerView.OnChildAttachStateChangeListener mAttachListener
43 | = new RecyclerView.OnChildAttachStateChangeListener() {
44 | @Override
45 | public void onChildViewAttachedToWindow(View view) {
46 | if (mOnItemClickListener != null) {
47 | view.setOnClickListener(mOnClickListener);
48 | RecyclerView.ViewHolder viewHolder = mRecyclerView.getChildViewHolder(view);
49 | if (viewHolder instanceof SingleHolder) {
50 | SingleHolder singleHolder = (SingleHolder) viewHolder;
51 | singleHolder.nameView.setOnClickListener(mOnClickListener);
52 | singleHolder.ageView.setOnClickListener(mOnClickListener);
53 | }
54 | }
55 | if (mOnItemLongClickListener != null) {
56 | view.setOnLongClickListener(mOnLongClickListener);
57 | }
58 | }
59 |
60 | @Override
61 | public void onChildViewDetachedFromWindow(View view) {
62 |
63 | }
64 | };
65 |
66 | private SingleItemClickSupport(RecyclerView recyclerView) {
67 | mRecyclerView = recyclerView;
68 | mRecyclerView.setTag(net.devwiki.recycler.R.id.item_click_support, this);
69 | mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
70 | }
71 |
72 | public static SingleItemClickSupport addTo(RecyclerView view) {
73 | SingleItemClickSupport support = (SingleItemClickSupport) view.getTag(net.devwiki.recycler.R.id.item_click_support);
74 | if (support == null) {
75 | support = new SingleItemClickSupport(view);
76 | }
77 | return support;
78 | }
79 |
80 | public static SingleItemClickSupport removeFrom(RecyclerView view) {
81 | SingleItemClickSupport support = (SingleItemClickSupport) view.getTag(net.devwiki.recycler.R.id.item_click_support);
82 | if (support != null) {
83 | support.detach(view);
84 | }
85 | return support;
86 | }
87 |
88 | public SingleItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
89 | mOnItemClickListener = listener;
90 | return this;
91 | }
92 |
93 | public SingleItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
94 | mOnItemLongClickListener = listener;
95 | return this;
96 | }
97 |
98 | private void detach(RecyclerView view) {
99 | view.removeOnChildAttachStateChangeListener(mAttachListener);
100 | view.setTag(net.devwiki.recycler.R.id.item_click_support, null);
101 | }
102 |
103 | public interface OnItemClickListener {
104 |
105 | void onNameClicked(RecyclerView recyclerView, int position, View view);
106 |
107 | void onAgeClicked(RecyclerView recyclerView, int position, View view);
108 | }
109 |
110 | public interface OnItemLongClickListener {
111 |
112 | boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
113 | }
114 | }
--------------------------------------------------------------------------------
/recycler/src/main/java/net/devwiki/recycler/DividerDecoration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.devwiki.recycler;
18 |
19 | import android.content.Context;
20 | import android.graphics.Canvas;
21 | import android.graphics.Rect;
22 | import android.graphics.drawable.Drawable;
23 | import android.support.annotation.DrawableRes;
24 | import android.support.v4.view.ViewCompat;
25 | import android.support.v7.widget.LinearLayoutManager;
26 | import android.support.v7.widget.RecyclerView;
27 | import android.view.View;
28 |
29 | /**
30 | * 普通的分割线,垂直列表绘制每一行的底部分割线,水平列表绘制每一列的右侧分割线
31 | */
32 | public class DividerDecoration extends RecyclerView.ItemDecoration {
33 |
34 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
35 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
36 |
37 | Drawable mDivider;
38 | int mOrientation;
39 |
40 | public DividerDecoration(Context context, int orientation) {
41 | mDivider = context.getResources().getDrawable(R.drawable.base_divider);
42 | mOrientation = orientation;
43 | }
44 |
45 | public DividerDecoration(Context context, int orientation, @DrawableRes int resId) {
46 | mDivider = context.getResources().getDrawable(resId);
47 | if (mDivider == null) {
48 | mDivider = context.getResources().getDrawable(R.drawable.base_divider);
49 | }
50 | mOrientation = orientation;
51 | }
52 |
53 | public DividerDecoration(Context context, int orientation, Drawable drawable) {
54 | mDivider = drawable == null ? context.getResources().getDrawable(R.drawable.base_divider) : drawable;
55 | mOrientation = orientation;
56 | }
57 |
58 | public void setDivider(Drawable drawable) {
59 | if (drawable != null) {
60 | mDivider = drawable;
61 | }
62 | }
63 |
64 | public void setOrientation(int orientation) {
65 | mOrientation = orientation;
66 | }
67 |
68 | public int getOrientation() {
69 | return mOrientation;
70 | }
71 |
72 | @Override
73 | public void onDraw(Canvas c, RecyclerView parent) {
74 | if (mOrientation == VERTICAL_LIST) {
75 | drawVertical(c, parent);
76 | } else {
77 | drawHorizontal(c, parent);
78 | }
79 | }
80 |
81 | public void drawVertical(Canvas c, RecyclerView parent) {
82 | final int left = parent.getPaddingLeft();
83 | final int right = parent.getWidth() - parent.getPaddingRight();
84 |
85 | final int childCount = parent.getChildCount();
86 | for (int i = 0; i < childCount; i++) {
87 | final View child = parent.getChildAt(i);
88 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
89 | final int top = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));
90 | final int bottom = top + mDivider.getIntrinsicHeight();
91 | mDivider.setBounds(left, top, right, bottom);
92 | mDivider.draw(c);
93 | }
94 | }
95 |
96 | public void drawHorizontal(Canvas c, RecyclerView parent) {
97 | final int top = parent.getPaddingTop();
98 | final int bottom = parent.getHeight() - parent.getPaddingBottom();
99 |
100 | final int childCount = parent.getChildCount();
101 | for (int i = 0; i < childCount; i++) {
102 | final View child = parent.getChildAt(i);
103 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
104 | final int left = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));
105 | final int right = left + mDivider.getIntrinsicHeight();
106 | mDivider.setBounds(left, top, right, bottom);
107 | mDivider.draw(c);
108 | }
109 | }
110 |
111 | @Override
112 | public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
113 | if (mOrientation == VERTICAL_LIST) {
114 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
115 | } else {
116 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/app/src/main/java/net/devwiki/recyclerview/single/SingleActivity.java:
--------------------------------------------------------------------------------
1 | package net.devwiki.recyclerview.single;
2 |
3 | import android.graphics.drawable.Drawable;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.support.v7.widget.LinearLayoutManager;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.widget.Toast;
11 |
12 | import net.devwiki.log.DevLog;
13 | import net.devwiki.recycler.DividerDecoration;
14 | import net.devwiki.recyclerview.MockService;
15 | import net.devwiki.recyclerview.R;
16 |
17 | public class SingleActivity extends AppCompatActivity {
18 |
19 | private RecyclerView recyclerView;
20 | private LinearLayoutManager layoutManager;
21 | private SingleAdapter singleAdapter;
22 | private MockService mockService;
23 |
24 | private SingleItemClickListener touchListener;
25 | private SingleAdapter.OnSingleItemClickListener adapterListener;
26 | private SingleItemClickSupport supportListener;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_single);
32 |
33 | mockService = new MockService();
34 | singleAdapter = new SingleAdapter(this);
35 | singleAdapter.fillList(mockService.getPersonList());
36 |
37 | recyclerView = (RecyclerView) findViewById(R.id.single_rv);
38 | layoutManager = new LinearLayoutManager(this);
39 | recyclerView.setLayoutManager(layoutManager);
40 | DividerDecoration decoration = new DividerDecoration(this, DividerDecoration.VERTICAL_LIST);
41 | Drawable drawable = getResources().getDrawable(R.drawable.divider_single);
42 | decoration.setDivider(drawable);
43 | recyclerView.addItemDecoration(decoration);
44 | recyclerView.setAdapter(singleAdapter);
45 |
46 | View view = LayoutInflater.from(this).inflate(R.layout.item_single_header, null, false);
47 | singleAdapter.addHeaderView(view);
48 |
49 | String type = getIntent().getStringExtra("type");
50 | if ("adapter".equals(type)) {
51 | setClickListenerWithAdapter();
52 | } else if ("touch".equals(type)) {
53 | setClickListenerWithTouch();
54 | } else {
55 | setClickListenerWithSupport();
56 | }
57 | }
58 |
59 | private void setClickListenerWithTouch() {
60 | recyclerView.addOnItemTouchListener(new SingleItemClickListener(recyclerView,
61 | new SingleItemClickListener.OnItemClickListener() {
62 |
63 | @Override
64 | public void onItemClick(View view, int position) {
65 | DevLog.i("touch click name:" + position);
66 | Toast.makeText(SingleActivity.this, "touch click:" + position, Toast.LENGTH_SHORT).show();
67 | }
68 |
69 | @Override
70 | public void onItemLongClick(View view, int position) {
71 | DevLog.i("touch long click:" + position);
72 | Toast.makeText(SingleActivity.this, "touch long click:" + position, Toast.LENGTH_SHORT).show();
73 | }
74 | }));
75 | }
76 |
77 | private void setClickListenerWithAdapter() {
78 | singleAdapter.setClickListener(new SingleAdapter.OnSingleItemClickListener() {
79 | @Override
80 | public void onNameClick(int position) {
81 | DevLog.i("adapter click name:" + position);
82 | Toast.makeText(SingleActivity.this, "adapter click name:" + position, Toast.LENGTH_SHORT).show();
83 | }
84 |
85 | @Override
86 | public void onAgeClick(int position) {
87 | DevLog.i("adapter click age:" + position);
88 | Toast.makeText(SingleActivity.this, "adapter click name:" + position, Toast.LENGTH_SHORT).show();
89 | }
90 | });
91 | }
92 |
93 | private void setClickListenerWithSupport() {
94 | SingleItemClickSupport.addTo(recyclerView)
95 | .setOnItemClickListener(new SingleItemClickSupport.OnItemClickListener() {
96 |
97 | @Override
98 | public void onNameClicked(RecyclerView recyclerView, int position, View view) {
99 | DevLog.i("support name click:" + position);
100 | Toast.makeText(SingleActivity.this, "support click name:" + position, Toast.LENGTH_SHORT).show();
101 | }
102 |
103 | @Override
104 | public void onAgeClicked(RecyclerView recyclerView, int position, View view) {
105 | DevLog.i("support age click:" + position);
106 | Toast.makeText(SingleActivity.this, "support click name:" + position, Toast.LENGTH_SHORT).show();
107 | }
108 | });
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/recycler/src/main/java/net/devwiki/recycler/BaseAdapter.java:
--------------------------------------------------------------------------------
1 | package net.devwiki.recycler;
2 |
3 | import android.content.Context;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * 基础的Adapter
10 | *
11 | * Created by DevWiki on 2016/7/13.
12 | */
13 |
14 | public abstract class BaseAdapter extends AbsAdapter {
15 |
16 | private List dataList;
17 |
18 | public BaseAdapter(Context context) {
19 | super(context);
20 | this.dataList = new ArrayList<>();
21 | }
22 |
23 | public BaseAdapter(Context context, List list) {
24 | super(context);
25 | this.dataList = new ArrayList<>();
26 | this.dataList.addAll(list);
27 | }
28 |
29 | /**
30 | * 填充数据,此操作会清除原来的数据
31 | *
32 | * @param list 要填充的数据
33 | * @return true:填充成功并调用刷新数据
34 | */
35 | public boolean fillList(List list) {
36 | dataList.clear();
37 | boolean result = dataList.addAll(list);
38 | if (result) {
39 | notifyDataSetChanged();
40 | }
41 | return result;
42 | }
43 |
44 | /**
45 | * 追加一条数据
46 | *
47 | * @param data 要追加的数据
48 | * @return true:追加成功并刷新界面
49 | */
50 | public boolean appendItem(M data) {
51 | boolean result = dataList.add(data);
52 | if (result) {
53 | if (getHeaderExtraViewCount() == 0) {
54 | notifyItemInserted(dataList.size() - 1);
55 | } else {
56 | notifyItemInserted(dataList.size());
57 | }
58 | }
59 | return result;
60 | }
61 |
62 | /**
63 | * 追加集合数据
64 | *
65 | * @param list 要追加的集合数据
66 | * @return 追加成功并刷新
67 | */
68 | public boolean appendList(List list) {
69 | boolean result = dataList.addAll(list);
70 | if (result) {
71 | notifyDataSetChanged();
72 | }
73 | return result;
74 | }
75 |
76 | /**
77 | * 在最顶部前置数据
78 | *
79 | * @param data 要前置的数据
80 | */
81 | public void proposeItem(M data) {
82 | dataList.add(0, data);
83 | if (getHeaderExtraViewCount() == 0) {
84 | notifyItemInserted(0);
85 | } else {
86 | notifyItemInserted(getHeaderExtraViewCount());
87 | }
88 | }
89 |
90 | /**
91 | * 在顶部前置数据集合
92 | *
93 | * @param list 要前置的数据集合
94 | */
95 | public void proposeList(List list) {
96 | dataList.addAll(0, list);
97 | notifyDataSetChanged();
98 | }
99 |
100 | @Override
101 | public long getItemId(int position) {
102 | return position;
103 | }
104 |
105 | @Override
106 | public final int getItemViewType(int position) {
107 | if (headerView != null && position == 0) {
108 | return VIEW_TYPE_HEADER;
109 | } else if (footerView != null && position == dataList.size() + getHeaderExtraViewCount()) {
110 | return VIEW_TYPE_FOOTER;
111 | } else {
112 | return getCustomViewType(position);
113 | }
114 | }
115 |
116 | /**
117 | * 获取自定义View的类型
118 | *
119 | * @param position 位置
120 | * @return View的类型
121 | */
122 | public abstract int getCustomViewType(int position);
123 |
124 | @Override
125 | public int getItemCount() {
126 | return dataList.size() + getExtraViewCount();
127 | }
128 |
129 | /**
130 | * 根据位置获取一条数据
131 | *
132 | * @param position View的位置
133 | * @return 数据
134 | */
135 | public M getItem(int position) {
136 | if (headerView != null && position == 0
137 | || position >= dataList.size() + getHeaderExtraViewCount()) {
138 | return null;
139 | }
140 | return headerView == null ? dataList.get(position) : dataList.get(position - 1);
141 | }
142 |
143 | /**
144 | * 根据ViewHolder获取数据
145 | *
146 | * @param holder ViewHolder
147 | * @return 数据
148 | */
149 | public M getItem(VH holder) {
150 | return getItem(holder.getAdapterPosition());
151 | }
152 |
153 | public void updateItem(M data) {
154 | int index = dataList.indexOf(data);
155 | if (index < 0) {
156 | return;
157 | }
158 | dataList.set(index, data);
159 | if (headerView == null) {
160 | notifyItemChanged(index);
161 | } else {
162 | notifyItemChanged(index + 1);
163 | }
164 | }
165 |
166 | /**
167 | * 移除一条数据
168 | *
169 | * @param position 位置
170 | */
171 | public void removeItem(int position) {
172 | if (headerView == null) {
173 | dataList.remove(position);
174 | } else {
175 | dataList.remove(position - 1);
176 | }
177 | notifyItemRemoved(position);
178 | }
179 |
180 | /**
181 | * 移除一条数据
182 | *
183 | * @param data 要移除的数据
184 | */
185 | public void removeItem(M data) {
186 | int index = dataList.indexOf(data);
187 | if (index < 0) {
188 | return;
189 | }
190 | dataList.remove(index);
191 | if (headerView == null) {
192 | notifyItemRemoved(index);
193 | } else {
194 | notifyItemRemoved(index + 1);
195 | }
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/java/net/devwiki/recyclerview/chat/ChatItemClickSupport.java:
--------------------------------------------------------------------------------
1 | package net.devwiki.recyclerview.chat;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.View;
5 |
6 | import net.devwiki.log.DevLog;
7 | import net.devwiki.recyclerview.R;
8 | import net.devwiki.recyclerview.single.SingleHolder;
9 |
10 | /**
11 | * SingleItem的点击事件
12 | * Created by zyz on 2016/7/20.
13 | */
14 |
15 | public class ChatItemClickSupport {
16 | private final RecyclerView mRecyclerView;
17 | private OnItemClickListener mOnItemClickListener;
18 | private OnItemLongClickListener mOnItemLongClickListener;
19 | private View.OnClickListener mOnClickListener = new View.OnClickListener() {
20 | @Override
21 | public void onClick(View v) {
22 | if (mOnItemClickListener != null) {
23 | RecyclerView.ViewHolder holder = mRecyclerView.findContainingViewHolder(v);
24 | if (holder != null) {
25 | int position = holder.getAdapterPosition();
26 | if (v.getId() == R.id.name_tv) {
27 | mOnItemClickListener.onNameClick(mRecyclerView, position, v);
28 | }else if (v.getId() == R.id.content_tv){
29 | mOnItemClickListener.onTextClick(mRecyclerView, position, v);
30 | }else if (v.getId() == R.id.content_iv) {
31 | mOnItemClickListener.onImageClick(mRecyclerView, position, v);
32 | } else {
33 | DevLog.d("holder is null.....");
34 | }
35 | }
36 | }
37 | }
38 | };
39 | private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
40 | @Override
41 | public boolean onLongClick(View v) {
42 | if (mOnItemLongClickListener != null) {
43 | RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
44 | return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
45 | }
46 | return false;
47 | }
48 | };
49 | private RecyclerView.OnChildAttachStateChangeListener mAttachListener
50 | = new RecyclerView.OnChildAttachStateChangeListener() {
51 | @Override
52 | public void onChildViewAttachedToWindow(View view) {
53 | if (mOnItemClickListener != null) {
54 | view.setOnClickListener(mOnClickListener);
55 | RecyclerView.ViewHolder viewHolder = mRecyclerView.getChildViewHolder(view);
56 | if (viewHolder instanceof ChatHolder) {
57 | ChatHolder chatHolder = (ChatHolder) viewHolder;
58 | chatHolder.senderNameTv.setOnClickListener(mOnClickListener);
59 | if (chatHolder instanceof TextHolder) {
60 | TextHolder textHolder = (TextHolder) chatHolder;
61 | textHolder.contentTv.setOnClickListener(mOnClickListener);
62 | }
63 | if (chatHolder instanceof ImageHolder) {
64 | ImageHolder imageHolder = (ImageHolder) chatHolder;
65 | imageHolder.contentIv.setOnClickListener(mOnClickListener);
66 | }
67 | }
68 | }
69 | if (mOnItemLongClickListener != null) {
70 | view.setOnLongClickListener(mOnLongClickListener);
71 | }
72 | }
73 |
74 | @Override
75 | public void onChildViewDetachedFromWindow(View view) {
76 |
77 | }
78 | };
79 |
80 | private ChatItemClickSupport(RecyclerView recyclerView) {
81 | mRecyclerView = recyclerView;
82 | mRecyclerView.setTag(net.devwiki.recycler.R.id.item_click_support, this);
83 | mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
84 | }
85 |
86 | public static ChatItemClickSupport addTo(RecyclerView view) {
87 | ChatItemClickSupport support = (ChatItemClickSupport) view.getTag(net.devwiki.recycler.R.id.item_click_support);
88 | if (support == null) {
89 | support = new ChatItemClickSupport(view);
90 | }
91 | return support;
92 | }
93 |
94 | public static ChatItemClickSupport removeFrom(RecyclerView view) {
95 | ChatItemClickSupport support = (ChatItemClickSupport) view.getTag(net.devwiki.recycler.R.id.item_click_support);
96 | if (support != null) {
97 | support.detach(view);
98 | }
99 | return support;
100 | }
101 |
102 | public ChatItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
103 | mOnItemClickListener = listener;
104 | return this;
105 | }
106 |
107 | public ChatItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
108 | mOnItemLongClickListener = listener;
109 | return this;
110 | }
111 |
112 | private void detach(RecyclerView view) {
113 | view.removeOnChildAttachStateChangeListener(mAttachListener);
114 | view.setTag(net.devwiki.recycler.R.id.item_click_support, null);
115 | }
116 |
117 | public interface OnItemClickListener {
118 |
119 | void onNameClick(RecyclerView recyclerView, int position, View view);
120 |
121 | void onTextClick(RecyclerView recyclerView, int position, View view);
122 |
123 | void onImageClick(RecyclerView recyclerView, int position, View view);
124 | }
125 |
126 | public interface OnItemLongClickListener {
127 |
128 | boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
129 | }
130 | }
--------------------------------------------------------------------------------
/recycler/src/main/java/net/devwiki/recycler/GridDividerDecoration.java:
--------------------------------------------------------------------------------
1 | package net.devwiki.recycler;
2 |
3 | import android.content.Context;
4 | import android.graphics.Rect;
5 | import android.graphics.drawable.Drawable;
6 | import android.support.annotation.DrawableRes;
7 | import android.support.v7.widget.GridLayoutManager;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.support.v7.widget.StaggeredGridLayoutManager;
11 |
12 | /**
13 | * 表格使用,高度和宽度分别取drawable的height和width
14 | * Created by zyz on 2016/9/19.
15 | */
16 |
17 | public class GridDividerDecoration extends DividerDecoration {
18 |
19 | public GridDividerDecoration(Context context, int orientation) {
20 | super(context, orientation);
21 | }
22 |
23 | public GridDividerDecoration(Context context, int orientation, @DrawableRes int resId) {
24 | super(context, orientation, resId);
25 | }
26 |
27 | public GridDividerDecoration(Context context, int orientation, Drawable drawable) {
28 | super(context, orientation, drawable);
29 | }
30 |
31 | private boolean isLastSpan(RecyclerView parent, int pos, int spanCount, int childCount) {
32 | RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
33 | if (layoutManager instanceof GridLayoutManager) {
34 | // 如果是最后一列,则不需要绘制右边
35 | if ((pos + 1) % spanCount == 0) {
36 | return true;
37 | }
38 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
39 | int orientation = ((StaggeredGridLayoutManager) layoutManager)
40 | .getOrientation();
41 | if (orientation == StaggeredGridLayoutManager.VERTICAL) {
42 | // 如果是最后一列,则不需要绘制右边
43 | if ((pos + 1) % spanCount == 0) {
44 | return true;
45 | }
46 | } else {
47 | childCount = childCount - childCount % spanCount;
48 | // 如果是最后一列,则不需要绘制右边
49 | if (pos >= childCount) {
50 | return true;
51 | }
52 | }
53 | }
54 | return false;
55 | }
56 |
57 | private boolean isLastRow(RecyclerView parent, int pos, int spanCount, int childCount) {
58 | RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
59 | if (layoutManager instanceof GridLayoutManager) {
60 | if (childCount < spanCount) {
61 | return true;
62 | } else {
63 | int completeRowCount = childCount / spanCount;
64 | int div = childCount % spanCount;
65 | if (div == 0) {
66 | return pos >= (completeRowCount-1) * spanCount;
67 | } else {
68 | return pos >= completeRowCount * spanCount;
69 | }
70 | }
71 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
72 | int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
73 | if (orientation == StaggeredGridLayoutManager.VERTICAL) {
74 | // StaggeredGridLayoutManager 且纵向滚动
75 | childCount = childCount - childCount % spanCount;
76 | // 如果是最后一行,则不需要绘制底部
77 | if (pos >= childCount) {
78 | return true;
79 | }
80 | } else {
81 | // StaggeredGridLayoutManager 且横向滚动
82 | // 如果是最后一行,则不需要绘制底部
83 | if ((pos + 1) % spanCount == 0) {
84 | return true;
85 | }
86 | }
87 | } else if (layoutManager instanceof LinearLayoutManager) {
88 | return pos == childCount-1;
89 | }
90 | return false;
91 | }
92 |
93 | private int getSpanCount(RecyclerView parent) {
94 | // 列数
95 | int spanCount = 1;
96 | RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
97 | if (layoutManager instanceof GridLayoutManager) {
98 | spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
99 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
100 | spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
101 | }
102 | return spanCount;
103 | }
104 |
105 | @Override
106 | public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
107 | int spanCount = getSpanCount(parent);
108 | int childCount = parent.getAdapter().getItemCount();
109 | if (mOrientation == VERTICAL_LIST) {
110 | if (isLastSpan(parent, itemPosition, spanCount, childCount)) {
111 | if (isLastRow(parent, itemPosition, spanCount, childCount)) {
112 | outRect.set(mDivider.getIntrinsicWidth()/2, 0, 0, 0);
113 | } else {
114 | outRect.set(mDivider.getIntrinsicWidth()/2, 0, 0, mDivider.getIntrinsicHeight());
115 | }
116 | } else{
117 | if (isLastSpan(parent, itemPosition, spanCount, childCount)) {
118 |
119 | } else {
120 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
121 | }
122 | }
123 | } else {
124 | if (isLastSpan(parent, itemPosition, spanCount, childCount)) {
125 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
126 | } else if (isLastRow(parent, itemPosition, spanCount, childCount)){
127 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
128 | } else {
129 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight());
130 | }
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/.idea/codeStyleSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
229 |
230 |
231 |
--------------------------------------------------------------------------------