├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable-hdpi
│ │ │ ├── ic_done.png
│ │ │ ├── ic_menu.png
│ │ │ ├── ic_discuss.png
│ │ │ ├── ic_event.png
│ │ │ ├── ic_forum.png
│ │ │ ├── ic_headset.png
│ │ │ └── ic_dashboard.png
│ │ ├── drawable-mdpi
│ │ │ ├── ic_done.png
│ │ │ ├── ic_menu.png
│ │ │ ├── ic_discuss.png
│ │ │ ├── ic_event.png
│ │ │ ├── ic_forum.png
│ │ │ ├── ic_headset.png
│ │ │ └── ic_dashboard.png
│ │ ├── drawable-nodpi
│ │ │ ├── cheese_1.jpg
│ │ │ ├── cheese_2.jpg
│ │ │ ├── cheese_3.jpg
│ │ │ ├── cheese_4.jpg
│ │ │ └── cheese_5.jpg
│ │ ├── drawable-xhdpi
│ │ │ ├── ic_done.png
│ │ │ ├── ic_event.png
│ │ │ ├── ic_forum.png
│ │ │ ├── ic_menu.png
│ │ │ ├── ic_discuss.png
│ │ │ ├── ic_headset.png
│ │ │ └── ic_dashboard.png
│ │ ├── drawable-xxhdpi
│ │ │ ├── ic_done.png
│ │ │ ├── ic_event.png
│ │ │ ├── ic_forum.png
│ │ │ ├── ic_menu.png
│ │ │ ├── ic_discuss.png
│ │ │ ├── ic_headset.png
│ │ │ └── ic_dashboard.png
│ │ ├── drawable-xxxhdpi
│ │ │ ├── ic_done.png
│ │ │ └── ic_menu.png
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── layout
│ │ │ ├── test_item.xml
│ │ │ ├── fragment_cheese_2_list.xml
│ │ │ ├── fragment_cheese_grid_with_header.xml
│ │ │ ├── test_head_item.xml
│ │ │ ├── fragment_cheese_grid.xml
│ │ │ ├── fragment_cheese_list.xml
│ │ │ ├── sample_header1.xml
│ │ │ ├── sample_header2.xml
│ │ │ ├── sample_header.xml
│ │ │ ├── nav_header.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_grid.xml
│ │ │ ├── activity_linear.xml
│ │ │ ├── include_main.xml
│ │ │ ├── list_item.xml
│ │ │ ├── grid_dialog.xml
│ │ │ ├── include_list_viewpager.xml
│ │ │ └── activity_detail.xml
│ │ ├── menu
│ │ │ ├── sample_actions.xml
│ │ │ └── drawer_view.xml
│ │ ├── values-v21
│ │ │ └── styles.xml
│ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── styles.xml
│ │ │ ├── dimens.xml
│ │ │ └── strings.xml
│ │ ├── java
│ │ └── com
│ │ │ └── support
│ │ │ └── android
│ │ │ └── designlibdemo
│ │ │ ├── GridOperation.java
│ │ │ ├── SampleHeader.java
│ │ │ ├── SampleHeader1.java
│ │ │ ├── SampleHeader2.java
│ │ │ ├── adapter
│ │ │ └── TestAdapter.java
│ │ │ ├── CheeseDetailActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── LinearActivity.java
│ │ │ ├── CustomizeFragment.java
│ │ │ ├── WithHeaderFragment.java
│ │ │ ├── CheeseListFragment.java
│ │ │ ├── GridWithHeaderFragment.java
│ │ │ ├── CheeseGridFragment.java
│ │ │ ├── GridActivity.java
│ │ │ ├── StickHeadFragment.java
│ │ │ └── Cheeses.java
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── extendablerecyclerview
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ └── strings.xml
│ │ │ └── layout
│ │ │ │ ├── dm_recyclerview_wrapper_layout.xml
│ │ │ │ ├── dm_recyclerview_bottom_progressbar.xml
│ │ │ │ ├── dm_recyclerview_vertical.xml
│ │ │ │ └── dm_recyclerview_horizontal.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── edus
│ │ │ │ └── view
│ │ │ │ ├── HeadViewHolder.java
│ │ │ │ ├── LoadingViewHolder.java
│ │ │ │ ├── sticky
│ │ │ │ ├── util
│ │ │ │ │ ├── OrientationProvider.java
│ │ │ │ │ └── LinearLayoutOrientationProvider.java
│ │ │ │ ├── caching
│ │ │ │ │ ├── HeaderProvider.java
│ │ │ │ │ └── HeaderViewCache.java
│ │ │ │ ├── StickyRecyclerHeadersAdapter.java
│ │ │ │ ├── calculation
│ │ │ │ │ └── DimensionCalculator.java
│ │ │ │ ├── rendering
│ │ │ │ │ └── HeaderRenderer.java
│ │ │ │ ├── StickyRecyclerHeadersDecoration.java
│ │ │ │ └── HeaderPositionCalculator.java
│ │ │ │ ├── DmBaseViewHolder.java
│ │ │ │ ├── DmRecyclerView.java
│ │ │ │ ├── decoration
│ │ │ │ ├── LinearItemDividerDecoration.java
│ │ │ │ └── DividerGridItemDecoration.java
│ │ │ │ ├── DmBaseAdapter.java
│ │ │ │ └── DmRecyclerViewWrapper.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── dewmobile
│ │ │ └── dmrecyclerview
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── dewmobile
│ │ └── dmrecyclerview
│ │ └── ApplicationTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── README.md
├── gradle.properties
├── .gitignore
├── .idea
└── misc.xml
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/extendablerecyclerview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':extendablerecyclerview', ':app'
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DmRecyclerView
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-hdpi/ic_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-hdpi/ic_menu.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-mdpi/ic_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-mdpi/ic_menu.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_discuss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-hdpi/ic_discuss.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_event.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-hdpi/ic_event.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_forum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-hdpi/ic_forum.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_headset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-hdpi/ic_headset.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_discuss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-mdpi/ic_discuss.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_event.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-mdpi/ic_event.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_forum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-mdpi/ic_forum.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_headset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-mdpi/ic_headset.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/cheese_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-nodpi/cheese_1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/cheese_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-nodpi/cheese_2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/cheese_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-nodpi/cheese_3.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/cheese_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-nodpi/cheese_4.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/cheese_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-nodpi/cheese_5.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xhdpi/ic_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_event.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xhdpi/ic_event.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_forum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xhdpi/ic_forum.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xhdpi/ic_menu.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xxhdpi/ic_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_event.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xxhdpi/ic_event.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_forum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xxhdpi/ic_forum.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xxhdpi/ic_menu.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xxxhdpi/ic_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xxxhdpi/ic_menu.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-hdpi/ic_dashboard.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-mdpi/ic_dashboard.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_discuss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xhdpi/ic_discuss.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_headset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xhdpi/ic_headset.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_discuss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xxhdpi/ic_discuss.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_headset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xxhdpi/ic_headset.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xhdpi/ic_dashboard.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yqpan1991/ExtendableRecyclerView/HEAD/app/src/main/res/drawable-xxhdpi/ic_dashboard.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Sep 03 11:50:12 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-2.2-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/GridOperation.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo;
2 |
3 | /**
4 | * Created by panda on 2018/1/29.
5 | */
6 |
7 | public interface GridOperation {
8 | public void setOrientation(int orientation);
9 | public void setSpanCount(int spanCount);
10 | }
11 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/HeadViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.edus.view;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * Created by yqpan on 2016/1/17.
7 | */
8 | public class HeadViewHolder extends DmBaseViewHolder {
9 |
10 | public HeadViewHolder(View itemView) {
11 | super(itemView);
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/LoadingViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.edus.view;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * Created by Administrator on 2016/1/13.
7 | */
8 | public class LoadingViewHolder extends DmBaseViewHolder {
9 |
10 | public LoadingViewHolder(View itemView) {
11 | super(itemView);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/sticky/util/OrientationProvider.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.sticky.util;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 |
5 | /**
6 | * Interface for getting the orientation of a RecyclerView from its LayoutManager
7 | */
8 | public interface OrientationProvider {
9 |
10 | public int getOrientation(RecyclerView recyclerView);
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/test_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_cheese_2_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/test/java/com/dewmobile/dmrecyclerview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.dewmobile.dmrecyclerview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_cheese_grid_with_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/DmBaseViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.edus.view;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.View;
5 |
6 | /**
7 | * Created by yqpan on 2016/1/13.
8 | */
9 | public class DmBaseViewHolder extends RecyclerView.ViewHolder {
10 |
11 | public DmBaseViewHolder(View itemView) {
12 | super(itemView);
13 | }
14 |
15 | public void updateData(T t, int position){
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/androidTest/java/com/dewmobile/dmrecyclerview/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.dewmobile.dmrecyclerview;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/test_head_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #ExtendableRecyclerView
2 | ##1.支持什么
3 | ExtendableRecyclerView支持的功能如下:
4 | 1. 内部支持下拉刷新和加载更多
5 |
6 | 2. 支持是否允许下拉刷新加载更多
7 |
8 | 3. 复写的adapter支持动态的添加headerView(暂不支持添加其他的footer,目前的加载更多为一个footerView)
9 |
10 |
11 | ##2. 实现原理
12 |
13 | 此封装类为个人在其他的开源项目基础上进行了演变
14 | 之前的UltimateRecyclerView个人认为功能过于繁杂,因而只是取其核心部分,通过封装RecyclerView和SwipeRefreshLayout和加载更多的条目的逻辑
15 | 另外,参照其他的开源项目中,发现其headerView的实现逻辑存在问题,条目类型与headerView的position进行绑定,这个实现逻辑是存在问题的,因而个人将其纠正,每个headerView的type是不同的,并且是支持动态的增加和删除
16 |
17 | 注意: 此工程是采用google的support.design的sample为样例,进行的更改.
18 |
19 | 欢迎各位加入安卓源码分析群: 164812238
20 |
21 | 攀岩不止,永强不息~
22 |
--------------------------------------------------------------------------------
/extendablerecyclerview/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:\dev\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/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 /usr/local/google/home/chrisbanes/bin/current-android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/res/layout/dm_recyclerview_wrapper_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/sticky/caching/HeaderProvider.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.sticky.caching;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.View;
5 |
6 | /**
7 | * Implemented by objects that provide header views for decoration
8 | */
9 | public interface HeaderProvider {
10 |
11 | /**
12 | * Will provide a header view for a given position in the RecyclerView
13 | *
14 | * @param recyclerView that will display the header
15 | * @param position that will be headed by the header
16 | * @return a header view for the given position and list
17 | */
18 | public View getHeader(RecyclerView recyclerView, int position);
19 |
20 | /**
21 | * TODO: describe this functionality and its necessity
22 | */
23 | void invalidate();
24 | }
25 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/res/layout/dm_recyclerview_bottom_progressbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
20 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/sticky/util/LinearLayoutOrientationProvider.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.sticky.util;
2 |
3 | import android.support.v7.widget.LinearLayoutManager;
4 | import android.support.v7.widget.RecyclerView;
5 |
6 | /**
7 | * OrientationProvider for ReyclerViews who use a LinearLayoutManager
8 | */
9 | public class LinearLayoutOrientationProvider implements OrientationProvider {
10 |
11 | @Override
12 | public int getOrientation(RecyclerView recyclerView) {
13 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
14 |
15 | if (layoutManager instanceof LinearLayoutManager) {
16 | return ((LinearLayoutManager) layoutManager).getOrientation();
17 | } else {
18 | throw new IllegalStateException("StickyListHeadersDecoration can only be used with a " +
19 | "LinearLayoutManager.");
20 | }
21 | }
22 |
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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/extendablerecyclerview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral() // or jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:1.5.0'
10 | }
11 | }
12 |
13 | android {
14 | compileSdkVersion 23
15 | buildToolsVersion "23.0.1"
16 |
17 | defaultConfig {
18 | minSdkVersion 9
19 | targetSdkVersion 23
20 | versionCode 1
21 | versionName "1.0"
22 | }
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | }
30 |
31 | dependencies {
32 | compile fileTree(dir: 'libs', include: ['*.jar'])
33 | compile 'com.android.support:appcompat-v7:23.1.1'
34 | compile 'com.android.support:recyclerview-v7:23.1.1'
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/SampleHeader.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.RelativeLayout;
6 |
7 | /**
8 | * Created by cundong on 2015/10/9.
9 | *
10 | * RecyclerView的HeaderView,简单的展示一个TextView
11 | */
12 | public class SampleHeader extends RelativeLayout {
13 |
14 | public SampleHeader(Context context) {
15 | super(context);
16 | init(context);
17 | }
18 |
19 | public SampleHeader(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | init(context);
22 | }
23 |
24 | public SampleHeader(Context context, AttributeSet attrs, int defStyleAttr) {
25 | super(context, attrs, defStyleAttr);
26 | init(context);
27 | }
28 |
29 | public void init(Context context) {
30 |
31 | inflate(context, R.layout.sample_header, this);
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/SampleHeader1.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.RelativeLayout;
6 |
7 | /**
8 | * Created by cundong on 2015/10/9.
9 | *
10 | * RecyclerView的HeaderView,简单的展示一个TextView
11 | */
12 | public class SampleHeader1 extends RelativeLayout {
13 |
14 | public SampleHeader1(Context context) {
15 | super(context);
16 | init(context);
17 | }
18 |
19 | public SampleHeader1(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | init(context);
22 | }
23 |
24 | public SampleHeader1(Context context, AttributeSet attrs, int defStyleAttr) {
25 | super(context, attrs, defStyleAttr);
26 | init(context);
27 | }
28 |
29 | public void init(Context context) {
30 |
31 | inflate(context, R.layout.sample_header1, this);
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/SampleHeader2.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.RelativeLayout;
6 |
7 | /**
8 | * Created by cundong on 2015/10/9.
9 | *
10 | * RecyclerView的HeaderView,简单的展示一个TextView
11 | */
12 | public class SampleHeader2 extends RelativeLayout {
13 |
14 | public SampleHeader2(Context context) {
15 | super(context);
16 | init(context);
17 | }
18 |
19 | public SampleHeader2(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | init(context);
22 | }
23 |
24 | public SampleHeader2(Context context, AttributeSet attrs, int defStyleAttr) {
25 | super(context, attrs, defStyleAttr);
26 | init(context);
27 | }
28 |
29 | public void init(Context context) {
30 |
31 | inflate(context, R.layout.sample_header2, this);
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_cheese_grid.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_cheese_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/sample_actions.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | #FFF5F5F5
20 |
21 | #3F51B5
22 | #303F9F
23 | #FF4081
24 |
25 | #F0F0F0
26 | #8A000000
27 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/res/layout/dm_recyclerview_vertical.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/res/layout/dm_recyclerview_horizontal.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | buildscript {
4 | repositories {
5 | jcenter() // or jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:1.5.0'
10 | }
11 | }
12 |
13 | android {
14 | compileSdkVersion 23
15 | buildToolsVersion "23.0.1"
16 |
17 | defaultConfig {
18 | applicationId "com.support.android.designlibdemo"
19 | minSdkVersion 9
20 | targetSdkVersion 23
21 | versionCode 1
22 | versionName "1.0"
23 | }
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 | }
31 |
32 | repositories {
33 | jcenter()
34 | }
35 |
36 | dependencies {
37 | compile 'com.android.support:design:23.1.1'
38 | compile 'com.android.support:cardview-v7:23.1.1'
39 | compile 'com.github.bumptech.glide:glide:3.6.0'
40 | compile 'de.hdodenhof:circleimageview:1.3.0'
41 | compile project(':extendablerecyclerview')
42 | }
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # IntelliJ
36 | *.iml
37 | .idea/
38 |
39 | # Keystore files
40 | # Uncomment the following line if you do not want to check your keystore files in.
41 | #*.jks
42 |
43 | # External native build folder generated in Android Studio 2.2 and later
44 | .externalNativeBuild
45 |
46 | # Google Services (e.g. APIs or Firebase)
47 | google-services.json
48 |
49 | # Freeline
50 | freeline.py
51 | freeline/
52 | freeline_project_description.json
53 |
54 | # fastlane
55 | fastlane/report.xml
56 | fastlane/Preview.html
57 | fastlane/screenshots
58 | fastlane/test_output
59 | fastlane/readme.md
--------------------------------------------------------------------------------
/app/src/main/res/layout/sample_header1.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
24 |
25 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/sample_header2.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
24 |
25 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/sample_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
24 |
25 |
29 |
30 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/sticky/StickyRecyclerHeadersAdapter.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.sticky;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.ViewGroup;
5 |
6 | public interface StickyRecyclerHeadersAdapter {
7 | /**
8 | * Get the ID of the header associated with this item. For example, if your headers group
9 | * items by their first letter, you could return the character representation of the first letter.
10 | * Return a value < 0 if the view should not have a header (like, a header view or footer view)
11 | *
12 | * @param position
13 | * @return
14 | */
15 | public long getHeaderId(int position);
16 |
17 | /**
18 | * Creates a new ViewHolder for a header. This works the same way onCreateViewHolder in
19 | * Recycler.Adapter, ViewHolders can be reused for different views. This is usually a good place
20 | * to inflate the layout for the header.
21 | *
22 | * @param parent
23 | * @return
24 | */
25 | public VH onCreateHeaderViewHolder(ViewGroup parent);
26 |
27 | /**
28 | * Binds an existing ViewHolder to the specified adapter position.
29 | *
30 | * @param holder
31 | * @param position
32 | */
33 | public void onBindHeaderViewHolder(VH holder, int position);
34 |
35 | public int getItemCount();
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
26 |
27 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
25 |
26 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_grid.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
26 |
27 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_linear.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
26 |
27 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/include_main.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
21 |
22 |
27 |
28 |
33 |
34 |
35 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
22 |
23 |
29 |
30 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/adapter/TestAdapter.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.GridLayoutManager;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import com.edus.view.DmBaseAdapter;
10 | import com.edus.view.DmBaseViewHolder;
11 | import com.support.android.designlibdemo.R;
12 |
13 | /**
14 | { * Created by yqpan on 2016/1/13.
15 | */
16 | public class TestAdapter extends DmBaseAdapter {
17 |
18 | public TestAdapter(Context context) {
19 | super(context);
20 | }
21 |
22 | @Override
23 | public DmBaseViewHolder onCreateAdapterViewHolder(ViewGroup parent, int viewType) {
24 | return new CustomViewHolder(mInflater.inflate(R.layout.test_item,parent,false));
25 | }
26 |
27 | @Override
28 | public void onBindAdapterViewHolder(DmBaseViewHolder holder, int position) {
29 | String adapterDataItem = getAdapterDataItem(position);
30 | holder.updateData(adapterDataItem, position);
31 | }
32 |
33 | public static class CustomViewHolder extends DmBaseViewHolder{
34 | TextView tvDemo;
35 | public CustomViewHolder(View itemView) {
36 | super(itemView);
37 | tvDemo = (TextView) itemView.findViewById(R.id.tv_demo);
38 | }
39 |
40 | @Override
41 | public void updateData(String s, int position) {
42 | super.updateData(s, position);
43 | tvDemo.setText(s);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | 256dp
20 | 16dp
21 | 16dp
22 | 40dp
23 |
24 | 16dp
25 | 16dp
26 |
27 | 0.66dp
28 | 4dp
29 | 10dp
30 | 14dp
31 | 22dp
32 | 36dp
33 | 40dp
34 | 60dp
35 | 72dp
36 |
37 | 12sp
38 | 14sp
39 | 16sp
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
26 |
27 |
32 |
33 |
38 |
39 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/sticky/calculation/DimensionCalculator.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.sticky.calculation;
2 |
3 | import android.graphics.Rect;
4 | import android.view.View;
5 |
6 | import static android.view.ViewGroup.LayoutParams;
7 | import static android.view.ViewGroup.MarginLayoutParams;
8 |
9 | /**
10 | * Helper to calculate various view dimensions
11 | */
12 | public class DimensionCalculator {
13 |
14 | /**
15 | * Returns {@link Rect} representing margins for any view.
16 | *
17 | * @param view for which to get margins
18 | * @return margins for the given view. All 0 if the view does not support margins
19 | */
20 | public Rect getMargins(View view) {
21 | LayoutParams layoutParams = view.getLayoutParams();
22 |
23 | if (layoutParams instanceof MarginLayoutParams) {
24 | MarginLayoutParams marginLayoutParams = (MarginLayoutParams) layoutParams;
25 | return getMarginRect(marginLayoutParams);
26 | } else {
27 | return new Rect();
28 | }
29 | }
30 |
31 | /**
32 | * Converts {@link MarginLayoutParams} into a representative {@link Rect}
33 | *
34 | * @param marginLayoutParams margins to convert to a Rect
35 | * @return Rect representing margins, where {@link MarginLayoutParams#leftMargin} is equivalent to
36 | * {@link Rect#left}, etc.
37 | */
38 | private Rect getMarginRect(MarginLayoutParams marginLayoutParams) {
39 | return new Rect(
40 | marginLayoutParams.leftMargin,
41 | marginLayoutParams.topMargin,
42 | marginLayoutParams.rightMargin,
43 | marginLayoutParams.bottomMargin
44 | );
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/grid_dialog.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
21 |
22 |
27 |
28 |
33 |
34 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | ExtendRecyclerView
20 |
21 | Jarlsberg lancashire edam. Dolcelatte hard cheese brie st. agur blue
22 | cheese caerphilly bavarian bergkase cheese and biscuits mascarpone. Cheeseburger swiss bavarian
23 | bergkase cream cheese fromage frais cheesy feet port-salut airedale. St. agur blue cheese rubber
24 | cheese caerphilly cheddar cheesecake cream cheese manchego lancashire. Roquefort squirty cheese
25 | the big cheese.
26 | Checkin
27 | Settings
28 |
29 |
30 | The Header
31 | The Footer
32 |
33 |
34 | 正在加载中…
35 | 点击重新加载
36 | 已经到底了
37 |
38 |
39 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/DmRecyclerView.java:
--------------------------------------------------------------------------------
1 | package com.edus.view;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.AttributeSet;
7 |
8 | /**
9 | * Created by yqpan on 2015/12/17.
10 | */
11 | public class DmRecyclerView extends RecyclerView {
12 |
13 | private final String TAG = DmRecyclerView.this.getClass().getSimpleName();
14 |
15 | public DmRecyclerView(Context context) {
16 | this(context, null);
17 | }
18 |
19 | public DmRecyclerView(Context context, AttributeSet attrs) {
20 | this(context, attrs, 0);
21 | }
22 |
23 | public DmRecyclerView(Context context, AttributeSet attrs, int defStyle) {
24 | super(context, attrs, defStyle);
25 | // Log.e(TAG, "CustomRecyclerView init");
26 | }
27 |
28 | @Override
29 | protected void onMeasure(int widthSpec, int heightSpec) {
30 | super.onMeasure(widthSpec, heightSpec);
31 | // Log.e(TAG, "onMeasure");
32 | }
33 |
34 | @Override
35 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
36 | super.onLayout(changed, l, t, r, b);
37 | // Log.e(TAG, "onLayout");
38 | }
39 |
40 | @Override
41 | public void onDraw(Canvas c) {
42 | super.onDraw(c);
43 | // Log.e(TAG, "onDraw");
44 | }
45 |
46 | @Override
47 | protected void onAttachedToWindow() {
48 | super.onAttachedToWindow();
49 | // Log.e(TAG,"onAttachedToWindow");
50 | }
51 |
52 | @Override
53 | protected void onDetachedFromWindow() {
54 | super.onDetachedFromWindow();
55 | // Log.e(TAG, "onDetachedFromWindow");
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/drawer_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
50 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
20 |
21 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
16 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | 1.7
38 |
39 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/include_list_viewpager.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
23 |
24 |
29 |
30 |
37 |
38 |
42 |
43 |
44 |
45 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/CheeseDetailActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 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 com.support.android.designlibdemo;
18 |
19 | import android.content.Intent;
20 | import android.os.Bundle;
21 | import android.support.design.widget.CollapsingToolbarLayout;
22 | import android.support.v7.app.AppCompatActivity;
23 | import android.support.v7.widget.Toolbar;
24 | import android.view.Menu;
25 | import android.view.MenuItem;
26 | import android.widget.ImageView;
27 |
28 | import com.bumptech.glide.Glide;
29 |
30 | import java.util.Random;
31 |
32 | public class CheeseDetailActivity extends AppCompatActivity {
33 |
34 | public static final String EXTRA_NAME = "cheese_name";
35 |
36 | @Override
37 | public void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | setContentView(R.layout.activity_detail);
40 |
41 | Intent intent = getIntent();
42 | final String cheeseName = intent.getStringExtra(EXTRA_NAME);
43 |
44 | final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
45 | setSupportActionBar(toolbar);
46 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
47 |
48 | CollapsingToolbarLayout collapsingToolbar =
49 | (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
50 | collapsingToolbar.setTitle(cheeseName);
51 |
52 | loadBackdrop();
53 | }
54 |
55 | private void loadBackdrop() {
56 | final ImageView imageView = (ImageView) findViewById(R.id.backdrop);
57 | Glide.with(this).load(Cheeses.getRandomCheeseDrawable()).centerCrop().into(imageView);
58 | }
59 |
60 | @Override
61 | public boolean onCreateOptionsMenu(Menu menu) {
62 | getMenuInflater().inflate(R.menu.sample_actions, menu);
63 | return true;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 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 com.support.android.designlibdemo;
18 |
19 | import android.content.Intent;
20 | import android.os.Bundle;
21 | import android.support.v7.app.ActionBar;
22 | import android.support.v7.app.AppCompatActivity;
23 | import android.support.v7.widget.Toolbar;
24 | import android.view.Menu;
25 | import android.view.View;
26 |
27 | /**
28 | * TODO
29 | */
30 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_main);
36 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
37 | setSupportActionBar(toolbar);
38 | toolbar.setTitleTextColor(getResources().getColor(android.R.color.white));
39 | final ActionBar ab = getSupportActionBar();
40 | ab.setHomeAsUpIndicator(R.drawable.ic_menu);
41 | ab.setDisplayHomeAsUpEnabled(true);
42 | initView();
43 | }
44 |
45 | private void initView() {
46 | findViewById(R.id.bt_linear).setOnClickListener(this);
47 | findViewById(R.id.bt_grid).setOnClickListener(this);
48 | findViewById(R.id.bt_stagger).setOnClickListener(this);
49 | }
50 |
51 | @Override
52 | public boolean onCreateOptionsMenu(Menu menu) {
53 | getMenuInflater().inflate(R.menu.sample_actions, menu);
54 | return true;
55 | }
56 |
57 | @Override
58 | public void onClick(View v) {
59 | switch (v.getId()){
60 | case R.id.bt_linear:
61 | startActivity(new Intent(getApplicationContext(), LinearActivity.class));
62 | break;
63 | case R.id.bt_grid:
64 | startActivity(new Intent(getApplicationContext(), GridActivity.class));
65 | break;
66 | case R.id.bt_stagger:
67 | break;
68 | }
69 |
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/sticky/caching/HeaderViewCache.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.sticky.caching;
2 |
3 | import android.support.v4.util.LongSparseArray;
4 | import android.support.v7.widget.LinearLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import com.edus.view.sticky.util.OrientationProvider;
10 | import com.edus.view.sticky.StickyRecyclerHeadersAdapter;
11 |
12 | /**
13 | * An implementation of {@link com.marshalchen.ultimaterecyclerview.stickyheadersrecyclerview.caching.HeaderProvider} that creates and caches header views
14 | */
15 | public class HeaderViewCache implements HeaderProvider {
16 |
17 | private final StickyRecyclerHeadersAdapter mAdapter;
18 | private final LongSparseArray mHeaderViews = new LongSparseArray<>();
19 | private final OrientationProvider mOrientationProvider;
20 |
21 | public HeaderViewCache(StickyRecyclerHeadersAdapter adapter,
22 | OrientationProvider orientationProvider) {
23 | mAdapter = adapter;
24 | mOrientationProvider = orientationProvider;
25 | }
26 |
27 | @Override
28 | public View getHeader(RecyclerView parent, int position) {
29 | long headerId = mAdapter.getHeaderId(position);
30 |
31 | View header = mHeaderViews.get(headerId);
32 | if (header == null) {
33 | //TODO - recycle views
34 | RecyclerView.ViewHolder viewHolder = mAdapter.onCreateHeaderViewHolder(parent);
35 | mAdapter.onBindHeaderViewHolder(viewHolder, position);
36 | header = viewHolder.itemView;
37 | if (header.getLayoutParams() == null) {
38 | header.setLayoutParams(new ViewGroup.LayoutParams(
39 | ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
40 | }
41 |
42 | int widthSpec;
43 | int heightSpec;
44 |
45 | if (mOrientationProvider.getOrientation(parent) == LinearLayoutManager.VERTICAL) {
46 | widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY);
47 | heightSpec = View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED);
48 | } else {
49 | widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.UNSPECIFIED);
50 | heightSpec = View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.EXACTLY);
51 | }
52 |
53 | int childWidth = ViewGroup.getChildMeasureSpec(widthSpec,
54 | parent.getPaddingLeft() + parent.getPaddingRight(), header.getLayoutParams().width);
55 | int childHeight = ViewGroup.getChildMeasureSpec(heightSpec,
56 | parent.getPaddingTop() + parent.getPaddingBottom(), header.getLayoutParams().height);
57 | header.measure(childWidth, childHeight);
58 | header.layout(0, 0, header.getMeasuredWidth(), header.getMeasuredHeight());
59 | mHeaderViews.put(headerId, header);
60 | }
61 | return header;
62 | }
63 |
64 | @Override
65 | public void invalidate() {
66 | mHeaderViews.clear();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/sticky/rendering/HeaderRenderer.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.sticky.rendering;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Rect;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.View;
7 | import android.widget.LinearLayout;
8 |
9 | import com.edus.view.sticky.util.OrientationProvider;
10 | import com.edus.view.sticky.calculation.DimensionCalculator;
11 |
12 | /**
13 | * Responsible for drawing headers to the canvas provided by the item decoration
14 | */
15 | public class HeaderRenderer {
16 |
17 | private final DimensionCalculator mDimensionCalculator;
18 | private final OrientationProvider mOrientationProvider;
19 |
20 | public HeaderRenderer(OrientationProvider orientationProvider) {
21 | this(orientationProvider, new DimensionCalculator());
22 | }
23 |
24 | private HeaderRenderer(OrientationProvider orientationProvider,
25 | DimensionCalculator dimensionCalculator) {
26 | mOrientationProvider = orientationProvider;
27 | mDimensionCalculator = dimensionCalculator;
28 | }
29 |
30 | /**
31 | * Draws a header to a canvas, offsetting by some x and y amount
32 | *
33 | * @param recyclerView the parent recycler view for drawing the header into
34 | * @param canvas the canvas on which to draw the header
35 | * @param header the view to draw as the header
36 | * @param offset a Rect used to define the x/y offset of the header. Specify x/y offset by setting
37 | * the {@link Rect#left} and {@link Rect#top} properties, respectively.
38 | */
39 | public void drawHeader(RecyclerView recyclerView, Canvas canvas, View header, Rect offset) {
40 | canvas.save();
41 |
42 | if (recyclerView.getLayoutManager().getClipToPadding()) {
43 | // Clip drawing of headers to the padding of the RecyclerView. Avoids drawing in the padding
44 | Rect clipRect = getClipRectForHeader(recyclerView, header);
45 | canvas.clipRect(clipRect);
46 | }
47 |
48 | canvas.translate(offset.left, offset.top);
49 |
50 | header.draw(canvas);
51 | canvas.restore();
52 | }
53 |
54 | /**
55 | * Gets a clipping rect for the header based on the margins of the header and the padding of the
56 | * recycler.
57 | * FIXME: Currently right margin in VERTICAL orientation and bottom margin in HORIZONTAL
58 | * orientation are clipped so they look accurate, but the headers are not being drawn at the
59 | * correctly smaller width and height respectively.
60 | *
61 | * @param recyclerView for which to provide a header
62 | * @param header for clipping
63 | * @return a {@link Rect} for clipping a provided header to the padding of a recycler view
64 | */
65 | private Rect getClipRectForHeader(RecyclerView recyclerView, View header) {
66 | Rect headerMargins = mDimensionCalculator.getMargins(header);
67 | if (mOrientationProvider.getOrientation(recyclerView) == LinearLayout.VERTICAL) {
68 | return new Rect(
69 | recyclerView.getPaddingLeft(),
70 | recyclerView.getPaddingTop(),
71 | recyclerView.getWidth() - recyclerView.getPaddingRight() - headerMargins.right,
72 | recyclerView.getHeight() - recyclerView.getPaddingBottom());
73 | } else {
74 | return new Rect(
75 | recyclerView.getPaddingLeft(),
76 | recyclerView.getPaddingTop(),
77 | recyclerView.getWidth() - recyclerView.getPaddingRight(),
78 | recyclerView.getHeight() - recyclerView.getPaddingBottom() - headerMargins.bottom);
79 | }
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/decoration/LinearItemDividerDecoration.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.decoration;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Rect;
7 | import android.graphics.drawable.Drawable;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.view.View;
11 |
12 | /**
13 | * Created by cym on 15-1-27.
14 | */
15 | public class LinearItemDividerDecoration extends RecyclerView.ItemDecoration {
16 | private static final int[] ATTRS = new int[]{
17 | android.R.attr.listDivider
18 | };
19 |
20 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
21 |
22 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
23 |
24 | private Drawable mDivider;
25 |
26 | private int mOrientation;
27 |
28 | public LinearItemDividerDecoration(Context context, int orientation) {
29 | final TypedArray a = context.obtainStyledAttributes(ATTRS);
30 | mDivider = a.getDrawable(0);
31 | a.recycle();
32 | setOrientation(orientation);
33 | }
34 |
35 | public void setOrientation(int orientation) {
36 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
37 | throw new IllegalArgumentException("invalid orientation");
38 | }
39 | mOrientation = orientation;
40 | }
41 |
42 | @Override
43 | public void onDraw(Canvas c, RecyclerView parent) {
44 | if (mOrientation == VERTICAL_LIST) {
45 | drawVertical(c, parent);
46 | } else {
47 | drawHorizontal(c, parent);
48 | }
49 | }
50 |
51 | private void drawVertical(Canvas c, RecyclerView parent) {
52 | final int left = parent.getPaddingLeft();
53 | final int right = parent.getWidth() - parent.getPaddingRight();
54 |
55 | final int childCount = parent.getChildCount();
56 | for (int i = 0; i < childCount; i++) {
57 | final View child = parent.getChildAt(i);
58 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
59 | .getLayoutParams();
60 | final int top = child.getBottom() + params.bottomMargin;
61 | final int bottom = top + mDivider.getIntrinsicHeight();
62 | mDivider.setBounds(left, top, right, bottom);
63 | mDivider.draw(c);
64 | }
65 | }
66 |
67 | private void drawHorizontal(Canvas c, RecyclerView parent) {
68 | final int top = parent.getPaddingTop();
69 | final int bottom = parent.getHeight() - parent.getPaddingBottom();
70 |
71 | final int childCount = parent.getChildCount();
72 | for (int i = 0; i < childCount; i++) {
73 | final View child = parent.getChildAt(i);
74 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
75 | .getLayoutParams();
76 | final int left = child.getRight() + params.rightMargin;
77 | final int right = left + mDivider.getIntrinsicHeight();
78 | mDivider.setBounds(left, top, right, bottom);
79 | mDivider.draw(c);
80 | }
81 | }
82 |
83 | @Override
84 | public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
85 | if (mOrientation == VERTICAL_LIST) {
86 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
87 | } else {
88 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/LinearActivity.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo;
2 |
3 | import android.os.Bundle;
4 | import android.support.design.widget.FloatingActionButton;
5 | import android.support.design.widget.NavigationView;
6 | import android.support.design.widget.Snackbar;
7 | import android.support.design.widget.TabLayout;
8 | import android.support.v4.app.Fragment;
9 | import android.support.v4.app.FragmentManager;
10 | import android.support.v4.app.FragmentPagerAdapter;
11 | import android.support.v4.view.GravityCompat;
12 | import android.support.v4.view.ViewPager;
13 | import android.support.v4.widget.DrawerLayout;
14 | import android.support.v7.app.ActionBar;
15 | import android.support.v7.app.AppCompatActivity;
16 | import android.support.v7.widget.Toolbar;
17 | import android.view.Menu;
18 | import android.view.MenuItem;
19 | import android.view.View;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 |
24 | /**
25 | * Created by panda on 2018/1/28.
26 | */
27 |
28 | public class LinearActivity extends AppCompatActivity {
29 |
30 | private DrawerLayout mDrawerLayout;
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_linear);
36 |
37 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
38 | setSupportActionBar(toolbar);
39 |
40 | final ActionBar ab = getSupportActionBar();
41 | ab.setHomeAsUpIndicator(R.drawable.ic_menu);
42 | ab.setDisplayHomeAsUpEnabled(true);
43 |
44 | mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
45 |
46 | NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
47 | if (navigationView != null) {
48 | setupDrawerContent(navigationView);
49 | }
50 |
51 | ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
52 | if (viewPager != null) {
53 | setupViewPager(viewPager);
54 | }
55 |
56 | TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
57 | tabLayout.setupWithViewPager(viewPager);
58 | }
59 |
60 | @Override
61 | public boolean onCreateOptionsMenu(Menu menu) {
62 | getMenuInflater().inflate(R.menu.sample_actions, menu);
63 | return true;
64 | }
65 |
66 | @Override
67 | public boolean onOptionsItemSelected(MenuItem item) {
68 | switch (item.getItemId()) {
69 | case android.R.id.home:
70 | mDrawerLayout.openDrawer(GravityCompat.START);
71 | return true;
72 | }
73 | return super.onOptionsItemSelected(item);
74 | }
75 |
76 | private void setupViewPager(ViewPager viewPager) {
77 | Adapter adapter = new Adapter(getSupportFragmentManager());
78 | adapter.addFragment(new CheeseListFragment(), "normal");
79 | adapter.addFragment(new StickHeadFragment(), "stickyHead");
80 | adapter.addFragment(new WithHeaderFragment(), "header");
81 | adapter.addFragment(new CustomizeFragment(), "customize");
82 | viewPager.setAdapter(adapter);
83 | }
84 |
85 | private void setupDrawerContent(NavigationView navigationView) {
86 | navigationView.setNavigationItemSelectedListener(
87 | new NavigationView.OnNavigationItemSelectedListener() {
88 | @Override
89 | public boolean onNavigationItemSelected(MenuItem menuItem) {
90 | menuItem.setChecked(true);
91 | mDrawerLayout.closeDrawers();
92 | return true;
93 | }
94 | });
95 | }
96 |
97 | static class Adapter extends FragmentPagerAdapter {
98 | private final List mFragments = new ArrayList<>();
99 | private final List mFragmentTitles = new ArrayList<>();
100 |
101 | public Adapter(FragmentManager fm) {
102 | super(fm);
103 | }
104 |
105 | public void addFragment(Fragment fragment, String title) {
106 | mFragments.add(fragment);
107 | mFragmentTitles.add(title);
108 | }
109 |
110 | @Override
111 | public Fragment getItem(int position) {
112 | return mFragments.get(position);
113 | }
114 |
115 | @Override
116 | public int getCount() {
117 | return mFragments.size();
118 | }
119 |
120 | @Override
121 | public CharSequence getPageTitle(int position) {
122 | return mFragmentTitles.get(position);
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/CustomizeFragment.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo;
2 |
3 | import android.os.Bundle;
4 | import android.os.Handler;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.widget.SwipeRefreshLayout;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.util.Log;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 |
15 | import com.edus.view.DmRecyclerViewWrapper;
16 | import com.support.android.designlibdemo.adapter.TestAdapter;
17 | import com.edus.view.decoration.LinearItemDividerDecoration;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | /**
23 | * 定制的RecyclerView,包含HeaderView,FooterView和LoadMore
24 | */
25 | public class CustomizeFragment extends Fragment {
26 |
27 | private final String TAG = this.getClass().getSimpleName();
28 |
29 | private DmRecyclerViewWrapper mDrvwContent;
30 | private TestAdapter mAdapter;
31 |
32 | @Nullable
33 | @Override
34 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
35 | return inflater.inflate(R.layout.fragment_cheese_2_list, container, false);
36 | }
37 |
38 | @Override
39 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
40 | super.onViewCreated(view, savedInstanceState);
41 | mDrvwContent = (DmRecyclerViewWrapper) view.findViewById(R.id.rv_content);
42 | }
43 |
44 | @Override
45 | public void onActivityCreated(@Nullable Bundle savedInstanceState) {
46 | super.onActivityCreated(savedInstanceState);
47 | setupRecyclerView();
48 | }
49 |
50 | private void setupRecyclerView() {
51 | initAdapterData();
52 | mDrvwContent.setAdapter(mAdapter);
53 | mDrvwContent.addItemDecoration(new LinearItemDividerDecoration(this.getActivity(), LinearItemDividerDecoration.VERTICAL_LIST));
54 | mDrvwContent.setLayoutManager(new LinearLayoutManager(this.getActivity(), LinearLayoutManager.VERTICAL, false));
55 | mDrvwContent.setOnLoadMoreListener(new DmRecyclerViewWrapper.OnLoadMoreListener() {
56 | @Override
57 | public void loadMore(int itemsCount, int maxLastVisiblePosition) {
58 | new Handler().postDelayed(new Runnable() {
59 | @Override
60 | public void run() {
61 | List data = mAdapter.getDataList();
62 | for (int i = 0; i <= 3; i++) {
63 | data.add(data.size() + 1 + "");
64 | }
65 | mAdapter.notifyDataSetChanged();
66 | }
67 | }, 2000);
68 | }
69 | });
70 |
71 | mDrvwContent.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
72 | @Override
73 | public void onRefresh() {
74 | new Handler().postDelayed(new Runnable() {
75 | @Override
76 | public void run() {
77 | mDrvwContent.setRefreshing(false);
78 | List data = mAdapter.getDataList();
79 | for (int i = 0; i <= 3; i++) {
80 | data.add(0, data.size() + 1 + "");
81 | }
82 | mAdapter.notifyDataSetChanged();
83 | }
84 | }, 2000);
85 | }
86 | });
87 | mDrvwContent.enableLoadMore(true);
88 | mDrvwContent.enableRefresh(true);
89 | mDrvwContent.addOnScrollListener(new RecyclerView.OnScrollListener() {
90 | @Override
91 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
92 | super.onScrollStateChanged(recyclerView, newState);
93 | Log.e(TAG,"onScrollStateChanged:"+newState);
94 | }
95 |
96 | @Override
97 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
98 | super.onScrolled(recyclerView, dx, dy);
99 | Log.e(TAG, "onScrolled,dx:" + dx+",dy:"+dy);
100 | }
101 | });
102 | }
103 |
104 | private void initAdapterData() {
105 | mAdapter = new TestAdapter(this.getActivity());
106 | List dataList = new ArrayList<>();
107 | for(int i = 0;i<30;i++){
108 | dataList.add(i+"");
109 | }
110 | mAdapter.setDataList(dataList);
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/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/com/support/android/designlibdemo/WithHeaderFragment.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo;
2 |
3 | import android.os.Bundle;
4 | import android.os.Handler;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.widget.SwipeRefreshLayout;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.util.Log;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 |
15 | import com.edus.view.DmRecyclerViewWrapper;
16 | import com.edus.view.decoration.LinearItemDividerDecoration;
17 | import com.support.android.designlibdemo.adapter.TestAdapter;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | /**
23 | * Created by Administrator on 2016/1/12.
24 | */
25 | public class WithHeaderFragment extends Fragment {
26 |
27 | private final String TAG = this.getClass().getSimpleName();
28 |
29 | private DmRecyclerViewWrapper mDrvwContent;
30 | private TestAdapter mAdapter;
31 | private boolean isFirstTime = true;
32 | private boolean isSecondTime = false;
33 | private View mHeadView1;
34 |
35 | @Nullable
36 | @Override
37 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
38 | return inflater.inflate(R.layout.fragment_cheese_2_list, container, false);
39 | }
40 |
41 | @Override
42 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
43 | super.onViewCreated(view, savedInstanceState);
44 | mDrvwContent = (DmRecyclerViewWrapper) view.findViewById(R.id.rv_content);
45 | }
46 |
47 | @Override
48 | public void onActivityCreated(@Nullable Bundle savedInstanceState) {
49 | super.onActivityCreated(savedInstanceState);
50 | setupRecyclerView();
51 | }
52 |
53 | private void setupRecyclerView() {
54 | initAdapterData();
55 | mDrvwContent.setAdapter(mAdapter);
56 | mDrvwContent.addItemDecoration(new LinearItemDividerDecoration(this.getActivity(), LinearItemDividerDecoration.VERTICAL_LIST));
57 | mDrvwContent.setLayoutManager(new LinearLayoutManager(this.getActivity(), LinearLayoutManager.VERTICAL, false));
58 | mDrvwContent.setOnLoadMoreListener(new DmRecyclerViewWrapper.OnLoadMoreListener() {
59 | @Override
60 | public void loadMore(int itemsCount, int maxLastVisiblePosition) {
61 | new Handler().postDelayed(new Runnable() {
62 | @Override
63 | public void run() {
64 | List data = mAdapter.getDataList();
65 | int lastCount = data.size();
66 | for (int i = 0; i <= 3; i++) {
67 | data.add(data.size() + 1 + "");
68 | }
69 | // mAdapter.notifyDataSetChanged();
70 | mAdapter.notifyAdapterItemRangeInserted(lastCount,0);
71 | }
72 | }, 2000);
73 | }
74 | });
75 |
76 | mDrvwContent.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
77 |
78 | @Override
79 | public void onRefresh() {
80 | if(isFirstTime){
81 | isFirstTime = false;
82 | isSecondTime = true;
83 | mAdapter.removeHeaderView(mHeadView1, true);
84 | }else if(isSecondTime){
85 | isSecondTime = false;
86 | mAdapter.addHeaderView(mHeadView1, true);
87 | }
88 | new Handler().postDelayed(new Runnable() {
89 | @Override
90 | public void run() {
91 |
92 | mDrvwContent.setRefreshing(false);
93 | List data = mAdapter.getDataList();
94 | int index = data.size();
95 | for (int i = 0; i <= 3; i++) {
96 | data.add(0, data.size() + 1 + "");
97 | }
98 | mAdapter.notifyAdapterItemRangeInserted(0,3);
99 | // mAdapter.notifyDataSetChanged();
100 | }
101 | }, 2000);
102 | }
103 | });
104 | mDrvwContent.enableLoadMore(true);
105 | mDrvwContent.enableRefresh(true);
106 | mDrvwContent.addOnScrollListener(new RecyclerView.OnScrollListener() {
107 | @Override
108 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
109 | super.onScrollStateChanged(recyclerView, newState);
110 | Log.e(TAG,"onScrollStateChanged:"+newState);
111 | }
112 |
113 | @Override
114 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
115 | super.onScrolled(recyclerView, dx, dy);
116 | Log.e(TAG, "onScrolled,dx:" + dx+",dy:"+dy);
117 | }
118 | });
119 | }
120 |
121 | private void initAdapterData() {
122 | mAdapter = new TestAdapter(this.getActivity());
123 | mAdapter.addHeaderView(new SampleHeader(this.getActivity()));
124 | mHeadView1 = new SampleHeader1(this.getActivity());
125 | mAdapter.addHeaderView(mHeadView1);
126 | mAdapter.addHeaderView(new SampleHeader2(this.getActivity()));
127 | List dataList = new ArrayList<>();
128 | for(int i = 0;i<30;i++){
129 | dataList.add(i+"");
130 | }
131 | mAdapter.setDataList(dataList);
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/CheeseListFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 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 com.support.android.designlibdemo;
18 |
19 | import android.content.Context;
20 | import android.content.Intent;
21 | import android.os.Bundle;
22 | import android.support.annotation.Nullable;
23 | import android.support.v4.app.Fragment;
24 | import android.support.v7.widget.LinearLayoutManager;
25 | import android.support.v7.widget.RecyclerView;
26 | import android.util.TypedValue;
27 | import android.view.LayoutInflater;
28 | import android.view.View;
29 | import android.view.ViewGroup;
30 | import android.widget.ImageView;
31 | import android.widget.TextView;
32 |
33 | import com.bumptech.glide.Glide;
34 | import com.edus.view.decoration.LinearItemDividerDecoration;
35 |
36 | import java.util.ArrayList;
37 | import java.util.List;
38 | import java.util.Random;
39 |
40 | /**
41 | * RecyclerView的基本用法
42 | */
43 | public class CheeseListFragment extends Fragment {
44 |
45 | @Nullable
46 | @Override
47 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
48 | RecyclerView rv = (RecyclerView) inflater.inflate(
49 | R.layout.fragment_cheese_list, container, false);
50 | setupRecyclerView(rv);
51 | return rv;
52 | }
53 |
54 | private void setupRecyclerView(RecyclerView recyclerView) {
55 | //1. RecyclerView设置LayoutManager
56 | //2. RecyclerView设置Adapter
57 | //3. adapter复写对应的getItemCount, getItemViewType,onCreateViewHolder,onBindViewHolder
58 | //4. adapter设置数据
59 | //5. 如果需要分割线,RecyclerView设置ItemDecoration
60 | //6. 如果需要动画,设置ItemDecoration
61 | recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
62 | recyclerView.addItemDecoration(new LinearItemDividerDecoration(this.getActivity(), LinearItemDividerDecoration.VERTICAL_LIST));
63 | recyclerView.setAdapter(new SimpleStringRecyclerViewAdapter(getActivity(),
64 | getRandomSublist(Cheeses.sCheeseStrings, 30)));
65 | }
66 |
67 | private List getRandomSublist(String[] array, int amount) {
68 | ArrayList list = new ArrayList<>(amount);
69 | Random random = new Random();
70 | while (list.size() < amount) {
71 | list.add(array[random.nextInt(array.length)]);
72 | }
73 | return list;
74 | }
75 |
76 | public static class SimpleStringRecyclerViewAdapter
77 | extends RecyclerView.Adapter {
78 |
79 | private final TypedValue mTypedValue = new TypedValue();
80 | private int mBackground;
81 | private List mValues;
82 |
83 | public static class ViewHolder extends RecyclerView.ViewHolder {
84 | public String mBoundString;
85 |
86 | public final View mView;
87 | public final ImageView mImageView;
88 | public final TextView mTextView;
89 |
90 | public ViewHolder(View view) {
91 | super(view);
92 | mView = view;
93 | mImageView = (ImageView) view.findViewById(R.id.avatar);
94 | mTextView = (TextView) view.findViewById(android.R.id.text1);
95 | }
96 |
97 | @Override
98 | public String toString() {
99 | return super.toString() + " '" + mTextView.getText();
100 | }
101 | }
102 |
103 | public String getValueAt(int position) {
104 | return mValues.get(position);
105 | }
106 |
107 | public SimpleStringRecyclerViewAdapter(Context context, List items) {
108 | context.getTheme().resolveAttribute(R.attr.selectableItemBackground, mTypedValue, true);
109 | mBackground = mTypedValue.resourceId;
110 | mValues = items;
111 | }
112 |
113 | @Override
114 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
115 | View view = LayoutInflater.from(parent.getContext())
116 | .inflate(R.layout.list_item, parent, false);
117 | view.setBackgroundResource(mBackground);
118 | return new ViewHolder(view);
119 | }
120 |
121 | @Override
122 | public void onBindViewHolder(final ViewHolder holder, int position) {
123 | holder.mBoundString = mValues.get(position);
124 | holder.mTextView.setText(mValues.get(position));
125 |
126 | holder.mView.setOnClickListener(new View.OnClickListener() {
127 | @Override
128 | public void onClick(View v) {
129 | Context context = v.getContext();
130 | Intent intent = new Intent(context, CheeseDetailActivity.class);
131 | intent.putExtra(CheeseDetailActivity.EXTRA_NAME, holder.mBoundString);
132 |
133 | context.startActivity(intent);
134 | }
135 | });
136 |
137 | Glide.with(holder.mImageView.getContext())
138 | .load(Cheeses.getRandomCheeseDrawable())
139 | .fitCenter()
140 | .into(holder.mImageView);
141 | }
142 |
143 | @Override
144 | public int getItemCount() {
145 | return mValues.size();
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/decoration/DividerGridItemDecoration.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.decoration;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Canvas;
7 | import android.graphics.Rect;
8 | import android.graphics.drawable.Drawable;
9 | import android.support.v7.widget.GridLayoutManager;
10 | import android.support.v7.widget.RecyclerView.LayoutManager;
11 | import android.support.v7.widget.RecyclerView.State;
12 | import android.support.v7.widget.StaggeredGridLayoutManager;
13 | import android.view.View;
14 |
15 | /**
16 | * Created by panda on 2018/1/29.
17 | */
18 |
19 | public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {
20 |
21 | private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
22 | private Drawable mDivider;
23 |
24 | public DividerGridItemDecoration(Context context) {
25 | final TypedArray a = context.obtainStyledAttributes(ATTRS);
26 | mDivider = a.getDrawable(0);
27 | a.recycle();
28 | }
29 |
30 | @Override
31 | public void onDraw(Canvas c, RecyclerView parent, State state) {
32 |
33 | drawHorizontal(c, parent);
34 | drawVertical(c, parent);
35 |
36 | }
37 |
38 | private int getSpanCount(RecyclerView parent) {
39 | // 列数
40 | int spanCount = -1;
41 | LayoutManager layoutManager = parent.getLayoutManager();
42 | if (layoutManager instanceof GridLayoutManager) {
43 | spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
44 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
45 | spanCount = ((StaggeredGridLayoutManager) layoutManager)
46 | .getSpanCount();
47 | }
48 | return spanCount;
49 | }
50 |
51 | private void drawHorizontal(Canvas c, RecyclerView parent) {
52 | int childCount = parent.getChildCount();
53 | for (int i = 0; i < childCount; i++) {
54 | final View child = parent.getChildAt(i);
55 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
56 | .getLayoutParams();
57 | final int left = child.getLeft() - params.leftMargin;
58 | final int right = child.getRight() + params.rightMargin
59 | + mDivider.getIntrinsicWidth();
60 | final int top = child.getBottom() + params.bottomMargin;
61 | final int bottom = top + mDivider.getIntrinsicHeight();
62 | mDivider.setBounds(left, top, right, bottom);
63 | mDivider.draw(c);
64 | }
65 | }
66 |
67 | private void drawVertical(Canvas c, RecyclerView parent) {
68 | final int childCount = parent.getChildCount();
69 | for (int i = 0; i < childCount; i++) {
70 | final View child = parent.getChildAt(i);
71 |
72 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
73 | .getLayoutParams();
74 | final int top = child.getTop() - params.topMargin;
75 | final int bottom = child.getBottom() + params.bottomMargin;
76 | final int left = child.getRight() + params.rightMargin;
77 | final int right = left + mDivider.getIntrinsicWidth();
78 |
79 | mDivider.setBounds(left, top, right, bottom);
80 | mDivider.draw(c);
81 | }
82 | }
83 |
84 | private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
85 | int childCount) {
86 | LayoutManager layoutManager = parent.getLayoutManager();
87 | if (layoutManager instanceof GridLayoutManager) {
88 | if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
89 | {
90 | return true;
91 | }
92 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
93 | int orientation = ((StaggeredGridLayoutManager) layoutManager)
94 | .getOrientation();
95 | if (orientation == StaggeredGridLayoutManager.VERTICAL) {
96 | if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
97 | {
98 | return true;
99 | }
100 | } else {
101 | childCount = childCount - childCount % spanCount;
102 | if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
103 | return true;
104 | }
105 | }
106 | return false;
107 | }
108 |
109 | private boolean isLastRow(RecyclerView parent, int pos, int spanCount, int childCount) {
110 | LayoutManager layoutManager = parent.getLayoutManager();
111 | if (layoutManager instanceof GridLayoutManager) {
112 | childCount = childCount - childCount % spanCount;
113 | if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
114 | return true;
115 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
116 | int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
117 | // StaggeredGridLayoutManager 且纵向滚动
118 | if (orientation == StaggeredGridLayoutManager.VERTICAL) {
119 | childCount = childCount - childCount % spanCount;
120 | // 如果是最后一行,则不需要绘制底部
121 | if (pos >= childCount)
122 | return true;
123 | } else {// StaggeredGridLayoutManager 且横向滚动
124 | // 如果是最后一行,则不需要绘制底部
125 | if ((pos + 1) % spanCount == 0) {
126 | return true;
127 | }
128 | }
129 | }
130 | return false;
131 | }
132 |
133 | @Override
134 | public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
135 | int spanCount = getSpanCount(parent);
136 | int childCount = parent.getAdapter().getItemCount();
137 | if (isLastRow(parent, itemPosition, spanCount, childCount)){// 如果是最后一行,则不需要绘制底部
138 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
139 | } else if (isLastColum(parent, itemPosition, spanCount, childCount)){// 如果是最后一列,则不需要绘制右边
140 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
141 | } else {
142 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight());
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/GridWithHeaderFragment.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo;
2 |
3 | import android.os.Bundle;
4 | import android.os.Handler;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.widget.SwipeRefreshLayout;
8 | import android.support.v7.widget.GridLayoutManager;
9 | import android.support.v7.widget.LinearLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.util.Log;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 |
16 | import com.edus.view.DmRecyclerViewWrapper;
17 | import com.edus.view.decoration.DividerGridItemDecoration;
18 | import com.edus.view.decoration.LinearItemDividerDecoration;
19 | import com.support.android.designlibdemo.adapter.TestAdapter;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 |
24 | /**
25 | * Created by Administrator on 2016/1/12.
26 | */
27 | public class GridWithHeaderFragment extends Fragment implements GridOperation{
28 |
29 | private final String TAG = this.getClass().getSimpleName();
30 |
31 | private int mOrientation = LinearLayoutManager.VERTICAL;
32 | private int mSpanCount = 2;
33 | private GridLayoutManager mGridLayoutManager;
34 |
35 | private DmRecyclerViewWrapper mDrvwContent;
36 | private TestAdapter mAdapter;
37 | private boolean isFirstTime = true;
38 | private boolean isSecondTime = false;
39 | private View mHeadView1;
40 |
41 | @Nullable
42 | @Override
43 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
44 | return inflater.inflate(R.layout.fragment_cheese_grid_with_header, container, false);
45 | }
46 |
47 | @Override
48 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
49 | super.onViewCreated(view, savedInstanceState);
50 | mDrvwContent = (DmRecyclerViewWrapper) view.findViewById(R.id.rv_content);
51 | }
52 |
53 | @Override
54 | public void onActivityCreated(@Nullable Bundle savedInstanceState) {
55 | super.onActivityCreated(savedInstanceState);
56 | setupRecyclerView();
57 | }
58 |
59 | private void setupRecyclerView() {
60 | initAdapterData();
61 | mDrvwContent.setAdapter(mAdapter);
62 | mGridLayoutManager = new GridLayoutManager(mDrvwContent.getContext(), mSpanCount, mOrientation, false);
63 | mDrvwContent.setLayoutManager(mGridLayoutManager);
64 | mDrvwContent.addItemDecoration(new DividerGridItemDecoration(this.getActivity()));
65 | mDrvwContent.setOnLoadMoreListener(new DmRecyclerViewWrapper.OnLoadMoreListener() {
66 | @Override
67 | public void loadMore(int itemsCount, int maxLastVisiblePosition) {
68 | new Handler().postDelayed(new Runnable() {
69 | @Override
70 | public void run() {
71 | List data = mAdapter.getDataList();
72 | int lastCount = data.size();
73 | for (int i = 0; i <= 3; i++) {
74 | data.add(data.size() + 1 + "");
75 | }
76 | // mAdapter.notifyDataSetChanged();
77 | mAdapter.notifyAdapterItemRangeInserted(lastCount,0);
78 | }
79 | }, 2000);
80 | }
81 | });
82 |
83 | mDrvwContent.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
84 |
85 | @Override
86 | public void onRefresh() {
87 | if(isFirstTime){
88 | isFirstTime = false;
89 | isSecondTime = true;
90 | mAdapter.removeHeaderView(mHeadView1, true);
91 | }else if(isSecondTime){
92 | isSecondTime = false;
93 | mAdapter.addHeaderView(mHeadView1, true);
94 | }
95 | new Handler().postDelayed(new Runnable() {
96 | @Override
97 | public void run() {
98 |
99 | mDrvwContent.setRefreshing(false);
100 | List data = mAdapter.getDataList();
101 | int index = data.size();
102 | for (int i = 0; i <= 3; i++) {
103 | data.add(0, data.size() + 1 + "");
104 | }
105 | mAdapter.notifyAdapterItemRangeInserted(0,3);
106 | // mAdapter.notifyDataSetChanged();
107 | }
108 | }, 2000);
109 | }
110 | });
111 | mDrvwContent.enableLoadMore(true);
112 | mDrvwContent.enableRefresh(true);
113 | mDrvwContent.addOnScrollListener(new RecyclerView.OnScrollListener() {
114 | @Override
115 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
116 | super.onScrollStateChanged(recyclerView, newState);
117 | Log.e(TAG,"onScrollStateChanged:"+newState);
118 | }
119 |
120 | @Override
121 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
122 | super.onScrolled(recyclerView, dx, dy);
123 | Log.e(TAG, "onScrolled,dx:" + dx+",dy:"+dy);
124 | }
125 | });
126 | }
127 |
128 | private void initAdapterData() {
129 | mAdapter = new TestAdapter(this.getActivity());
130 | mAdapter.addHeaderView(new SampleHeader(this.getActivity()));
131 | mHeadView1 = new SampleHeader1(this.getActivity());
132 | mAdapter.addHeaderView(mHeadView1);
133 | mAdapter.addHeaderView(new SampleHeader2(this.getActivity()));
134 | List dataList = new ArrayList<>();
135 | for(int i = 0;i<30;i++){
136 | dataList.add(i+"");
137 | }
138 | mAdapter.setDataList(dataList);
139 | }
140 |
141 | @Override
142 | public void setOrientation(int orientation) {
143 | mOrientation = orientation;
144 | if(mGridLayoutManager != null){
145 | mGridLayoutManager.setOrientation(mOrientation);
146 | }
147 | }
148 |
149 | @Override
150 | public void setSpanCount(int spanCount) {
151 | if(spanCount < 1){
152 | return;
153 | }
154 | mSpanCount = spanCount;
155 | if(mGridLayoutManager != null){
156 | mGridLayoutManager.setSpanCount(spanCount);
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/sticky/StickyRecyclerHeadersDecoration.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.sticky;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Rect;
5 | import android.support.v7.widget.LinearLayoutManager;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.util.SparseArray;
8 | import android.view.View;
9 |
10 | import com.edus.view.sticky.util.LinearLayoutOrientationProvider;
11 | import com.edus.view.sticky.util.OrientationProvider;
12 | import com.edus.view.sticky.caching.HeaderProvider;
13 | import com.edus.view.sticky.caching.HeaderViewCache;
14 | import com.edus.view.sticky.calculation.DimensionCalculator;
15 | import com.edus.view.sticky.rendering.HeaderRenderer;
16 |
17 | public class StickyRecyclerHeadersDecoration extends RecyclerView.ItemDecoration {
18 |
19 | private final StickyRecyclerHeadersAdapter mAdapter;
20 | private final SparseArray mHeaderRects = new SparseArray<>();
21 | private final HeaderProvider mHeaderProvider;
22 | private final OrientationProvider mOrientationProvider;
23 | private final HeaderPositionCalculator mHeaderPositionCalculator;
24 | private final HeaderRenderer mRenderer;
25 | private final DimensionCalculator mDimensionCalculator;
26 |
27 | // TODO: Consider passing in orientation to simplify orientation accounting within calculation
28 | public StickyRecyclerHeadersDecoration(StickyRecyclerHeadersAdapter adapter) {
29 | this(adapter, new LinearLayoutOrientationProvider(), new DimensionCalculator());
30 | }
31 |
32 | private StickyRecyclerHeadersDecoration(StickyRecyclerHeadersAdapter adapter, OrientationProvider orientationProvider,
33 | DimensionCalculator dimensionCalculator) {
34 | this(adapter, orientationProvider, dimensionCalculator, new HeaderRenderer(orientationProvider),
35 | new HeaderViewCache(adapter, orientationProvider));
36 | }
37 |
38 | private StickyRecyclerHeadersDecoration(StickyRecyclerHeadersAdapter adapter, OrientationProvider orientationProvider,
39 | DimensionCalculator dimensionCalculator, HeaderRenderer headerRenderer, HeaderProvider headerProvider) {
40 | this(adapter, headerRenderer, orientationProvider, dimensionCalculator, headerProvider,
41 | new HeaderPositionCalculator(adapter, headerProvider, orientationProvider,
42 | dimensionCalculator));
43 | }
44 |
45 | private StickyRecyclerHeadersDecoration(StickyRecyclerHeadersAdapter adapter, HeaderRenderer headerRenderer,
46 | OrientationProvider orientationProvider, DimensionCalculator dimensionCalculator, HeaderProvider headerProvider,
47 | HeaderPositionCalculator headerPositionCalculator) {
48 | mAdapter = adapter;
49 | mHeaderProvider = headerProvider;
50 | mOrientationProvider = orientationProvider;
51 | mRenderer = headerRenderer;
52 | mDimensionCalculator = dimensionCalculator;
53 | mHeaderPositionCalculator = headerPositionCalculator;
54 | }
55 |
56 | @Override
57 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
58 | super.getItemOffsets(outRect, view, parent, state);
59 | int itemPosition = parent.getChildAdapterPosition(view);
60 | if (itemPosition == RecyclerView.NO_POSITION) {
61 | return;
62 | }
63 | if (mHeaderPositionCalculator.hasNewHeader(itemPosition)) {
64 | View header = getHeaderView(parent, itemPosition);
65 | setItemOffsetsForHeader(outRect, header, mOrientationProvider.getOrientation(parent));
66 | }
67 | }
68 |
69 | /**
70 | * Sets the offsets for the first item in a section to make room for the header view
71 | *
72 | * @param itemOffsets rectangle to define offsets for the item
73 | * @param header view used to calculate offset for the item
74 | * @param orientation used to calculate offset for the item
75 | */
76 | private void setItemOffsetsForHeader(Rect itemOffsets, View header, int orientation) {
77 | Rect headerMargins = mDimensionCalculator.getMargins(header);
78 | if (orientation == LinearLayoutManager.VERTICAL) {
79 | itemOffsets.top = header.getHeight() + headerMargins.top + headerMargins.bottom;
80 | } else {
81 | itemOffsets.left = header.getWidth() + headerMargins.left + headerMargins.right;
82 | }
83 | }
84 |
85 | @Override
86 | public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
87 | super.onDrawOver(canvas, parent, state);
88 | mHeaderRects.clear();
89 |
90 | if (parent.getChildCount() <= 0 || mAdapter.getItemCount() <= 0) {
91 | return;
92 | }
93 |
94 | for (int i = 0; i < parent.getChildCount(); i++) {
95 | View itemView = parent.getChildAt(i);
96 | int position = parent.getChildAdapterPosition(itemView);
97 | if (position == RecyclerView.NO_POSITION) {
98 | continue;
99 | }
100 | if (hasStickyHeader(i, position) || mHeaderPositionCalculator.hasNewHeader(position)) {
101 | View header = mHeaderProvider.getHeader(parent, position);
102 | Rect headerOffset = mHeaderPositionCalculator.getHeaderBounds(parent, header,
103 | itemView, hasStickyHeader(i, position));
104 | mRenderer.drawHeader(parent, canvas, header, headerOffset);
105 | mHeaderRects.put(position, headerOffset);
106 | }
107 | }
108 | }
109 |
110 | private boolean hasStickyHeader(int listChildPosition, int indexInList) {
111 | if (listChildPosition > 0 || mAdapter.getHeaderId(indexInList) < 0) {
112 | return false;
113 | }
114 |
115 | return true;
116 | }
117 |
118 | /**
119 | * Gets the position of the header under the specified (x, y) coordinates.
120 | *
121 | * @param x x-coordinate
122 | * @param y y-coordinate
123 | * @return position of header, or -1 if not found
124 | */
125 | public int findHeaderPositionUnder(int x, int y) {
126 | for (int i = 0; i < mHeaderRects.size(); i++) {
127 | Rect rect = mHeaderRects.get(mHeaderRects.keyAt(i));
128 | if (rect.contains(x, y)) {
129 | return mHeaderRects.keyAt(i);
130 | }
131 | }
132 | return -1;
133 | }
134 |
135 | /**
136 | * Gets the header view for the associated position. If it doesn't exist yet, it will be
137 | * created, measured, and laid out.
138 | *
139 | * @param parent
140 | * @param position
141 | * @return Header view
142 | */
143 | public View getHeaderView(RecyclerView parent, int position) {
144 | return mHeaderProvider.getHeader(parent, position);
145 | }
146 |
147 | /**
148 | * Invalidates cached headers. This does not invalidate the recyclerview, you should do that manually after
149 | * calling this method.
150 | */
151 | public void invalidateHeaders() {
152 | mHeaderProvider.invalidate();
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/CheeseGridFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 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 com.support.android.designlibdemo;
18 |
19 | import android.content.Context;
20 | import android.content.Intent;
21 | import android.os.Bundle;
22 | import android.support.annotation.Nullable;
23 | import android.support.v4.app.Fragment;
24 | import android.support.v7.widget.GridLayoutManager;
25 | import android.support.v7.widget.LinearLayoutManager;
26 | import android.support.v7.widget.RecyclerView;
27 | import android.util.TypedValue;
28 | import android.view.LayoutInflater;
29 | import android.view.View;
30 | import android.view.ViewGroup;
31 | import android.widget.GridLayout;
32 | import android.widget.ImageView;
33 | import android.widget.LinearLayout;
34 | import android.widget.TextView;
35 |
36 | import com.bumptech.glide.Glide;
37 | import com.edus.view.decoration.DividerGridItemDecoration;
38 | import com.edus.view.decoration.LinearItemDividerDecoration;
39 |
40 | import java.util.ArrayList;
41 | import java.util.List;
42 | import java.util.Random;
43 |
44 | /**
45 | * RecyclerView的基本用法
46 | */
47 | public class CheeseGridFragment extends Fragment implements GridOperation{
48 |
49 | private int mOrientation = LinearLayoutManager.VERTICAL;
50 | private int mSpanCount = 2;
51 | private GridLayoutManager mGridLayoutManager;
52 |
53 | @Nullable
54 | @Override
55 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
56 | RecyclerView rv = (RecyclerView) inflater.inflate(
57 | R.layout.fragment_cheese_grid, container, false);
58 | setupRecyclerView(rv);
59 | return rv;
60 | }
61 |
62 | private void setupRecyclerView(RecyclerView recyclerView) {
63 | //1. RecyclerView设置LayoutManager
64 | //2. RecyclerView设置Adapter
65 | //3. adapter复写对应的getItemCount, getItemViewType,onCreateViewHolder,onBindViewHolder
66 | //4. adapter设置数据
67 | //5. 如果需要分割线,RecyclerView设置ItemDecoration
68 | //6. 如果需要动画,设置ItemDecoration
69 | mGridLayoutManager = new GridLayoutManager(recyclerView.getContext(), mSpanCount, mOrientation, false);
70 | recyclerView.setLayoutManager(mGridLayoutManager);
71 | recyclerView.addItemDecoration(new DividerGridItemDecoration(this.getActivity()));
72 | recyclerView.setAdapter(new SimpleStringRecyclerViewAdapter(getActivity(),
73 | getRandomSublist(Cheeses.sCheeseStrings, 30)));
74 | }
75 |
76 | private List getRandomSublist(String[] array, int amount) {
77 | ArrayList list = new ArrayList<>(amount);
78 | Random random = new Random();
79 | while (list.size() < amount) {
80 | list.add(array[random.nextInt(array.length)]);
81 | }
82 | return list;
83 | }
84 |
85 | @Override
86 | public void setOrientation(int orientation) {
87 | mOrientation = orientation;
88 | if(mGridLayoutManager != null){
89 | mGridLayoutManager.setOrientation(mOrientation);
90 | }
91 | }
92 |
93 | @Override
94 | public void setSpanCount(int spanCount) {
95 | if(spanCount < 1){
96 | return;
97 | }
98 | mSpanCount = spanCount;
99 | if(mGridLayoutManager != null){
100 | mGridLayoutManager.setSpanCount(spanCount);
101 | }
102 | }
103 |
104 | public static class SimpleStringRecyclerViewAdapter
105 | extends RecyclerView.Adapter {
106 |
107 | private final TypedValue mTypedValue = new TypedValue();
108 | private int mBackground;
109 | private List mValues;
110 |
111 | public static class ViewHolder extends RecyclerView.ViewHolder {
112 | public String mBoundString;
113 |
114 | public final View mView;
115 | public final ImageView mImageView;
116 | public final TextView mTextView;
117 |
118 | public ViewHolder(View view) {
119 | super(view);
120 | mView = view;
121 | mImageView = (ImageView) view.findViewById(R.id.avatar);
122 | mTextView = (TextView) view.findViewById(android.R.id.text1);
123 | }
124 |
125 | @Override
126 | public String toString() {
127 | return super.toString() + " '" + mTextView.getText();
128 | }
129 | }
130 |
131 | public String getValueAt(int position) {
132 | return mValues.get(position);
133 | }
134 |
135 | public SimpleStringRecyclerViewAdapter(Context context, List items) {
136 | context.getTheme().resolveAttribute(R.attr.selectableItemBackground, mTypedValue, true);
137 | mBackground = mTypedValue.resourceId;
138 | mValues = items;
139 | }
140 |
141 | @Override
142 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
143 | View view = LayoutInflater.from(parent.getContext())
144 | .inflate(R.layout.list_item, parent, false);
145 | view.setBackgroundResource(mBackground);
146 | return new ViewHolder(view);
147 | }
148 |
149 | @Override
150 | public void onBindViewHolder(final ViewHolder holder, int position) {
151 | holder.mBoundString = mValues.get(position);
152 | holder.mTextView.setText(mValues.get(position));
153 |
154 | holder.mView.setOnClickListener(new View.OnClickListener() {
155 | @Override
156 | public void onClick(View v) {
157 | Context context = v.getContext();
158 | Intent intent = new Intent(context, CheeseDetailActivity.class);
159 | intent.putExtra(CheeseDetailActivity.EXTRA_NAME, holder.mBoundString);
160 |
161 | context.startActivity(intent);
162 | }
163 | });
164 |
165 | Glide.with(holder.mImageView.getContext())
166 | .load(Cheeses.getRandomCheeseDrawable())
167 | .fitCenter()
168 | .into(holder.mImageView);
169 | }
170 |
171 | @Override
172 | public int getItemCount() {
173 | return mValues.size();
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/GridActivity.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo;
2 |
3 | import android.content.DialogInterface;
4 | import android.os.Bundle;
5 | import android.support.design.widget.NavigationView;
6 | import android.support.design.widget.TabLayout;
7 | import android.support.v4.app.Fragment;
8 | import android.support.v4.app.FragmentManager;
9 | import android.support.v4.app.FragmentPagerAdapter;
10 | import android.support.v4.view.GravityCompat;
11 | import android.support.v4.view.ViewPager;
12 | import android.support.v4.widget.DrawerLayout;
13 | import android.support.v7.app.ActionBar;
14 | import android.support.v7.app.AlertDialog;
15 | import android.support.v7.app.AppCompatActivity;
16 | import android.support.v7.widget.LinearLayoutManager;
17 | import android.support.v7.widget.Toolbar;
18 | import android.view.LayoutInflater;
19 | import android.view.Menu;
20 | import android.view.MenuItem;
21 | import android.view.View;
22 | import android.widget.RadioGroup;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | /**
28 | * Created by panda on 2018/1/28.
29 | */
30 |
31 | public class GridActivity extends AppCompatActivity {
32 |
33 | private DrawerLayout mDrawerLayout;
34 | private Adapter mAdapter;
35 |
36 | @Override
37 | protected void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | setContentView(R.layout.activity_grid);
40 |
41 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
42 | setSupportActionBar(toolbar);
43 |
44 | final ActionBar ab = getSupportActionBar();
45 | ab.setHomeAsUpIndicator(R.drawable.ic_menu);
46 | ab.setDisplayHomeAsUpEnabled(true);
47 |
48 | mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
49 |
50 | NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
51 | if (navigationView != null) {
52 | setupDrawerContent(navigationView);
53 | }
54 |
55 | ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
56 | if (viewPager != null) {
57 | setupViewPager(viewPager);
58 | }
59 |
60 | TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
61 | tabLayout.setupWithViewPager(viewPager);
62 | }
63 |
64 | @Override
65 | public boolean onCreateOptionsMenu(Menu menu) {
66 | getMenuInflater().inflate(R.menu.sample_actions, menu);
67 | return true;
68 | }
69 |
70 | @Override
71 | public boolean onOptionsItemSelected(MenuItem item) {
72 | switch (item.getItemId()) {
73 | case android.R.id.home:
74 | mDrawerLayout.openDrawer(GravityCompat.START);
75 | return true;
76 | case R.id.action_settings:
77 | //弹窗修改
78 | showAlterDialog();
79 | return true;
80 | }
81 | return super.onOptionsItemSelected(item);
82 | }
83 |
84 | private void showAlterDialog() {
85 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
86 | builder.setTitle("update recycler config");
87 | View inflate = LayoutInflater.from(this).inflate(R.layout.grid_dialog, null);
88 | final RadioGroup radioGroup = (RadioGroup) inflate.findViewById(R.id.rg_orientaion);
89 | builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
90 | @Override
91 | public void onClick(DialogInterface dialog, int which) {
92 | int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId();
93 | if(checkedRadioButtonId == R.id.rb_vertical){
94 | mAdapter.setOrientation(LinearLayoutManager.VERTICAL);
95 | }else if(checkedRadioButtonId == R.id.rb_horizontal){
96 | mAdapter.setOrientation(LinearLayoutManager.HORIZONTAL);
97 | }
98 | dialog.dismiss();
99 | }
100 | });
101 | builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
102 | @Override
103 | public void onClick(DialogInterface dialog, int which) {
104 |
105 | }
106 | });
107 | builder.setView(inflate);
108 | builder.create().show();
109 | }
110 |
111 | private void setupViewPager(ViewPager viewPager) {
112 | mAdapter = new Adapter(getSupportFragmentManager());
113 | mAdapter.addFragment(new CheeseGridFragment(), "normal");
114 | mAdapter.addFragment(new GridWithHeaderFragment(), "header");
115 | viewPager.setAdapter(mAdapter);
116 | }
117 |
118 | private void setupDrawerContent(NavigationView navigationView) {
119 | navigationView.setNavigationItemSelectedListener(
120 | new NavigationView.OnNavigationItemSelectedListener() {
121 | @Override
122 | public boolean onNavigationItemSelected(MenuItem menuItem) {
123 | menuItem.setChecked(true);
124 | mDrawerLayout.closeDrawers();
125 | return true;
126 | }
127 | });
128 | }
129 |
130 | static class Adapter extends FragmentPagerAdapter implements GridOperation{
131 | private final List mFragments = new ArrayList<>();
132 | private final List mFragmentTitles = new ArrayList<>();
133 |
134 | public Adapter(FragmentManager fm) {
135 | super(fm);
136 | }
137 |
138 | public void addFragment(Fragment fragment, String title) {
139 | mFragments.add(fragment);
140 | mFragmentTitles.add(title);
141 | }
142 |
143 | @Override
144 | public Fragment getItem(int position) {
145 | return mFragments.get(position);
146 | }
147 |
148 | @Override
149 | public int getCount() {
150 | return mFragments.size();
151 | }
152 |
153 | @Override
154 | public CharSequence getPageTitle(int position) {
155 | return mFragmentTitles.get(position);
156 | }
157 |
158 | @Override
159 | public void setOrientation(int orientation) {
160 | if(mFragments != null && !mFragments.isEmpty()){
161 | for(Fragment fragment : mFragments){
162 | if(fragment instanceof GridOperation){
163 | ((GridOperation)fragment).setOrientation(orientation);
164 | }
165 | }
166 | }
167 | }
168 |
169 | @Override
170 | public void setSpanCount(int spanCount) {
171 | if(mFragments != null && !mFragments.isEmpty()){
172 | for(Fragment fragment : mFragments){
173 | if(fragment instanceof GridOperation){
174 | ((GridOperation)fragment).setSpanCount(spanCount);
175 | }
176 | }
177 | }
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/StickHeadFragment.java:
--------------------------------------------------------------------------------
1 | package com.support.android.designlibdemo;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.os.Handler;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.Fragment;
8 | import android.support.v4.widget.SwipeRefreshLayout;
9 | import android.support.v7.widget.LinearLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.util.Log;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.widget.TextView;
16 |
17 | import com.edus.view.DmBaseAdapter;
18 | import com.edus.view.DmBaseViewHolder;
19 | import com.edus.view.DmRecyclerViewWrapper;
20 | import com.edus.view.decoration.LinearItemDividerDecoration;
21 | import com.edus.view.sticky.StickyRecyclerHeadersAdapter;
22 | import com.edus.view.sticky.StickyRecyclerHeadersDecoration;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | /**
28 | * Created by yqpan on 2016/1/12.
29 | */
30 | public class StickHeadFragment extends Fragment {
31 |
32 | private final String TAG = this.getClass().getSimpleName();
33 |
34 | private DmRecyclerViewWrapper mDrvwContent;
35 | private StickAdapter mAdapter;
36 |
37 | @Nullable
38 | @Override
39 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
40 | return inflater.inflate(R.layout.fragment_cheese_2_list, container, false);
41 | }
42 |
43 | @Override
44 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
45 | super.onViewCreated(view, savedInstanceState);
46 | mDrvwContent = (DmRecyclerViewWrapper) view.findViewById(R.id.rv_content);
47 | }
48 |
49 | @Override
50 | public void onActivityCreated(@Nullable Bundle savedInstanceState) {
51 | super.onActivityCreated(savedInstanceState);
52 | setupRecyclerView();
53 | }
54 |
55 | private void setupRecyclerView() {
56 | initAdapterData();
57 | mDrvwContent.setAdapter(mAdapter);
58 | mDrvwContent.addItemDecoration(new StickyRecyclerHeadersDecoration(mAdapter));
59 | mDrvwContent.addItemDecoration(new LinearItemDividerDecoration(this.getActivity(), LinearItemDividerDecoration.VERTICAL_LIST));
60 | mDrvwContent.setLayoutManager(new LinearLayoutManager(this.getActivity(), LinearLayoutManager.VERTICAL, false));
61 | mDrvwContent.setOnLoadMoreListener(new DmRecyclerViewWrapper.OnLoadMoreListener() {
62 | @Override
63 | public void loadMore(int itemsCount, int maxLastVisiblePosition) {
64 | new Handler().postDelayed(new Runnable() {
65 | @Override
66 | public void run() {
67 | List data = mAdapter.getDataList();
68 | for (int i = 0; i <= 3; i++) {
69 | data.add(data.size() + 1 + "");
70 | }
71 | mAdapter.notifyDataSetChanged();
72 | }
73 | }, 2000);
74 | }
75 | });
76 |
77 | mDrvwContent.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
78 | @Override
79 | public void onRefresh() {
80 | new Handler().postDelayed(new Runnable() {
81 | @Override
82 | public void run() {
83 | mDrvwContent.setRefreshing(false);
84 | List data = mAdapter.getDataList();
85 | for (int i = 0; i <= 3; i++) {
86 | data.add(0, data.size() + 1 + "");
87 | }
88 | mAdapter.notifyDataSetChanged();
89 | }
90 | }, 2000);
91 | }
92 | });
93 | mDrvwContent.enableLoadMore(true);
94 | mDrvwContent.enableRefresh(true);
95 | mDrvwContent.addOnScrollListener(new RecyclerView.OnScrollListener() {
96 | @Override
97 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
98 | super.onScrollStateChanged(recyclerView, newState);
99 | Log.e(TAG,"onScrollStateChanged:"+newState);
100 | }
101 |
102 | @Override
103 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
104 | super.onScrolled(recyclerView, dx, dy);
105 | Log.e(TAG, "onScrolled,dx:" + dx+",dy:"+dy);
106 | }
107 | });
108 | }
109 |
110 | private void initAdapterData() {
111 | mAdapter = new StickAdapter(this.getActivity());
112 | List dataList = new ArrayList<>();
113 | for(int i = 0;i<30;i++){
114 | dataList.add(i+"");
115 | }
116 | mAdapter.setDataList(dataList);
117 | }
118 |
119 | public static class StickAdapter extends DmBaseAdapter implements StickyRecyclerHeadersAdapter{
120 |
121 | public StickAdapter(Context context) {
122 | super(context);
123 | }
124 |
125 | @Override
126 | public DmBaseViewHolder onCreateAdapterViewHolder(ViewGroup parent, int viewType) {
127 | return new CustomViewHolder(mInflater.inflate(R.layout.test_item,parent,false));
128 | }
129 |
130 | @Override
131 | public void onBindAdapterViewHolder(DmBaseViewHolder holder, int position) {
132 | String adapterDataItem = getAdapterDataItem(position);
133 | holder.updateData(adapterDataItem, position);
134 | }
135 |
136 |
137 | @Override
138 | public long getHeaderId(int position) {
139 | String adapterDataItem = getAdapterDataItem(position);
140 | if(adapterDataItem != null){
141 | return getAdapterDataItem(position).charAt(0);
142 | }else{
143 | return -1;
144 | }
145 | }
146 |
147 | @Override
148 | public DmBaseViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
149 | return new CustomViewHolder(mInflater.inflate(R.layout.test_head_item,parent,false));
150 | }
151 |
152 | @Override
153 | public void onBindHeaderViewHolder(DmBaseViewHolder holder, int position) {
154 | String adapterDataItem = getAdapterDataItem(position);
155 | holder.updateData(adapterDataItem, position);
156 | }
157 |
158 | public static class CustomViewHolder extends DmBaseViewHolder{
159 | TextView tvDemo;
160 | public CustomViewHolder(View itemView) {
161 | super(itemView);
162 | tvDemo = (TextView) itemView.findViewById(R.id.tv_demo);
163 | }
164 |
165 | @Override
166 | public void updateData(String s, int position) {
167 | super.updateData(s, position);
168 | tvDemo.setText(s);
169 | }
170 | }
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
31 |
32 |
41 |
42 |
49 |
50 |
56 |
57 |
58 |
59 |
60 |
61 |
65 |
66 |
71 |
72 |
76 |
77 |
81 |
82 |
87 |
88 |
92 |
93 |
94 |
95 |
96 |
97 |
103 |
104 |
108 |
109 |
114 |
115 |
119 |
120 |
121 |
122 |
123 |
124 |
130 |
131 |
135 |
136 |
141 |
142 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
163 |
164 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/sticky/HeaderPositionCalculator.java:
--------------------------------------------------------------------------------
1 | package com.edus.view.sticky;
2 |
3 | import android.graphics.Rect;
4 | import android.support.v7.widget.LinearLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.View;
7 |
8 | import com.edus.view.sticky.caching.HeaderProvider;
9 | import com.edus.view.sticky.calculation.DimensionCalculator;
10 | import com.edus.view.sticky.util.OrientationProvider;
11 |
12 |
13 | /**
14 | * Calculates the position and location of header views
15 | */
16 | public class HeaderPositionCalculator {
17 |
18 | private final StickyRecyclerHeadersAdapter mAdapter;
19 | private final OrientationProvider mOrientationProvider;
20 | private final HeaderProvider mHeaderProvider;
21 | private final DimensionCalculator mDimensionCalculator;
22 |
23 | public HeaderPositionCalculator(StickyRecyclerHeadersAdapter adapter, HeaderProvider headerProvider,
24 | OrientationProvider orientationProvider, DimensionCalculator dimensionCalculator) {
25 | mAdapter = adapter;
26 | mHeaderProvider = headerProvider;
27 | mOrientationProvider = orientationProvider;
28 | mDimensionCalculator = dimensionCalculator;
29 | }
30 |
31 | /**
32 | * Determines if an item in the list should have a header that is different than the item in the
33 | * list that immediately precedes it. Items with no headers will always return false.
34 | *
35 | * @param position of the list item in questions
36 | * @return true if this item has a different header than the previous item in the list
37 | * @see {@link StickyRecyclerHeadersAdapter#getHeaderId(int)}
38 | */
39 | public boolean hasNewHeader(int position) {
40 | if (indexOutOfBounds(position)) {
41 | return false;
42 | }
43 |
44 | long headerId = mAdapter.getHeaderId(position);
45 |
46 | if (headerId < 0) {
47 | return false;
48 | }
49 |
50 | return position == 0 || headerId != mAdapter.getHeaderId(position - 1);
51 | }
52 |
53 | private boolean indexOutOfBounds(int position) {
54 | return position < 0 || position >= mAdapter.getItemCount();
55 | }
56 |
57 | public Rect getHeaderBounds(RecyclerView recyclerView, View header, View firstView, boolean firstHeader) {
58 | int orientation = mOrientationProvider.getOrientation(recyclerView);
59 | Rect bounds = getDefaultHeaderOffset(recyclerView, header, firstView, orientation);
60 |
61 | if (firstHeader && isStickyHeaderBeingPushedOffscreen(recyclerView, header)) {
62 | View viewAfterNextHeader = getFirstViewUnobscuredByHeader(recyclerView, header);
63 | int firstViewUnderHeaderPosition = recyclerView.getChildAdapterPosition(viewAfterNextHeader);
64 | View secondHeader = mHeaderProvider.getHeader(recyclerView, firstViewUnderHeaderPosition);
65 | translateHeaderWithNextHeader(recyclerView, mOrientationProvider.getOrientation(recyclerView), bounds,
66 | header, viewAfterNextHeader, secondHeader);
67 | }
68 |
69 | return bounds;
70 | }
71 |
72 | private Rect getDefaultHeaderOffset(RecyclerView recyclerView, View header, View firstView, int orientation) {
73 | int translationX, translationY;
74 | Rect headerMargins = mDimensionCalculator.getMargins(header);
75 | if (orientation == LinearLayoutManager.VERTICAL) {
76 | translationX = firstView.getLeft() + headerMargins.left;
77 | translationY = Math.max(
78 | firstView.getTop() - header.getHeight() - headerMargins.bottom,
79 | getListTop(recyclerView) + headerMargins.top);
80 | } else {
81 | translationY = firstView.getTop() + headerMargins.top;
82 | translationX = Math.max(
83 | firstView.getLeft() - header.getWidth() - headerMargins.right,
84 | getListLeft(recyclerView) + headerMargins.left);
85 | }
86 |
87 | return new Rect(translationX, translationY, translationX + header.getWidth(),
88 | translationY + header.getHeight());
89 | }
90 |
91 | private boolean isStickyHeaderBeingPushedOffscreen(RecyclerView recyclerView, View stickyHeader) {
92 | View viewAfterHeader = getFirstViewUnobscuredByHeader(recyclerView, stickyHeader);
93 | int firstViewUnderHeaderPosition = recyclerView.getChildAdapterPosition(viewAfterHeader);
94 | if (firstViewUnderHeaderPosition == RecyclerView.NO_POSITION) {
95 | return false;
96 | }
97 |
98 | if (firstViewUnderHeaderPosition > 0 && hasNewHeader(firstViewUnderHeaderPosition)) {
99 | View nextHeader = mHeaderProvider.getHeader(recyclerView, firstViewUnderHeaderPosition);
100 | Rect nextHeaderMargins = mDimensionCalculator.getMargins(nextHeader);
101 | Rect headerMargins = mDimensionCalculator.getMargins(stickyHeader);
102 |
103 | if (mOrientationProvider.getOrientation(recyclerView) == LinearLayoutManager.VERTICAL) {
104 | int topOfNextHeader = viewAfterHeader.getTop() - nextHeaderMargins.bottom - nextHeader.getHeight() - nextHeaderMargins.top;
105 | int bottomOfThisHeader = recyclerView.getPaddingTop() + stickyHeader.getBottom() + headerMargins.top + headerMargins.bottom;
106 | if (topOfNextHeader < bottomOfThisHeader) {
107 | return true;
108 | }
109 | } else {
110 | int leftOfNextHeader = viewAfterHeader.getLeft() - nextHeaderMargins.right - nextHeader.getWidth() - nextHeaderMargins.left;
111 | int rightOfThisHeader = recyclerView.getPaddingLeft() + stickyHeader.getRight() + headerMargins.left + headerMargins.right;
112 | if (leftOfNextHeader < rightOfThisHeader) {
113 | return true;
114 | }
115 | }
116 | }
117 |
118 | return false;
119 | }
120 |
121 | private void translateHeaderWithNextHeader(RecyclerView recyclerView, int orientation, Rect translation,
122 | View currentHeader, View viewAfterNextHeader, View nextHeader) {
123 | Rect nextHeaderMargins = mDimensionCalculator.getMargins(nextHeader);
124 | Rect stickyHeaderMargins = mDimensionCalculator.getMargins(currentHeader);
125 | if (orientation == LinearLayoutManager.VERTICAL) {
126 | int topOfStickyHeader = getListTop(recyclerView) + stickyHeaderMargins.top + stickyHeaderMargins.bottom;
127 | int shiftFromNextHeader = viewAfterNextHeader.getTop() - nextHeader.getHeight() - nextHeaderMargins.bottom - nextHeaderMargins.top - currentHeader.getHeight() - topOfStickyHeader;
128 | if (shiftFromNextHeader < topOfStickyHeader) {
129 | translation.top += shiftFromNextHeader;
130 | }
131 | } else {
132 | int leftOfStickyHeader = getListLeft(recyclerView) + stickyHeaderMargins.left + stickyHeaderMargins.right;
133 | int shiftFromNextHeader = viewAfterNextHeader.getLeft() - nextHeader.getWidth() - nextHeaderMargins.right - nextHeaderMargins.left - currentHeader.getWidth() - leftOfStickyHeader;
134 | if (shiftFromNextHeader < leftOfStickyHeader) {
135 | translation.left += shiftFromNextHeader;
136 | }
137 | }
138 | }
139 |
140 | /**
141 | * Returns the first item currently in the RecyclerView that is not obscured by a header.
142 | *
143 | * @param parent Recyclerview containing all the list items
144 | * @return first item that is fully beneath a header
145 | */
146 | private View getFirstViewUnobscuredByHeader(RecyclerView parent, View firstHeader) {
147 | for (int i = 0; i < parent.getChildCount(); i++) {
148 | View child = parent.getChildAt(i);
149 | if (!itemIsObscuredByHeader(parent, child, firstHeader, mOrientationProvider.getOrientation(parent))) {
150 | return child;
151 | }
152 | }
153 | return null;
154 | }
155 |
156 | /**
157 | * Determines if an item is obscured by a header
158 | *
159 | *
160 | * @param parent
161 | * @param item to determine if obscured by header
162 | * @param header that might be obscuring the item
163 | * @param orientation of the {@link RecyclerView}
164 | * @return true if the item view is obscured by the header view
165 | */
166 | private boolean itemIsObscuredByHeader(RecyclerView parent, View item, View header, int orientation) {
167 | RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) item.getLayoutParams();
168 | Rect headerMargins = mDimensionCalculator.getMargins(header);
169 |
170 | int adapterPosition = parent.getChildAdapterPosition(item);
171 | if (adapterPosition == RecyclerView.NO_POSITION || mHeaderProvider.getHeader(parent, adapterPosition) != header) {
172 | // Resolves https://github.com/timehop/sticky-headers-recyclerview/issues/36
173 | // Handles an edge case where a trailing header is smaller than the current sticky header.
174 | return false;
175 | }
176 |
177 | if (orientation == LinearLayoutManager.VERTICAL) {
178 | int itemTop = item.getTop() - layoutParams.topMargin;
179 | int headerBottom = header.getBottom() + headerMargins.bottom + headerMargins.top;
180 | if (itemTop > headerBottom) {
181 | return false;
182 | }
183 | } else {
184 | int itemLeft = item.getLeft() - layoutParams.leftMargin;
185 | int headerRight = header.getRight() + headerMargins.right + headerMargins.left;
186 | if (itemLeft > headerRight) {
187 | return false;
188 | }
189 | }
190 |
191 | return true;
192 | }
193 |
194 | private int getListTop(RecyclerView view) {
195 | if (view.getLayoutManager().getClipToPadding()) {
196 | return view.getPaddingTop();
197 | } else {
198 | return 0;
199 | }
200 | }
201 |
202 | private int getListLeft(RecyclerView view) {
203 | if (view.getLayoutManager().getClipToPadding()) {
204 | return view.getPaddingLeft();
205 | } else {
206 | return 0;
207 | }
208 | }
209 |
210 | }
211 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/DmBaseAdapter.java:
--------------------------------------------------------------------------------
1 | package com.edus.view;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 | import java.util.LinkedList;
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | /**
16 | * wrapp RecyclerView.Adapter
17 | * 1. can add/remove multiple headerView with/without animation
18 | * 2. instead of using Adapter.notifyItem/Range changed , using notifyAdapterItem/Range chagned
19 | * 3. dataList Position is different with adapter position, adapter position contains header view
20 | * 4. constraint : your value type should be between : 0 ~ Integer.MAX_VALUE-100
21 | * @param
22 | * @author yqpan
23 | * @date 2016/1/13.
24 | */
25 | public abstract class DmBaseAdapter extends RecyclerView.Adapter> {
26 | //HEADER view type Integer.MIN_VALUE ~ mMaxHeaderType
27 | //FOOTER view type mMinFooterType ~ Integer.MAX_VALUE
28 | protected static final int VIEW_TYPE_FOOTER = -1;
29 | protected static final int VIEW_TYPE_NORMAL = 0;
30 |
31 | protected Context mContext;
32 | protected LayoutInflater mInflater;
33 | protected List mDataList = new ArrayList<>();
34 |
35 | private View mCustomLoadingView;
36 |
37 | private boolean mEnableLoadingMore;
38 |
39 | private List mHeadViews;
40 | private Map mTypeViewMap;
41 | private Map mViewTypeMap;
42 |
43 | private int mMinHeaderType;
44 | private int mMaxHeaderType;
45 | private int mLastHeaderType;
46 |
47 | private int mLastFooterType;
48 | private int mMinFooterType;
49 | private int mMaxFooterType;
50 |
51 |
52 | public DmBaseAdapter(Context context) {
53 | mContext = context;
54 | mInflater = LayoutInflater.from(mContext);
55 | mHeadViews = new ArrayList<>();
56 | mTypeViewMap = new HashMap<>();
57 | mViewTypeMap = new HashMap<>();
58 |
59 | mMinHeaderType = Integer.MIN_VALUE;
60 | mMaxHeaderType = mMinHeaderType + 100;
61 | mLastHeaderType = mMinHeaderType;
62 |
63 | mMaxFooterType = Integer.MAX_VALUE;
64 | mMinFooterType = mMaxFooterType - 100;
65 | mLastFooterType = mMinFooterType;
66 | }
67 |
68 | public final void addHeaderView(View view){
69 | addHeaderView(view, false);
70 | }
71 |
72 | public final void addHeaderView(View view , boolean hasAnimation){
73 | if(view == null){
74 | throw new RuntimeException("headerView cannot be null");
75 | }
76 | if(!mHeadViews.contains(view)){
77 | mHeadViews.add(view);
78 | mLastHeaderType++;
79 | mTypeViewMap.put(mLastHeaderType,view);
80 | mViewTypeMap.put(view, mLastHeaderType);
81 | if(hasAnimation){
82 | notifyItemInserted(mHeadViews.size() - 1);
83 | }else{
84 | notifyDataSetChanged();
85 | }
86 | }
87 | }
88 |
89 | public final void removeHeaderView(View view){
90 | removeHeaderView(view, false);
91 | }
92 |
93 | public final void removeHeaderView(View view, boolean hasAnimation){
94 | if(mHeadViews.contains(view)){
95 | int index = mHeadViews.indexOf(view);
96 | int viewType = mViewTypeMap.remove(view);
97 | mHeadViews.remove(index);
98 | mTypeViewMap.remove(viewType);
99 | if(hasAnimation){
100 | notifyItemRemoved(index);
101 | }else{
102 | notifyDataSetChanged();
103 | }
104 | }
105 | }
106 |
107 | private int getHeadViewCount(){
108 | return mHeadViews.size();
109 | }
110 |
111 | private boolean isFooterViewType(int viewType) {
112 | return viewType == VIEW_TYPE_FOOTER;
113 | }
114 |
115 | private boolean isHeaderViewType(int viewType){
116 | return viewType >= mMinHeaderType && viewType <= mMaxHeaderType;
117 | }
118 |
119 | public boolean isHeader(int position){
120 | return isHeaderViewType(getItemViewType(position));
121 | }
122 |
123 | public boolean isFooter(int position){
124 | return isFooterViewType(getItemViewType(position));
125 | }
126 |
127 |
128 | public void setDataList(List dataList){
129 | mDataList.clear();
130 | if(dataList != null && !dataList.isEmpty()){
131 | mDataList.addAll(dataList);
132 | }
133 | notifyDataSetChanged();
134 | }
135 |
136 | public List getDataList(){
137 | return mDataList;
138 | }
139 |
140 | /**
141 | * @param dataListPosition position in dataList
142 | * @return
143 | */
144 | public T getAdapterDataItem(int dataListPosition){
145 | if(dataListPosition >= 0 && dataListPosition < mDataList.size()){
146 | return mDataList.get(dataListPosition);
147 | }
148 | return null;
149 | }
150 |
151 | void enableLoadingMore(boolean enable) {
152 | if (mEnableLoadingMore != enable) {
153 | mEnableLoadingMore = enable;
154 | setDataList(new LinkedList(mDataList));
155 | }
156 | }
157 |
158 | public void setCustomLoadingView(View loadingView) {
159 | mCustomLoadingView = loadingView;
160 | notifyDataSetChanged();
161 | }
162 |
163 | public View getCustomLoadingView(){
164 | return mCustomLoadingView;
165 | }
166 |
167 | @Override
168 | public final int getItemCount() {
169 | if (mEnableLoadingMore && mCustomLoadingView != null) {
170 | return getHeadViewCount() + getAdapterItemCount() + 1;
171 | } else {
172 | return getHeadViewCount() + getAdapterItemCount();
173 | }
174 | }
175 |
176 | public int getAdapterItemCount(){
177 | return mDataList.size();
178 | }
179 |
180 | @Override
181 | public final int getItemViewType(int position) {
182 | if(position < getHeadViewCount()){
183 | return mViewTypeMap.get(mHeadViews.get(position));
184 | }else{
185 | if (mEnableLoadingMore && position == getItemCount() - 1 && mCustomLoadingView != null) {
186 | return VIEW_TYPE_FOOTER;
187 | } else {
188 | int adapterItemViewType = getAdapterItemViewType(position - getHeadViewCount());
189 | checkAdapterItemViewTypeValid(adapterItemViewType);
190 | return adapterItemViewType;
191 | }
192 | }
193 | }
194 |
195 | private void checkAdapterItemViewTypeValid(int adapterItemViewType){
196 | if(adapterItemViewType >= 0 && adapterItemViewType <= mMinFooterType ){
197 | return;
198 | }
199 | throw new RuntimeException("adapterItemViewType's value"+adapterItemViewType
200 | +" is not valid : ,valid value is between 0 ~ Integer.MAX_VALUE-100");
201 | }
202 |
203 | /**
204 | * @param dataListPosition position in dataList
205 | * @return
206 | */
207 | public int getAdapterItemViewType(int dataListPosition) {
208 | return VIEW_TYPE_NORMAL;
209 | }
210 |
211 | @Override
212 | public final DmBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
213 | if(isFooterViewType(viewType)){
214 | return onCreateLoadingViewHolder(parent, viewType);
215 | }else if(isHeaderViewType(viewType)){
216 | return onCreateHeaderViewHolder(parent,viewType);
217 | }else{
218 | return onCreateAdapterViewHolder(parent, viewType);
219 | }
220 | }
221 |
222 | private DmBaseViewHolder onCreateHeaderViewHolder(ViewGroup parent, int viewType) {
223 | return new DmBaseViewHolder(mTypeViewMap.get(viewType));
224 | }
225 |
226 | protected DmBaseViewHolder onCreateLoadingViewHolder(ViewGroup parent, int viewType) {
227 | return new DmBaseViewHolder(mCustomLoadingView);
228 | }
229 |
230 | public abstract DmBaseViewHolder onCreateAdapterViewHolder(ViewGroup parent, int viewType);
231 |
232 | @Override
233 | public final void onBindViewHolder(DmBaseViewHolder holder, int position) {
234 | int viewType = getItemViewType(position);
235 | if(isFooterViewType(viewType)){
236 | onBindLoadingViewHolder(holder, position);
237 | }else if(isHeaderViewType(viewType)){
238 | onBindHeaderViewHolder(holder, position);
239 | }else{
240 | onBindAdapterViewHolder(holder, position - getHeadViewCount());
241 | }
242 | }
243 |
244 | private void onBindHeaderViewHolder(DmBaseViewHolder holder, int position) {
245 |
246 | }
247 |
248 | protected void onBindLoadingViewHolder(DmBaseViewHolder holder, int position) {
249 |
250 | }
251 |
252 | public abstract void onBindAdapterViewHolder(DmBaseViewHolder holder, int dataListPosition);
253 |
254 |
255 |
256 | //start wrapper for dataChangedObserver
257 |
258 |
259 | public final void notifyAdapterItemChanged(int position) {
260 | notifyItemRangeChanged(getHeadViewCount() + position, 1);
261 | }
262 |
263 | public final void notifyAdapterItemChanged(int position, Object payload) {
264 | notifyItemRangeChanged(getHeadViewCount() + position, 1, payload);
265 | }
266 |
267 |
268 | public final void notifyAdapterItemRangeChanged(int positionStart, int itemCount) {
269 | notifyItemRangeChanged(getHeadViewCount() + positionStart, itemCount);
270 | }
271 |
272 | public final void notifyAdapterItemRangeChanged(int positionStart, int itemCount, Object payload) {
273 | notifyItemRangeChanged(getHeadViewCount() + positionStart, itemCount, payload);
274 | }
275 |
276 | public final void notifyAdapterItemInserted(int position) {
277 | notifyItemRangeInserted(getHeadViewCount() + position, 1);
278 | }
279 |
280 | public final void notifyAdapterItemMoved(int fromPosition, int toPosition) {
281 | notifyItemMoved(getHeadViewCount() + fromPosition, toPosition);
282 | }
283 |
284 | public final void notifyAdapterItemRangeInserted(int positionStart, int itemCount) {
285 | notifyItemRangeInserted(getHeadViewCount() + positionStart, itemCount);
286 | }
287 |
288 | public final void notifyAdapterItemRemoved(int position) {
289 | notifyItemRangeRemoved(getHeadViewCount() + position, 1);
290 | }
291 |
292 | public final void notifyAdapterItemRangeRemoved(int positionStart, int itemCount) {
293 | notifyItemRangeRemoved(getHeadViewCount() + positionStart, itemCount);
294 | }
295 |
296 | //end wrapper for dataChangedObserver
297 | }
298 |
--------------------------------------------------------------------------------
/app/src/main/java/com/support/android/designlibdemo/Cheeses.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 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 com.support.android.designlibdemo;
18 |
19 | import java.util.Random;
20 |
21 | public class Cheeses {
22 |
23 | private static final Random RANDOM = new Random();
24 |
25 | public static int getRandomCheeseDrawable() {
26 | switch (RANDOM.nextInt(5)) {
27 | default:
28 | case 0:
29 | return R.drawable.cheese_1;
30 | case 1:
31 | return R.drawable.cheese_2;
32 | case 2:
33 | return R.drawable.cheese_3;
34 | case 3:
35 | return R.drawable.cheese_4;
36 | case 4:
37 | return R.drawable.cheese_5;
38 | }
39 | }
40 |
41 | public static final String[] sCheeseStrings = {
42 | "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
43 | "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
44 | "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
45 | "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
46 | "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
47 | "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
48 | "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
49 | "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
50 | "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
51 | "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
52 | "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
53 | "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
54 | "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
55 | "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
56 | "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
57 | "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
58 | "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
59 | "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
60 | "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
61 | "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
62 | "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
63 | "Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
64 | "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
65 | "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
66 | "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
67 | "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
68 | "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
69 | "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
70 | "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
71 | "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
72 | "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
73 | "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
74 | "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
75 | "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
76 | "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
77 | "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
78 | "Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
79 | "Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
80 | "Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
81 | "Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
82 | "Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
83 | "Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
84 | "Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
85 | "Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
86 | "Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
87 | "Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
88 | "Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
89 | "Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
90 | "Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
91 | "Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
92 | "Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
93 | "Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
94 | "Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
95 | "Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
96 | "Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
97 | "Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
98 | "Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
99 | "Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
100 | "Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
101 | "Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
102 | "Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
103 | "Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
104 | "Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
105 | "Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
106 | "Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
107 | "Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
108 | "Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
109 | "La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
110 | "Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
111 | "Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
112 | "Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
113 | "Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
114 | "Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
115 | "Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
116 | "Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
117 | "Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
118 | "Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
119 | "Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
120 | "Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
121 | "Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
122 | "Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
123 | "Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
124 | "Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
125 | "Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
126 | "Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
127 | "Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
128 | "Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
129 | "Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
130 | "Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
131 | "Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
132 | "Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
133 | "Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
134 | "Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
135 | "Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
136 | "Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
137 | "Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
138 | "Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
139 | "Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
140 | "Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
141 | "Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
142 | "Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
143 | "Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
144 | "Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
145 | "Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
146 | "Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
147 | "Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
148 | "Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
149 | "Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
150 | "Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
151 | "Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
152 | "Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
153 | "Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
154 | "Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
155 | "Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
156 | "Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
157 | "Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
158 | "Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
159 | "Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
160 | "Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
161 | "Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
162 | "Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
163 | "Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
164 | "Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
165 | "Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
166 | "Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
167 | "Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
168 | "Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
169 | "Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
170 | "Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
171 | "Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"
172 | };
173 |
174 | }
175 |
--------------------------------------------------------------------------------
/extendablerecyclerview/src/main/java/com/edus/view/DmRecyclerViewWrapper.java:
--------------------------------------------------------------------------------
1 | package com.edus.view;
2 |
3 | import android.content.Context;
4 | import android.support.v4.widget.SwipeRefreshLayout;
5 | import android.support.v7.widget.GridLayoutManager;
6 | import android.support.v7.widget.LinearLayoutManager;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.support.v7.widget.StaggeredGridLayoutManager;
9 | import android.util.AttributeSet;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.widget.FrameLayout;
13 |
14 | import com.dewmobile.dmrecyclerview.R;
15 |
16 |
17 | /**
18 | * 1. implements RecyclerView basic function
19 | * 2. can load more and refresh
20 | * Created by yqpan on 2016/1/13.
21 | */
22 | public class DmRecyclerViewWrapper extends FrameLayout {
23 |
24 | private SwipeRefreshLayout mSrlRefresh;
25 | private RecyclerView mRvRecycler;
26 | private LayoutInflater mInflater;
27 |
28 | private int mScrollbarStyle;
29 |
30 | private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener;
31 | protected int[] mDefaultSwipeToDismissColors = null;
32 |
33 | private static final int SCROLLBARS_NONE = 0;
34 | private static final int SCROLLBARS_VERTICAL = 1;
35 | private static final int SCROLLBARS_HORIZONTAL = 2;
36 |
37 | private boolean mEnableLoadMore;
38 | private boolean mIsFirstSetLoadMore = true;
39 | private OnLoadMoreListener mOnLoadMoreListener;
40 | private RecyclerView.OnScrollListener mOnScrollListener;
41 | protected LAYOUT_MANAGER_TYPE layoutManagerType;
42 |
43 | private int lastVisibleItemPosition;
44 | private int mVisibleItemCount = 0;
45 | private int mTotalItemCount = 0;
46 | private int mPreviousTotal = 0;
47 | private int mFirstVisibleItem;
48 | private boolean mIsLoadingMore = false;
49 | private RecyclerView.AdapterDataObserver mAdapterDataObserver;
50 |
51 | public DmRecyclerViewWrapper(Context context) {
52 | this(context, null);
53 | }
54 |
55 | public DmRecyclerViewWrapper(Context context, AttributeSet attrs) {
56 | this(context, attrs, 0);
57 | }
58 |
59 | public DmRecyclerViewWrapper(Context context, AttributeSet attrs, int defStyleAttr) {
60 | super(context, attrs, defStyleAttr);
61 | initAttr(attrs);
62 | initViews();
63 | }
64 |
65 | private void initAttr(AttributeSet attrs) {
66 | if (attrs != null) {
67 | //1. mScrollbarStyle get it from xml
68 | }
69 | }
70 |
71 | private void initViews() {
72 | mInflater = LayoutInflater.from(getContext());
73 | View rootView = mInflater.inflate(R.layout.dm_recyclerview_wrapper_layout, this, true);
74 | mSrlRefresh = (SwipeRefreshLayout) rootView.findViewById(R.id.srl_refresh);
75 | mRvRecycler = (RecyclerView) rootView.findViewById(R.id.rv_recycler);
76 | setScrollBars();
77 | enableLoadMore(mEnableLoadMore);
78 | enableRefresh(false);
79 | }
80 |
81 | private void setScrollBars() {
82 | mInflater = LayoutInflater.from(getContext());
83 | switch (mScrollbarStyle) {
84 | case SCROLLBARS_VERTICAL:
85 | mSrlRefresh.removeView(mRvRecycler);
86 | View verticalView = mInflater.inflate(R.layout.dm_recyclerview_vertical, mSrlRefresh, true);
87 | mRvRecycler = (RecyclerView) verticalView.findViewById(R.id.rv_recycler);
88 | break;
89 | case SCROLLBARS_HORIZONTAL:
90 | mSrlRefresh.removeView(mRvRecycler);
91 | View horizontalView = mInflater.inflate(R.layout.dm_recyclerview_horizontal, mSrlRefresh, true);
92 | mRvRecycler = (RecyclerView) horizontalView.findViewById(R.id.rv_recycler);
93 | break;
94 | default:
95 | break;
96 | }
97 | }
98 |
99 |
100 | //---------------------recyclerview wrapper----------------
101 |
102 | public void setAdapter(DmBaseAdapter adapter) {
103 | if(getAdapter() != null && mAdapterDataObserver != null){
104 | getAdapter().unregisterAdapterDataObserver(mAdapterDataObserver);
105 | }
106 | mRvRecycler.setAdapter(adapter);
107 | mAdapterDataObserver = newAdapterDataObserver();
108 | adapter.registerAdapterDataObserver(mAdapterDataObserver);
109 | mIsFirstSetLoadMore = true;
110 | enableLoadMore(mEnableLoadMore);
111 | }
112 |
113 | public DmBaseAdapter getAdapter(){
114 | return (DmBaseAdapter) mRvRecycler.getAdapter();
115 | }
116 |
117 | public void setLayoutManager(RecyclerView.LayoutManager layoutManager) {
118 | mRvRecycler.setLayoutManager(layoutManager);
119 | handleLayoutManagerSetted(layoutManager);
120 | }
121 |
122 | private void handleLayoutManagerSetted(RecyclerView.LayoutManager layoutManager) {
123 | if(layoutManager == null){
124 | return;
125 | }
126 | if(layoutManager instanceof GridLayoutManager){//将header和footer作为整行或者整列使用
127 | final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
128 | gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
129 | @Override
130 | public int getSpanSize(int position) {
131 | DmBaseAdapter adapter = getAdapter();
132 | if(adapter != null && ( adapter.isHeader(position) || adapter.isFooter(position))){
133 | return gridLayoutManager.getSpanCount();
134 | }
135 | return 1;
136 | }
137 | });
138 | }
139 | }
140 |
141 | public void setHasFixedSize(boolean hasFixedSize) {
142 | mRvRecycler.setHasFixedSize(hasFixedSize);
143 | }
144 |
145 | public void addItemDecoration(RecyclerView.ItemDecoration itemDecoration){
146 | mRvRecycler.addItemDecoration(itemDecoration);
147 | }
148 |
149 | public void setItemAnimator(RecyclerView.ItemAnimator itemAnimator){
150 | mRvRecycler.setItemAnimator(itemAnimator);
151 | }
152 |
153 | //-------------load more-------
154 | public void enableLoadMore(boolean enable) {
155 | if (mEnableLoadMore != enable || mIsFirstSetLoadMore) {
156 | mEnableLoadMore = enable;
157 | mRvRecycler.removeOnScrollListener(mOnScrollListener);
158 | if(enable){
159 | mOnScrollListener = newOnScrollListener();
160 | mRvRecycler.addOnScrollListener(mOnScrollListener);
161 | }
162 | if(mRvRecycler.getAdapter() != null && mRvRecycler.getAdapter() instanceof DmBaseAdapter){
163 | DmBaseAdapter adapter = (DmBaseAdapter) (mRvRecycler.getAdapter());
164 | if(enable && adapter.getCustomLoadingView() == null){
165 | adapter.setCustomLoadingView(mInflater.inflate(R.layout.dm_recyclerview_bottom_progressbar,this,false));
166 | }
167 | adapter.enableLoadingMore(enable);
168 | }
169 | mIsFirstSetLoadMore = false;
170 | }
171 | }
172 |
173 | public void addOnScrollListener(RecyclerView.OnScrollListener listener){
174 | mRvRecycler.addOnScrollListener(listener);
175 | }
176 |
177 | public void removeOnScrollListener(RecyclerView.OnScrollListener listener){
178 | mRvRecycler.removeOnScrollListener(listener);
179 | }
180 |
181 | private RecyclerView.OnScrollListener newOnScrollListener() {
182 | return new RecyclerView.OnScrollListener() {
183 | private int[] lastPositions;
184 | @Override
185 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
186 | super.onScrolled(recyclerView, dx, dy);
187 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
188 |
189 | if (layoutManagerType == null) {
190 | if (layoutManager instanceof GridLayoutManager) {
191 | layoutManagerType = LAYOUT_MANAGER_TYPE.GRID;
192 | } else if (layoutManager instanceof LinearLayoutManager) {
193 | layoutManagerType = LAYOUT_MANAGER_TYPE.LINEAR;
194 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
195 | layoutManagerType = LAYOUT_MANAGER_TYPE.STAGGERED_GRID;
196 | } else {
197 | throw new RuntimeException("Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager");
198 | }
199 | }
200 |
201 | switch (layoutManagerType) {
202 | case LINEAR:
203 | mVisibleItemCount = layoutManager.getChildCount();
204 | mTotalItemCount = layoutManager.getItemCount();
205 | lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
206 | mFirstVisibleItem = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
207 | break;
208 | case GRID:
209 | lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
210 | mFirstVisibleItem = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
211 | break;
212 | case STAGGERED_GRID:
213 | StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
214 | if (lastPositions == null)
215 | lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];
216 |
217 | staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
218 | lastVisibleItemPosition = findMax(lastPositions);
219 |
220 | staggeredGridLayoutManager.findFirstVisibleItemPositions(lastPositions);
221 | mFirstVisibleItem = findMin(lastPositions);
222 | break;
223 | }
224 |
225 | if (mIsLoadingMore) {
226 | //todo: there are some bugs needs to be adjusted for admob adapter
227 | if (mTotalItemCount > mPreviousTotal) {
228 | mIsLoadingMore = false;
229 | mPreviousTotal = mTotalItemCount;
230 | }
231 | }
232 |
233 | if (!mIsLoadingMore && (mTotalItemCount - mVisibleItemCount) <= mFirstVisibleItem) {
234 | //todo: there are some bugs needs to be adjusted for admob adapter
235 | mOnLoadMoreListener.loadMore(mRvRecycler.getAdapter().getItemCount(), lastVisibleItemPosition);
236 | mIsLoadingMore = true;
237 | mPreviousTotal = mTotalItemCount;
238 | }
239 | }
240 | };
241 | }
242 |
243 | private RecyclerView.AdapterDataObserver newAdapterDataObserver(){
244 | return new RecyclerView.AdapterDataObserver() {
245 | @Override
246 | public void onChanged() {
247 | super.onChanged();
248 | updateData();
249 | }
250 |
251 | @Override
252 | public void onItemRangeChanged(int positionStart, int itemCount) {
253 | super.onItemRangeChanged(positionStart, itemCount);
254 | updateData();
255 | }
256 |
257 | @Override
258 | public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
259 | super.onItemRangeChanged(positionStart, itemCount, payload);
260 | updateData();
261 | }
262 |
263 | @Override
264 | public void onItemRangeInserted(int positionStart, int itemCount) {
265 | super.onItemRangeInserted(positionStart, itemCount);
266 | updateData();
267 | }
268 |
269 | @Override
270 | public void onItemRangeRemoved(int positionStart, int itemCount) {
271 | super.onItemRangeRemoved(positionStart, itemCount);
272 | updateData();
273 | }
274 |
275 | @Override
276 | public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
277 | super.onItemRangeMoved(fromPosition, toPosition, itemCount);
278 | updateData();
279 | }
280 |
281 | private void updateData(){
282 | mIsLoadingMore = false;
283 | }
284 | };
285 | }
286 |
287 | private int findMax(int[] lastPositions) {
288 | int max = Integer.MIN_VALUE;
289 | for (int value : lastPositions) {
290 | if (value > max)
291 | max = value;
292 | }
293 | return max;
294 | }
295 |
296 | private int findMin(int[] lastPositions) {
297 | int min = Integer.MAX_VALUE;
298 | for (int value : lastPositions) {
299 | if (value != RecyclerView.NO_POSITION && value < min)
300 | min = value;
301 | }
302 | return min;
303 | }
304 |
305 | public void setOnLoadMoreListener(OnLoadMoreListener listener) {
306 | mOnLoadMoreListener = listener;
307 | }
308 |
309 | public interface OnLoadMoreListener {
310 | void loadMore(int itemsCount, final int maxLastVisiblePosition);
311 | }
312 |
313 | //------------refresh--------
314 | public void setDefaultSwipeToDismissColors(int... colors) {
315 | if (colors != null && colors.length > 0) {
316 | mSrlRefresh.setColorSchemeColors(mDefaultSwipeToDismissColors);
317 | } else if (mDefaultSwipeToDismissColors != null && mDefaultSwipeToDismissColors.length > 0) {
318 | mSrlRefresh.setColorSchemeColors(mDefaultSwipeToDismissColors);
319 | } else {
320 | //#ff00ddff
321 | //#ff99cc00
322 | //#ffffbb33
323 | //#ffff4444
324 | mSrlRefresh.setColorSchemeResources(
325 | android.R.color.holo_blue_bright,
326 | android.R.color.holo_green_light,
327 | android.R.color.holo_orange_light,
328 | android.R.color.holo_red_light);
329 |
330 | }
331 | }
332 |
333 |
334 | public void enableRefresh(boolean enable) {
335 | if (enable != mSrlRefresh.isEnabled()) {
336 | mSrlRefresh.setEnabled(enable);
337 | if (!enable) mSrlRefresh.setRefreshing(false);
338 | }
339 | }
340 |
341 | public void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener) {
342 | mOnRefreshListener = listener;
343 | setDefaultSwipeToDismissColors(mDefaultSwipeToDismissColors);
344 |
345 | mSrlRefresh.setOnRefreshListener(listener);
346 |
347 | }
348 |
349 | public void setRefreshing(boolean refreshing) {
350 | if(mSrlRefresh != null){
351 | mSrlRefresh.setRefreshing(refreshing);
352 | }
353 | }
354 |
355 | public static enum LAYOUT_MANAGER_TYPE {
356 | LINEAR,
357 | GRID,
358 | STAGGERED_GRID
359 | }
360 |
361 |
362 | }
363 |
--------------------------------------------------------------------------------