├── MultiTypeAdapterSample
├── app
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ ├── dimens.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── drawable-xxhdpi
│ │ │ │ │ ├── ic_obama.png
│ │ │ │ │ ├── ic_djtrump.png
│ │ │ │ │ ├── ic_dlputin.png
│ │ │ │ │ └── ic_xidada.png
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable
│ │ │ │ │ ├── x_bg.xml
│ │ │ │ │ ├── x_btn_bg.xml
│ │ │ │ │ └── x_border.xml
│ │ │ │ ├── values-w820dp
│ │ │ │ │ └── dimens.xml
│ │ │ │ └── layout
│ │ │ │ │ ├── activity_main.xml
│ │ │ │ │ ├── item_header.xml
│ │ │ │ │ ├── item_empty.xml
│ │ │ │ │ ├── item_error.xml
│ │ │ │ │ ├── item_text.xml
│ │ │ │ │ ├── item_image.xml
│ │ │ │ │ ├── include_actions.xml
│ │ │ │ │ ├── item_follower.xml
│ │ │ │ │ └── item_footer.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── baurine
│ │ │ │ │ └── multitypeadaptersample
│ │ │ │ │ ├── activity
│ │ │ │ │ ├── RefreshingView.java
│ │ │ │ │ └── MainActivity.java
│ │ │ │ │ ├── item
│ │ │ │ │ ├── HeaderItem.java
│ │ │ │ │ ├── ErrorItem.java
│ │ │ │ │ ├── EmptyItem.java
│ │ │ │ │ ├── BaseItem.java
│ │ │ │ │ ├── FooterItem.java
│ │ │ │ │ ├── FollowerItem.java
│ │ │ │ │ ├── ImageItem.java
│ │ │ │ │ └── TextItem.java
│ │ │ │ │ ├── util
│ │ │ │ │ ├── DateFormatUtil.java
│ │ │ │ │ ├── CommonUtil.java
│ │ │ │ │ └── BindingUtil.java
│ │ │ │ │ ├── model
│ │ │ │ │ ├── ModelFaker.java
│ │ │ │ │ ├── BaseModel.java
│ │ │ │ │ ├── ImageModel.java
│ │ │ │ │ ├── FollowerModel.java
│ │ │ │ │ └── TextModel.java
│ │ │ │ │ └── presenter
│ │ │ │ │ └── MainPresenter.java
│ │ │ └── AndroidManifest.xml
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── baurine
│ │ │ │ └── multitypeadaptersample
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── baurine
│ │ │ └── multitypeadaptersample
│ │ │ └── ExampleInstrumentedTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
├── multitypeadapter
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ └── values
│ │ │ │ │ └── strings.xml
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── baurine
│ │ │ │ └── multitypeadapter
│ │ │ │ └── MultiTypeAdapter.java
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── baurine
│ │ │ │ └── multitypeadapter
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── baurine
│ │ │ └── multitypeadapter
│ │ │ └── ExampleInstrumentedTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
├── settings.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── .gitignore
├── build.gradle
├── gradle.properties
├── gradlew.bat
└── gradlew
├── MultiTypeAdapterTutorial
├── app
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ ├── dimens.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable
│ │ │ │ │ ├── x_bg.xml
│ │ │ │ │ ├── x_btn_bg.xml
│ │ │ │ │ └── x_border.xml
│ │ │ │ ├── values-w820dp
│ │ │ │ │ └── dimens.xml
│ │ │ │ └── layout
│ │ │ │ │ ├── activity_main.xml
│ │ │ │ │ ├── item_header.xml
│ │ │ │ │ ├── item_text.xml
│ │ │ │ │ ├── item_image.xml
│ │ │ │ │ ├── item_empty.xml
│ │ │ │ │ ├── item_error.xml
│ │ │ │ │ ├── include_actions.xml
│ │ │ │ │ └── item_footer.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── baurine
│ │ │ │ │ └── multitypeadaptertutorial
│ │ │ │ │ ├── activity
│ │ │ │ │ ├── RefreshingView.java
│ │ │ │ │ └── MainActivity.java
│ │ │ │ │ ├── item
│ │ │ │ │ ├── HeaderItem.java
│ │ │ │ │ ├── ErrorItem.java
│ │ │ │ │ ├── EmptyItem.java
│ │ │ │ │ ├── BaseItem.java
│ │ │ │ │ ├── FooterItem.java
│ │ │ │ │ ├── TextItem.java
│ │ │ │ │ └── ImageItem.java
│ │ │ │ │ ├── model
│ │ │ │ │ ├── ModelFaker.java
│ │ │ │ │ ├── BaseModel.java
│ │ │ │ │ ├── TextModel.java
│ │ │ │ │ └── ImageModel.java
│ │ │ │ │ ├── util
│ │ │ │ │ └── BindingUtil.java
│ │ │ │ │ └── presenter
│ │ │ │ │ └── MainPresenter.java
│ │ │ └── AndroidManifest.xml
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── baurine
│ │ │ │ └── multitypeadaptertutorial
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── baurine
│ │ │ └── multitypeadaptertutorial
│ │ │ └── ExampleInstrumentedTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
├── multitypeadapter
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ └── values
│ │ │ │ │ └── strings.xml
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── baurine
│ │ │ │ └── multitypeadapter
│ │ │ │ └── MultiTypeAdapter.java
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── baurine
│ │ │ │ └── multitypeadapter
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── baurine
│ │ │ └── multitypeadapter
│ │ │ └── ExampleInstrumentedTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
├── settings.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── .gitignore
├── build.gradle
├── gradle.properties
├── gradlew.bat
└── gradlew
├── note
├── tutorial_art
│ ├── tutorial_step_5.png
│ ├── tutorial_step_8.png
│ ├── tutorial_step_10_1.gif
│ ├── tutorial_step_11_1.gif
│ ├── tutorial_step_9_1.gif
│ ├── tutorial_step_final.png
│ ├── tutorial_step_6_refresh_1.gif
│ ├── tutorial_step_6_refresh_2.gif
│ ├── tutorial_step_7_loadmore_1.gif
│ └── tutorial_step_7_loadmore_2.gif
├── sample_art
│ ├── multi_type_adapter_1.gif
│ ├── multi_type_adapter_2.gif
│ └── multi_type_adapter_3.gif
└── multi-type-adapter-tutorial-1.md
└── README.md
/MultiTypeAdapterSample/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/multitypeadapter/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/multitypeadapter/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':multitypeadapter'
2 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':multitypeadapter'
2 |
--------------------------------------------------------------------------------
/note/tutorial_art/tutorial_step_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/tutorial_art/tutorial_step_5.png
--------------------------------------------------------------------------------
/note/tutorial_art/tutorial_step_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/tutorial_art/tutorial_step_8.png
--------------------------------------------------------------------------------
/note/sample_art/multi_type_adapter_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/sample_art/multi_type_adapter_1.gif
--------------------------------------------------------------------------------
/note/sample_art/multi_type_adapter_2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/sample_art/multi_type_adapter_2.gif
--------------------------------------------------------------------------------
/note/sample_art/multi_type_adapter_3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/sample_art/multi_type_adapter_3.gif
--------------------------------------------------------------------------------
/note/tutorial_art/tutorial_step_10_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/tutorial_art/tutorial_step_10_1.gif
--------------------------------------------------------------------------------
/note/tutorial_art/tutorial_step_11_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/tutorial_art/tutorial_step_11_1.gif
--------------------------------------------------------------------------------
/note/tutorial_art/tutorial_step_9_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/tutorial_art/tutorial_step_9_1.gif
--------------------------------------------------------------------------------
/note/tutorial_art/tutorial_step_final.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/tutorial_art/tutorial_step_final.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MultiTypeAdapterSample
3 |
4 |
--------------------------------------------------------------------------------
/note/tutorial_art/tutorial_step_6_refresh_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/tutorial_art/tutorial_step_6_refresh_1.gif
--------------------------------------------------------------------------------
/note/tutorial_art/tutorial_step_6_refresh_2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/tutorial_art/tutorial_step_6_refresh_2.gif
--------------------------------------------------------------------------------
/note/tutorial_art/tutorial_step_7_loadmore_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/tutorial_art/tutorial_step_7_loadmore_1.gif
--------------------------------------------------------------------------------
/note/tutorial_art/tutorial_step_7_loadmore_2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/note/tutorial_art/tutorial_step_7_loadmore_2.gif
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/multitypeadapter/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MultiTypeAdapter
3 |
4 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MultiTypeAdapter Tutorial
3 |
4 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/multitypeadapter/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MultiTypeAdapter
3 |
4 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterTutorial/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/drawable-xxhdpi/ic_obama.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/app/src/main/res/drawable-xxhdpi/ic_obama.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/drawable-xxhdpi/ic_djtrump.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/app/src/main/res/drawable-xxhdpi/ic_djtrump.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/drawable-xxhdpi/ic_dlputin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/app/src/main/res/drawable-xxhdpi/ic_dlputin.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/drawable-xxhdpi/ic_xidada.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/app/src/main/res/drawable-xxhdpi/ic_xidada.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterSample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterTutorial/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterTutorial/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterTutorial/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterTutorial/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterTutorial/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baurine/multi-type-adapter/HEAD/MultiTypeAdapterTutorial/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .idea
5 | #/.idea/workspace.xml
6 | #/.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .idea
5 | #/.idea/workspace.xml
6 | #/.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/drawable/x_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/drawable/x_btn_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/drawable/x_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/drawable/x_btn_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/activity/RefreshingView.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.activity;
2 |
3 | /**
4 | * Created by baurine on 1/16/17.
5 | */
6 |
7 | public interface RefreshingView {
8 | void setRefreshing(boolean refreshing);
9 | }
10 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/activity/RefreshingView.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.activity;
2 |
3 | /**
4 | * Created by baurine on 1/12/17.
5 | */
6 |
7 | // it should move to `iview` folder
8 | public interface RefreshingView {
9 | void setRefreshing(boolean refreshing);
10 | }
11 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/drawable/x_border.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/drawable/x_border.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/multitypeadapter/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/multitypeadapter/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/item/HeaderItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.item;
2 |
3 | import com.baurine.multitypeadaptersample.R;
4 |
5 | /**
6 | * Created by baurine on 1/10/17.
7 | */
8 |
9 | public class HeaderItem extends BaseItem {
10 | @Override
11 | public int getLayout() {
12 | return R.layout.item_header;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/item/HeaderItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.item;
2 |
3 | import com.baurine.multitypeadaptertutorial.R;
4 |
5 | /**
6 | * Created by baurine on 1/14/17.
7 | */
8 |
9 | public class HeaderItem extends BaseItem {
10 | @Override
11 | public int getLayout() {
12 | return R.layout.item_header;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/util/DateFormatUtil.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.util;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 |
6 | public class DateFormatUtil {
7 |
8 | private static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
9 |
10 | public static String formatTime(Date date) {
11 | return sdf.format(date);
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/test/java/com/baurine/multitypeadaptersample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/multitypeadapter/src/test/java/com/baurine/multitypeadapter/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadapter;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/model/ModelFaker.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.model;
2 |
3 | import java.util.Random;
4 |
5 | /**
6 | * Created by baurine on 1/16/17.
7 | */
8 |
9 | public class ModelFaker {
10 | public static BaseModel fake() {
11 | String type = new Random().nextBoolean() ? "image" : "text";
12 | if (type.equals("image")) {
13 | return new ImageModel();
14 | } else {
15 | return new TextModel();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/multitypeadapter/src/test/java/com/baurine/multitypeadapter/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadapter;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/test/java/com/baurine/multitypeadaptertutorial/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/util/CommonUtil.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.util;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.widget.Toast;
6 |
7 | public class CommonUtil {
8 |
9 | public static int dpToPx(int dp) {
10 | return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
11 | }
12 |
13 | public static void showToast(Context cxt, String content) {
14 | Toast.makeText(cxt, content, Toast.LENGTH_SHORT).show();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/model/ModelFaker.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.model;
2 |
3 | import java.util.Random;
4 |
5 | /**
6 | * Created by baurine on 1/11/17.
7 | */
8 |
9 | public class ModelFaker {
10 | public static BaseModel fake() {
11 | int type = new Random().nextInt() % 3;
12 | if (type == 0) {
13 | return new ImageModel();
14 | } else if (type == 1) {
15 | return new TextModel();
16 | } else {
17 | return new FollowerModel();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | }
20 | }
21 |
22 | task clean(type: Delete) {
23 | delete rootProject.buildDir
24 | }
25 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/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 /Users/baurine/Developments/android-sdk-macosx/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 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/item/ErrorItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.item;
2 |
3 | import com.baurine.multitypeadaptersample.R;
4 |
5 | /**
6 | * Created by baurine on 1/10/17.
7 | */
8 |
9 | public class ErrorItem extends BaseItem {
10 | @Override
11 | public int getLayout() {
12 | return R.layout.item_error;
13 | }
14 |
15 | /////////////////////////////////////////////////
16 | public ErrorItem() {
17 | content = "Error happened! please try it later!";
18 | }
19 |
20 | /////////////////////////////////////////////////
21 | // data part
22 | private String content;
23 |
24 | public String getContent() {
25 | return content;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/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 /Users/baurine/Developments/android-sdk-macosx/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 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/item/EmptyItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.item;
2 |
3 | import com.baurine.multitypeadaptersample.R;
4 |
5 | /**
6 | * Created by baurine on 1/10/17.
7 | */
8 |
9 | public class EmptyItem extends BaseItem {
10 | @Override
11 | public int getLayout() {
12 | return R.layout.item_empty;
13 | }
14 |
15 | /////////////////////////////////////////////////
16 | public EmptyItem() {
17 | content = "Currently has no items, please refresh it later!";
18 | }
19 |
20 | /////////////////////////////////////////////////
21 | // data part
22 | private String content;
23 |
24 | public String getContent() {
25 | return content;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/multitypeadapter/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 /Users/baurine/Developments/android-sdk-macosx/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 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/item/ErrorItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.item;
2 |
3 |
4 | import com.baurine.multitypeadaptertutorial.R;
5 |
6 | /**
7 | * Created by baurine on 1/10/17.
8 | */
9 |
10 | public class ErrorItem extends BaseItem {
11 | @Override
12 | public int getLayout() {
13 | return R.layout.item_error;
14 | }
15 |
16 | /////////////////////////////////////////////////
17 | public ErrorItem() {
18 | content = "Error happened! please try it later!";
19 | }
20 |
21 | /////////////////////////////////////////////////
22 | // data part
23 | private String content;
24 |
25 | public String getContent() {
26 | return content;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/multitypeadapter/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 /Users/baurine/Developments/android-sdk-macosx/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 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/item/EmptyItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.item;
2 |
3 | import com.baurine.multitypeadaptertutorial.R;
4 |
5 | /**
6 | * Created by baurine on 1/10/17.
7 | */
8 |
9 | public class EmptyItem extends BaseItem {
10 | @Override
11 | public int getLayout() {
12 | return R.layout.item_empty;
13 | }
14 |
15 | /////////////////////////////////////////////////
16 | public EmptyItem() {
17 | content = "Currently has no items, please refresh it later!";
18 | }
19 |
20 | /////////////////////////////////////////////////
21 | // data part
22 | private final String content;
23 |
24 | public String getContent() {
25 | return content;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/model/BaseModel.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.model;
2 |
3 | import com.baurine.multitypeadapter.MultiTypeAdapter;
4 |
5 | import java.util.Date;
6 | import java.util.Random;
7 |
8 | /**
9 | * Created by baurine on 1/11/17.
10 | */
11 |
12 | public class BaseModel {
13 |
14 | public MultiTypeAdapter.IItem createItem(MultiTypeAdapter adapter) {
15 | return null;
16 | }
17 |
18 | /////////////////////////////////////////////////////////////////////
19 | public final int id;
20 | public final Date createdAt;
21 | public final Date updatedAt;
22 |
23 | public BaseModel() {
24 | id = (new Random()).nextInt(10000);
25 | createdAt = new Date();
26 | updatedAt = new Date();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/util/BindingUtil.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.util;
2 |
3 | import android.databinding.BindingAdapter;
4 | import android.graphics.drawable.Drawable;
5 | import android.widget.ImageView;
6 |
7 | import com.bumptech.glide.Glide;
8 |
9 | public class BindingUtil {
10 | @BindingAdapter({"imageUrl", "error", "placeholder"})
11 | public static void loadImage(ImageView imgView,
12 | String url,
13 | Drawable error,
14 | Drawable placeholder) {
15 | Glide.with(imgView.getContext())
16 | .load(url)
17 | .error(error)
18 | .placeholder(placeholder)
19 | .into(imgView);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/model/BaseModel.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.model;
2 |
3 | import com.baurine.multitypeadapter.MultiTypeAdapter;
4 | import com.baurine.multitypeadaptertutorial.item.BaseItem;
5 |
6 | import java.util.Date;
7 | import java.util.Random;
8 |
9 | /**
10 | * Created by baurine on 1/11/17.
11 | */
12 |
13 | public class BaseModel {
14 | public BaseItem createItem(MultiTypeAdapter adapter) {
15 | return null;
16 | }
17 |
18 | ////////////////////////////////////////////////////////
19 | public int id;
20 | public Date createdAt;
21 | public Date updatedAt;
22 |
23 | public BaseModel() {
24 | id = (new Random()).nextInt(10000);
25 | createdAt = new Date();
26 | updatedAt = new Date();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/model/ImageModel.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.model;
2 |
3 | import com.baurine.multitypeadapter.MultiTypeAdapter;
4 | import com.baurine.multitypeadaptersample.item.ImageItem;
5 |
6 | import java.util.Random;
7 |
8 | /**
9 | * Created by baurine on 1/11/17.
10 | */
11 |
12 | public class ImageModel extends BaseModel {
13 | @Override
14 | public MultiTypeAdapter.IItem createItem(MultiTypeAdapter adapter) {
15 | return new ImageItem(this, adapter);
16 | }
17 |
18 | ////////////////////////////////////////
19 | public final String url;
20 | public boolean liked;
21 |
22 | public ImageModel() {
23 | super();
24 | url = "https://unsplash.it/200/200?random&" + new Random().nextInt(40);
25 | liked = (new Random()).nextBoolean();
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/item/BaseItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.item;
2 |
3 | import android.view.View;
4 |
5 | import com.baurine.multitypeadapter.MultiTypeAdapter;
6 | import com.baurine.multitypeadaptersample.BR;
7 |
8 | /**
9 | * Created by baurine on 1/10/17.
10 | */
11 |
12 | public abstract class BaseItem implements MultiTypeAdapter.IItem {
13 | @Override
14 | public int getVariableId() {
15 | return BR.item;
16 | }
17 |
18 | ////////////////////////////////////////////
19 | // handle event
20 | private View.OnClickListener onClickListener;
21 |
22 | public View.OnClickListener getOnClickListener() {
23 | return onClickListener;
24 | }
25 |
26 | public void setOnClickListener(View.OnClickListener onClickListener) {
27 | this.onClickListener = onClickListener;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/item/BaseItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.item;
2 |
3 | import android.view.View;
4 |
5 | import com.android.databinding.library.baseAdapters.BR;
6 | import com.baurine.multitypeadapter.MultiTypeAdapter;
7 |
8 | /**
9 | * Created by baurine on 1/10/17.
10 | */
11 |
12 | public abstract class BaseItem implements MultiTypeAdapter.IItem {
13 | @Override
14 | public int getVariableId() {
15 | return BR.item;
16 | }
17 |
18 | ////////////////////////////////////////////
19 | // handle event
20 | private View.OnClickListener onClickListener;
21 |
22 | public View.OnClickListener getOnClickListener() {
23 | return onClickListener;
24 | }
25 |
26 | public void setOnClickListener(View.OnClickListener onClickListener) {
27 | this.onClickListener = onClickListener;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/model/TextModel.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.model;
2 |
3 | import com.baurine.multitypeadapter.MultiTypeAdapter;
4 | import com.baurine.multitypeadaptertutorial.item.BaseItem;
5 | import com.baurine.multitypeadaptertutorial.item.TextItem;
6 |
7 | import java.util.Date;
8 | import java.util.Random;
9 |
10 | /**
11 | * Created by baurine on 1/16/17.
12 | */
13 |
14 | public class TextModel extends BaseModel {
15 | @Override
16 | public BaseItem createItem(MultiTypeAdapter adapter) {
17 | return new TextItem(adapter, this);
18 | }
19 |
20 | ////////////////////////////////////////////////////
21 | public String content;
22 | public boolean liked;
23 |
24 | public TextModel() {
25 | super();
26 | content = new Date().toString();
27 | liked = new Random().nextBoolean();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/model/ImageModel.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.model;
2 |
3 | import com.baurine.multitypeadapter.MultiTypeAdapter;
4 | import com.baurine.multitypeadaptertutorial.item.BaseItem;
5 | import com.baurine.multitypeadaptertutorial.item.ImageItem;
6 |
7 | import java.util.Random;
8 |
9 | /**
10 | * Created by baurine on 1/16/17.
11 | */
12 |
13 | public class ImageModel extends BaseModel {
14 | @Override
15 | public BaseItem createItem(MultiTypeAdapter adapter) {
16 | return new ImageItem(adapter, this);
17 | }
18 |
19 | ////////////////////////////////////////////////////
20 | public String url;
21 | public boolean liked;
22 |
23 | public ImageModel() {
24 | super();
25 | url = "https://unsplash.it/200/200?random&" + new Random().nextInt(40);
26 | liked = new Random().nextBoolean();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/androidTest/java/com/baurine/multitypeadaptersample/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.baurine.multitypeadaptersample", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/multitypeadapter/src/androidTest/java/com/baurine/multitypeadapter/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadapter;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.baurine.multitypeadapter.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/multitypeadapter/src/androidTest/java/com/baurine/multitypeadapter/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadapter;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.baurine.multitypeadapter.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/androidTest/java/com/baurine/multitypeadaptertutorial/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.baurine.multitypeadaptertutorial", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/layout/item_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
20 |
21 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/layout/item_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
20 |
21 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/layout/item_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
19 |
20 |
24 |
25 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/multitypeadapter/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "24.0.1"
6 |
7 | defaultConfig {
8 | minSdkVersion 16
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | dataBinding {
23 | enabled = true
24 | }
25 | }
26 |
27 | dependencies {
28 | compile fileTree(dir: 'libs', include: ['*.jar'])
29 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
30 | exclude group: 'com.android.support', module: 'support-annotations'
31 | })
32 | compile 'com.android.support:appcompat-v7:25.1.0'
33 | compile 'com.android.support:recyclerview-v7:25.1.0'
34 | testCompile 'junit:junit:4.12'
35 | }
36 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/util/BindingUtil.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.util;
2 |
3 | import android.databinding.BindingAdapter;
4 | import android.graphics.drawable.Drawable;
5 | import android.view.View;
6 | import android.widget.ImageView;
7 |
8 | import com.bumptech.glide.Glide;
9 |
10 | public class BindingUtil {
11 | @BindingAdapter({"imageUrl", "error", "placeholder"})
12 | public static void loadImage(ImageView imgView,
13 | String url,
14 | Drawable error,
15 | Drawable placeholder) {
16 | Glide.with(imgView.getContext())
17 | .load(url)
18 | .error(error)
19 | .placeholder(placeholder)
20 | .into(imgView);
21 | }
22 |
23 | @BindingAdapter("android:paddingVertical")
24 | public static void setPaddingVertical(View view, int paddingVertical) {
25 | int px = CommonUtil.dpToPx(paddingVertical);
26 | view.setPadding(view.getPaddingLeft(), px, view.getPaddingRight(), px);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/item/FooterItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.item;
2 |
3 | import com.baurine.multitypeadaptersample.R;
4 |
5 | /**
6 | * Created by baurine on 1/10/17.
7 | */
8 |
9 | public class FooterItem extends BaseItem {
10 | @Override
11 | public int getLayout() {
12 | return R.layout.item_footer;
13 | }
14 |
15 | ///////////////////////////////////////////////
16 | public FooterItem setState(int state) {
17 | this.state = state;
18 | return this;
19 | }
20 |
21 | ///////////////////////////////////////////////
22 | // data part
23 | // FooterItem has 3 states: Loading, Error, NoMore
24 | public final static int LOADING = 0;
25 | public final static int ERROR = 1;
26 | public final static int NO_MORE = 2;
27 | private int state = LOADING;
28 |
29 | public boolean isLoading() {
30 | return state == LOADING;
31 | }
32 |
33 | public boolean isError() {
34 | return state == ERROR;
35 | }
36 |
37 | public boolean isNoMore() {
38 | return state == NO_MORE;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/layout/item_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
18 |
19 |
26 |
27 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/item/FooterItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.item;
2 |
3 |
4 | import com.baurine.multitypeadaptertutorial.R;
5 |
6 | /**
7 | * Created by baurine on 1/10/17.
8 | */
9 |
10 | public class FooterItem extends BaseItem {
11 | @Override
12 | public int getLayout() {
13 | return R.layout.item_footer;
14 | }
15 |
16 | ///////////////////////////////////////////////
17 | public FooterItem setState(int state) {
18 | this.state = state;
19 | return this;
20 | }
21 |
22 | ///////////////////////////////////////////////
23 | // data part
24 | // FooterItem has 3 states: Loading, Error, NoMore
25 | public final static int LOADING = 0;
26 | public final static int ERROR = 1;
27 | public final static int NO_MORE = 2;
28 | private int state = LOADING;
29 |
30 | public boolean isLoading() {
31 | return state == LOADING;
32 | }
33 |
34 | public boolean isError() {
35 | return state == ERROR;
36 | }
37 |
38 | public boolean isNoMore() {
39 | return state == NO_MORE;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/multitypeadapter/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | group='com.github.baurine'
5 |
6 | android {
7 | compileSdkVersion 25
8 | buildToolsVersion "24.0.1"
9 |
10 | defaultConfig {
11 | minSdkVersion 16
12 | targetSdkVersion 25
13 | versionCode 10006
14 | versionName "1.0.6"
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | dataBinding {
24 | enabled = true
25 | }
26 | }
27 |
28 | dependencies {
29 | compile fileTree(dir: 'libs', include: ['*.jar'])
30 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
31 | exclude group: 'com.android.support', module: 'support-annotations'
32 | })
33 | compile 'com.android.support:appcompat-v7:25.1.0'
34 | compile 'com.android.support:recyclerview-v7:25.1.0'
35 | testCompile 'junit:junit:4.12'
36 | }
37 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "24.0.1"
6 | defaultConfig {
7 | applicationId "com.baurine.multitypeadaptertutorial"
8 | minSdkVersion 16
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | dataBinding {
21 | enabled = true
22 | }
23 | }
24 |
25 | dependencies {
26 | compile fileTree(dir: 'libs', include: ['*.jar'])
27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
28 | exclude group: 'com.android.support', module: 'support-annotations'
29 | })
30 | compile 'com.android.support:appcompat-v7:25.1.0'
31 | compile 'com.android.support:recyclerview-v7:25.1.0'
32 | compile 'com.github.bumptech.glide:glide:3.7.0'
33 | testCompile 'junit:junit:4.12'
34 | compile project(path: ':multitypeadapter')
35 | }
36 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "24.0.1"
6 | defaultConfig {
7 | applicationId "com.baurine.multitypeadaptersample"
8 | minSdkVersion 16
9 | targetSdkVersion 25
10 | versionCode 10006
11 | versionName "1.0.6"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | dataBinding {
21 | enabled = true
22 | }
23 | }
24 |
25 | dependencies {
26 | compile fileTree(dir: 'libs', include: ['*.jar'])
27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
28 | exclude group: 'com.android.support', module: 'support-annotations'
29 | })
30 | compile project(':multitypeadapter')
31 | compile 'com.android.support:appcompat-v7:25.1.0'
32 | compile 'com.android.support:recyclerview-v7:25.1.0'
33 | compile 'com.android.support:cardview-v7:25.1.0'
34 | compile 'com.github.bumptech.glide:glide:3.7.0'
35 | testCompile 'junit:junit:4.12'
36 | }
37 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/layout/item_empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
21 |
22 |
26 |
27 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/layout/item_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
21 |
22 |
26 |
27 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/layout/item_empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
21 |
22 |
26 |
27 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/layout/item_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
21 |
22 |
26 |
27 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/model/FollowerModel.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.model;
2 |
3 | import com.baurine.multitypeadapter.MultiTypeAdapter;
4 | import com.baurine.multitypeadaptersample.R;
5 | import com.baurine.multitypeadaptersample.item.FollowerItem;
6 |
7 | import java.util.Random;
8 |
9 | /**
10 | * Created by baurine on 1/11/17.
11 | */
12 |
13 | public class FollowerModel extends BaseModel {
14 | @Override
15 | public MultiTypeAdapter.IItem createItem(MultiTypeAdapter adapter) {
16 | return new FollowerItem(this, adapter);
17 | }
18 |
19 | ///////////////////////////////////////
20 | private static final String[] FOLLOWERS = new String[]{
21 | "习大大", "奥巴马", "川普", "普京"
22 | };
23 | private static final int[] AVATARS = new int[]{
24 | R.drawable.ic_xidada,
25 | R.drawable.ic_obama,
26 | R.drawable.ic_djtrump,
27 | R.drawable.ic_dlputin
28 | };
29 |
30 | ////////////////////////////////////////
31 | public final String follower;
32 | public final int avatarResId;
33 | public boolean followed;
34 |
35 | public FollowerModel() {
36 | super();
37 | int index = new Random().nextInt(100) % 4;
38 | follower = FOLLOWERS[index];
39 | avatarResId = AVATARS[index];
40 | followed = new Random().nextBoolean();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/model/TextModel.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.model;
2 |
3 | import com.baurine.multitypeadapter.MultiTypeAdapter;
4 | import com.baurine.multitypeadaptersample.item.TextItem;
5 |
6 | import java.util.Random;
7 |
8 | /**
9 | * Created by baurine on 1/11/17.
10 | */
11 |
12 | public class TextModel extends BaseModel {
13 | @Override
14 | public MultiTypeAdapter.IItem createItem(MultiTypeAdapter adapter) {
15 | return new TextItem(this, adapter);
16 | }
17 |
18 | ///////////////////////////////////////
19 | // copy from: http://www.guancha.cn/life/2016_11_28_382164.shtml
20 | private static final String[] TOXIC_SOUP = new String[]{
21 | "你必须非常努力,才能相信自己真的是无能无力",
22 | "能用钱解决的问题,我一件都解决不了",
23 | "不是因为看到希望了才去坚持,而是坚持了才知道没有希望",
24 | "那些曾经把我打倒的人,谢谢你们,躺着真舒服",
25 | "人就要趁年轻的时候多出去走走,看看不同的风景,不同的文化,等转遍了世界你就会发现原来....躺在被窝里是真他妈舒服!",
26 | "人生就是一个起落落落落落落...的过程",
27 | "生活不止眼前的苟且,还有明天和后天苟且",
28 | "一觉醒来,是不是感觉离梦想又远了呢",
29 | "一路上有你,苦一点也愿意,苦很多就算了",
30 | "旅行不必在乎目的地,在乎的是沿途的风景,因为就你那点钱也就只够买个往返的火车硬座票",
31 | };
32 |
33 | ////////////////////////////////////////
34 | public final String content;
35 | public boolean liked;
36 |
37 | public TextModel() {
38 | super();
39 | content = TOXIC_SOUP[(new Random()).nextInt(1000) % TOXIC_SOUP.length];
40 | liked = (new Random()).nextBoolean();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/layout/item_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
19 |
20 |
24 |
25 |
31 |
32 |
36 |
37 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/item/FollowerItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.item;
2 |
3 | import android.view.View;
4 |
5 | import com.baurine.multitypeadapter.MultiTypeAdapter;
6 | import com.baurine.multitypeadaptersample.R;
7 | import com.baurine.multitypeadaptersample.model.FollowerModel;
8 |
9 | /**
10 | * Created by baurine on 1/10/17.
11 | */
12 |
13 | public class FollowerItem extends BaseItem {
14 | @Override
15 | public int getLayout() {
16 | return R.layout.item_follower;
17 | }
18 |
19 | ////////////////////////////////////////////////
20 | public FollowerItem(FollowerModel followerModel, final MultiTypeAdapter adapter) {
21 | this.followerModel = followerModel;
22 |
23 | setOnClickListener(new View.OnClickListener() {
24 | @Override
25 | public void onClick(View view) {
26 | toggleFollowed();
27 | adapter.notifyItemChanged(adapter.findPos(FollowerItem.this));
28 | }
29 | });
30 | }
31 |
32 | ////////////////////////////////////////////////
33 | // data model part
34 | private final FollowerModel followerModel;
35 |
36 | public String getContent() {
37 | return followerModel.follower + " 关注了你!";
38 | }
39 |
40 | public int getAvatarResId() {
41 | return followerModel.avatarResId;
42 | }
43 |
44 | public boolean isFollowed() {
45 | return followerModel.followed;
46 | }
47 |
48 | public void toggleFollowed() {
49 | followerModel.followed = !followerModel.followed;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/layout/item_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
19 |
20 |
23 |
24 |
31 |
32 |
37 |
38 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/item/TextItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.item;
2 |
3 | import android.view.View;
4 |
5 | import com.baurine.multitypeadapter.MultiTypeAdapter;
6 | import com.baurine.multitypeadaptertutorial.R;
7 | import com.baurine.multitypeadaptertutorial.model.TextModel;
8 |
9 | /**
10 | * Created by baurine on 1/14/17.
11 | */
12 |
13 | public class TextItem extends BaseItem {
14 | @Override
15 | public int getLayout() {
16 | return R.layout.item_text;
17 | }
18 |
19 | ///////////////////////////////////////////
20 | private final TextModel textModel;
21 |
22 | public TextItem(final MultiTypeAdapter adapter, TextModel textModel) {
23 | this.textModel = textModel;
24 |
25 | setOnClickListener(new View.OnClickListener() {
26 | @Override
27 | public void onClick(View view) {
28 | switch (view.getId()) {
29 | case R.id.tv_like:
30 | toggleLiked();
31 | adapter.notifyItemChanged(adapter.findPos(TextItem.this));
32 | break;
33 | case R.id.tv_hide:
34 | adapter.notifyItemRemoved(adapter.removeItem(TextItem.this));
35 | break;
36 | case R.id.tv_comment:
37 | // TODO: jump to another activity
38 | break;
39 | }
40 | }
41 | });
42 | }
43 |
44 | public String getContent() {
45 | return textModel.content;
46 | }
47 |
48 | public boolean isLiked() {
49 | return textModel.liked;
50 | }
51 |
52 | private void toggleLiked() {
53 | textModel.liked = !textModel.liked;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/item/ImageItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.item;
2 |
3 | import android.view.View;
4 |
5 | import com.baurine.multitypeadapter.MultiTypeAdapter;
6 | import com.baurine.multitypeadaptertutorial.R;
7 | import com.baurine.multitypeadaptertutorial.model.ImageModel;
8 |
9 | /**
10 | * Created by baurine on 1/14/17.
11 | */
12 |
13 | public class ImageItem extends BaseItem {
14 | @Override
15 | public int getLayout() {
16 | return R.layout.item_image;
17 | }
18 |
19 | ////////////////////////////////////////////////
20 | private final ImageModel imageModel;
21 |
22 | public ImageItem(final MultiTypeAdapter adapter, ImageModel imageModel) {
23 | this.imageModel = imageModel;
24 |
25 | setOnClickListener(new View.OnClickListener() {
26 | @Override
27 | public void onClick(View view) {
28 | switch (view.getId()) {
29 | case R.id.tv_like:
30 | toggleLiked();
31 | adapter.notifyItemChanged(adapter.findPos(ImageItem.this));
32 | break;
33 | case R.id.tv_hide:
34 | adapter.notifyItemRemoved(adapter.removeItem(ImageItem.this));
35 | break;
36 | case R.id.tv_comment:
37 | // TODO: jump to another activity
38 | break;
39 | }
40 | }
41 | });
42 | }
43 |
44 | public String getUrl() {
45 | return imageModel.url;
46 | }
47 |
48 | public boolean isLiked() {
49 | return imageModel.liked;
50 | }
51 |
52 | private void toggleLiked() {
53 | imageModel.liked = !imageModel.liked;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/layout/include_actions.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
17 |
20 |
21 |
31 |
32 |
41 |
42 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/layout/item_follower.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
19 |
20 |
24 |
25 |
31 |
32 |
37 |
38 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/layout/include_actions.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
17 |
20 |
21 |
32 |
33 |
43 |
44 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/item/ImageItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.item;
2 |
3 | import android.view.View;
4 |
5 | import com.baurine.multitypeadapter.MultiTypeAdapter;
6 | import com.baurine.multitypeadaptersample.R;
7 | import com.baurine.multitypeadaptersample.model.ImageModel;
8 | import com.baurine.multitypeadaptersample.util.CommonUtil;
9 |
10 | /**
11 | * Created by baurine on 1/10/17.
12 | */
13 |
14 | public class ImageItem extends BaseItem {
15 | @Override
16 | public int getLayout() {
17 | return R.layout.item_image;
18 | }
19 |
20 | ///////////////////////////////////////
21 | public ImageItem(ImageModel imageModel, final MultiTypeAdapter adapter) {
22 | this.imageModel = imageModel;
23 |
24 | setOnClickListener(new View.OnClickListener() {
25 | @Override
26 | public void onClick(View view) {
27 | switch (view.getId()) {
28 | case R.id.tv_like:
29 | toggleLiked();
30 | // adapter.notifyDataSetChanged();
31 | adapter.notifyItemChanged(adapter.findPos(ImageItem.this));
32 | break;
33 | case R.id.tv_hide:
34 | // adapter.removeItem(item);
35 | // adapter.notifyDataSetChanged();
36 | adapter.notifyItemRemoved(adapter.removeItem(ImageItem.this));
37 | break;
38 | case R.id.tv_comment:
39 | CommonUtil.showToast(view.getContext(),
40 | "TODO: comment image, id: " +
41 | String.valueOf(getId()));
42 | break;
43 | }
44 | }
45 | });
46 | }
47 |
48 | ///////////////////////////////////////
49 | // data model part
50 | private final ImageModel imageModel;
51 |
52 | public String getUrl() {
53 | return imageModel.url;
54 | }
55 |
56 | public boolean isLiked() {
57 | return imageModel.liked;
58 | }
59 |
60 | public int getId() {
61 | return imageModel.id;
62 | }
63 |
64 | public void toggleLiked() {
65 | imageModel.liked = !imageModel.liked;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/res/layout/item_footer.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
28 |
29 |
30 |
37 |
38 |
39 |
44 |
45 |
49 |
50 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/res/layout/item_footer.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
28 |
29 |
30 |
37 |
38 |
39 |
44 |
45 |
49 |
50 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/item/TextItem.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.item;
2 |
3 | import android.view.View;
4 |
5 | import com.baurine.multitypeadapter.MultiTypeAdapter;
6 | import com.baurine.multitypeadaptersample.R;
7 | import com.baurine.multitypeadaptersample.model.TextModel;
8 | import com.baurine.multitypeadaptersample.util.CommonUtil;
9 | import com.baurine.multitypeadaptersample.util.DateFormatUtil;
10 |
11 | /**
12 | * Created by baurine on 1/10/17.
13 | */
14 |
15 | public class TextItem extends BaseItem {
16 | @Override
17 | public int getLayout() {
18 | return R.layout.item_text;
19 | }
20 |
21 | ////////////////////////////////////////////////
22 | public TextItem(TextModel textModel, final MultiTypeAdapter adapter) {
23 | this.textModel = textModel;
24 |
25 | setOnClickListener(new View.OnClickListener() {
26 | @Override
27 | public void onClick(View view) {
28 | switch (view.getId()) {
29 | case R.id.tv_like:
30 | toggleLiked();
31 | // adapter.notifyDataSetChanged();
32 | adapter.notifyItemChanged(adapter.findPos(TextItem.this));
33 | break;
34 | case R.id.tv_hide:
35 | // adapter.removeItem(item);
36 | // adapter.notifyDataSetChanged();
37 | adapter.notifyItemRemoved(adapter.removeItem(TextItem.this));
38 | break;
39 | case R.id.tv_comment:
40 | CommonUtil.showToast(view.getContext(),
41 | "TODO: comment text, id: " +
42 | String.valueOf(getId()));
43 | break;
44 | }
45 | }
46 | });
47 | }
48 |
49 | ////////////////////////////////////////////////
50 | // data model part
51 | private final TextModel textModel;
52 |
53 | public String getText() {
54 | return DateFormatUtil.formatTime(textModel.createdAt) + " - " + textModel.content;
55 | }
56 |
57 | public boolean isLiked() {
58 | return textModel.liked;
59 | }
60 |
61 | public int getId() {
62 | return textModel.id;
63 | }
64 |
65 | public void toggleLiked() {
66 | textModel.liked = !textModel.liked;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.activity;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v4.widget.SwipeRefreshLayout;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 |
10 | import com.baurine.multitypeadaptersample.R;
11 | import com.baurine.multitypeadaptersample.databinding.ActivityMainBinding;
12 | import com.baurine.multitypeadaptersample.presenter.MainPresenter;
13 |
14 | public class MainActivity extends AppCompatActivity implements RefreshingView {
15 |
16 | private RecyclerView recyclerView;
17 | private SwipeRefreshLayout swipeRefreshLayout;
18 | private MainPresenter mainPresenter;
19 |
20 | @Override
21 | protected void onCreate(Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
24 | mainPresenter = new MainPresenter(this);
25 |
26 | recyclerView = binding.recyclerView;
27 | swipeRefreshLayout = binding.swipeRefreshLayout;
28 | initViews();
29 | }
30 |
31 | private void initViews() {
32 | recyclerView.setHasFixedSize(true);
33 | final LinearLayoutManager llm = new LinearLayoutManager(recyclerView.getContext());
34 | recyclerView.setLayoutManager(llm);
35 | recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
36 | @Override
37 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
38 | if (newState == RecyclerView.SCROLL_STATE_IDLE &&
39 | llm.findLastVisibleItemPosition() >= mainPresenter.getAdapter().getItemCount() - 1) {
40 | mainPresenter.loadMoreData();
41 | }
42 | }
43 | });
44 | recyclerView.setAdapter(mainPresenter.getAdapter());
45 |
46 | swipeRefreshLayout.setOnRefreshListener(
47 | new SwipeRefreshLayout.OnRefreshListener() {
48 | @Override
49 | public void onRefresh() {
50 | mainPresenter.refreshData();
51 | }
52 | });
53 | }
54 |
55 | @Override
56 | public void setRefreshing(boolean refreshing) {
57 | swipeRefreshLayout.setRefreshing(refreshing);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.activity;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v4.widget.SwipeRefreshLayout;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 |
10 | import com.baurine.multitypeadaptertutorial.R;
11 | import com.baurine.multitypeadaptertutorial.databinding.ActivityMainBinding;
12 | import com.baurine.multitypeadaptertutorial.presenter.MainPresenter;
13 |
14 | public class MainActivity extends AppCompatActivity implements RefreshingView {
15 | private MainPresenter mainPresenter;
16 | private SwipeRefreshLayout swipeRefreshLayout;
17 | private RecyclerView recyclerView;
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | ActivityMainBinding binding =
23 | DataBindingUtil.setContentView(this, R.layout.activity_main);
24 |
25 | mainPresenter = new MainPresenter(this);
26 | swipeRefreshLayout = binding.swipeRefreshLayout;
27 | recyclerView = binding.recyclerView;
28 | initViews();
29 | }
30 |
31 | private void initViews() {
32 | swipeRefreshLayout.setOnRefreshListener(
33 | new SwipeRefreshLayout.OnRefreshListener() {
34 | @Override
35 | public void onRefresh() {
36 | mainPresenter.refreshData();
37 | }
38 | });
39 |
40 | recyclerView.setHasFixedSize(true);
41 | final LinearLayoutManager llm = new LinearLayoutManager(this);
42 | recyclerView.setLayoutManager(llm);
43 | recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
44 | @Override
45 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
46 | if (newState == RecyclerView.SCROLL_STATE_IDLE &&
47 | llm.findLastVisibleItemPosition() >=
48 | mainPresenter.getAdapter().getItemCount() - 1) {
49 | mainPresenter.loadMoreData();
50 | }
51 | }
52 | });
53 | recyclerView.setAdapter(mainPresenter.getAdapter());
54 | }
55 |
56 | @Override
57 | public void setRefreshing(boolean refreshing) {
58 | swipeRefreshLayout.setRefreshing(refreshing);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/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 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/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 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/multitypeadapter/src/main/java/com/baurine/multitypeadapter/MultiTypeAdapter.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadapter;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.databinding.ViewDataBinding;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.ViewGroup;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 |
13 | /**
14 | * Created by baurine on 1/14/17.
15 | */
16 |
17 | public class MultiTypeAdapter extends RecyclerView.Adapter {
18 |
19 | public interface IItem {
20 | // get the xml layout this type item used in
21 | int getLayout();
22 |
23 | // get the variable name in the xml
24 | int getVariableId();
25 | }
26 |
27 | private List items = new ArrayList<>();
28 |
29 | ///////////////////////////////////////////////////////
30 |
31 | @Override
32 | public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
33 | return ItemViewHolder.create(parent, viewType);
34 | }
35 |
36 | @Override
37 | public void onBindViewHolder(ItemViewHolder holder, int position) {
38 | holder.bindTo(items.get(position));
39 | }
40 |
41 | @Override
42 | public int getItemCount() {
43 | return items.size();
44 | }
45 |
46 | @Override
47 | public int getItemViewType(int position) {
48 | return items.get(position).getLayout();
49 | }
50 |
51 | ///////////////////////////////////////////////////////
52 | // operate items
53 |
54 | public List getItems() {
55 | return items;
56 | }
57 |
58 | public int findPos(IItem item) {
59 | return items.indexOf(item);
60 | }
61 |
62 | public void setItem(IItem item) {
63 | clearItems();
64 | addItem(item);
65 | }
66 |
67 | public void setItems(List items) {
68 | clearItems();
69 | addItems(items);
70 | }
71 |
72 | public void addItem(IItem item) {
73 | items.add(item);
74 | }
75 |
76 | public void addItem(IItem item, int index) {
77 | items.add(index, item);
78 | }
79 |
80 | public void addItems(List items) {
81 | this.items.addAll(items);
82 | }
83 |
84 | public int removeItem(IItem item) {
85 | int pos = findPos(item);
86 | items.remove(item);
87 | return pos;
88 | }
89 |
90 | public void clearItems() {
91 | items.clear();
92 | }
93 |
94 | ///////////////////////////////////////////////////
95 |
96 | static class ItemViewHolder extends RecyclerView.ViewHolder {
97 | private final ViewDataBinding binding;
98 |
99 | static ItemViewHolder create(ViewGroup parent, int viewType) {
100 | ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
101 | viewType, parent, false);
102 | return new ItemViewHolder(binding);
103 | }
104 |
105 | ItemViewHolder(ViewDataBinding binding) {
106 | super(binding.getRoot());
107 | this.binding = binding;
108 | }
109 |
110 | void bindTo(MultiTypeAdapter.IItem item) {
111 | binding.setVariable(item.getVariableId(), item);
112 | binding.executePendingBindings();
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/multitypeadapter/src/main/java/com/baurine/multitypeadapter/MultiTypeAdapter.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadapter;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.databinding.ViewDataBinding;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.ViewGroup;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | /**
13 | * Created by baurine on 1/10/17.
14 | */
15 |
16 | public class MultiTypeAdapter extends RecyclerView.Adapter {
17 | public interface IItem {
18 | // get the xml layout this type item used in
19 | int getLayout();
20 |
21 | // get the variable name in the xml
22 | int getVariableId();
23 | }
24 |
25 | private List items = new ArrayList<>();
26 |
27 | ////////////////////////////////////////////////////////
28 | @Override
29 | public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
30 | return ItemViewHolder.create(parent, viewType);
31 | }
32 |
33 | @Override
34 | public void onBindViewHolder(ItemViewHolder holder, int position) {
35 | holder.bindTo(items.get(position));
36 | }
37 |
38 | @Override
39 | public int getItemViewType(int position) {
40 | return items.get(position).getLayout();
41 | }
42 |
43 | @Override
44 | public int getItemCount() {
45 | return items.size();
46 | }
47 |
48 | ////////////////////////////////////////////////////////
49 | // default items operation
50 | // you also can inherit MultiTypeAdapter to implement more methods to operate items
51 | public List getItems() {
52 | return items;
53 | }
54 |
55 | public int findPos(IItem item) {
56 | return items.indexOf(item);
57 | }
58 |
59 | public void setItem(IItem item) {
60 | clearItems();
61 | addItem(item);
62 | }
63 |
64 | public void setItems(List items) {
65 | clearItems();
66 | addItems(items);
67 | }
68 |
69 | public void addItem(IItem item) {
70 | items.add(item);
71 | }
72 |
73 | public void addItem(IItem item, int index) {
74 | items.add(index, item);
75 | }
76 |
77 | public void addItems(List items) {
78 | this.items.addAll(items);
79 | }
80 |
81 | public int removeItem(IItem item) {
82 | int pos = findPos(item);
83 | items.remove(item);
84 | return pos;
85 | }
86 |
87 | public void clearItems() {
88 | items.clear();
89 | }
90 |
91 | ////////////////////////////////////////////////////////
92 | static class ItemViewHolder extends RecyclerView.ViewHolder {
93 | private final ViewDataBinding binding;
94 |
95 | static ItemViewHolder create(ViewGroup parent, int viewType) {
96 | ViewDataBinding binding =
97 | DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
98 | viewType, parent, false);
99 | return new ItemViewHolder(binding);
100 | }
101 |
102 | ItemViewHolder(ViewDataBinding binding) {
103 | super(binding.getRoot());
104 | this.binding = binding;
105 | }
106 |
107 | void bindTo(IItem item) {
108 | binding.setVariable(item.getVariableId(), item);
109 | binding.executePendingBindings();
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/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 |
--------------------------------------------------------------------------------
/MultiTypeAdapterSample/app/src/main/java/com/baurine/multitypeadaptersample/presenter/MainPresenter.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptersample.presenter;
2 |
3 | import android.os.Handler;
4 | import android.view.View;
5 |
6 | import com.baurine.multitypeadapter.MultiTypeAdapter;
7 | import com.baurine.multitypeadaptersample.activity.RefreshingView;
8 | import com.baurine.multitypeadaptersample.item.EmptyItem;
9 | import com.baurine.multitypeadaptersample.item.ErrorItem;
10 | import com.baurine.multitypeadaptersample.item.FooterItem;
11 | import com.baurine.multitypeadaptersample.item.HeaderItem;
12 | import com.baurine.multitypeadaptersample.model.ModelFaker;
13 |
14 | import java.util.Random;
15 |
16 | public class MainPresenter {
17 | private RefreshingView refreshingView;
18 |
19 | private boolean refreshing = false;
20 | private boolean loading = false;
21 | private static final int PER_PAGE_COUNT = 8;
22 |
23 | private MultiTypeAdapter adapter = new MultiTypeAdapter();
24 | private HeaderItem headerItem = new HeaderItem();
25 | private EmptyItem emptyItem = new EmptyItem();
26 | private ErrorItem errorItem = new ErrorItem();
27 | private FooterItem footerItem = new FooterItem();
28 |
29 | public MainPresenter(RefreshingView refreshingView) {
30 | this.refreshingView = refreshingView;
31 | initItems();
32 | }
33 |
34 | ////////////////////////////////////////////////////////
35 | private void initItems() {
36 | emptyItem.setOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View view) {
39 | adapter.notifyItemRemoved(adapter.removeItem(emptyItem));
40 | refreshData();
41 | }
42 | });
43 | errorItem.setOnClickListener(new View.OnClickListener() {
44 | @Override
45 | public void onClick(View view) {
46 | adapter.notifyItemRemoved(adapter.removeItem(errorItem));
47 | refreshData();
48 | }
49 | });
50 | footerItem.setOnClickListener(new View.OnClickListener() {
51 | @Override
52 | public void onClick(View view) {
53 | loadMoreData();
54 | }
55 | });
56 | adapter.addItem(headerItem);
57 | adapter.addItem(emptyItem);
58 | }
59 |
60 | ////////////////////////////////////////////////////////
61 | // public methods for MainView
62 |
63 | public MultiTypeAdapter getAdapter() {
64 | return adapter;
65 | }
66 |
67 | public void refreshData() {
68 | if (!refreshing) {
69 | refreshing = true;
70 | refreshingView.setRefreshing(true);
71 | footerItem.setState(FooterItem.LOADING);
72 | fetchData(false);
73 | }
74 | }
75 |
76 | public void loadMoreData() {
77 | int footerPos = adapter.findPos(footerItem);
78 | if (!loading &&
79 | footerPos >= 0 &&
80 | !footerItem.isNoMore()) {
81 | if (!footerItem.isLoading()) {
82 | footerItem.setState(FooterItem.LOADING);
83 | adapter.notifyItemChanged(footerPos);
84 | }
85 | loading = true;
86 | fetchData(true);
87 | }
88 | }
89 |
90 | ////////////////////////////////////////////////////////
91 | // fetch data from server, for refreshing or load more
92 | private void fetchData(final boolean loadMore) {
93 | // mock network request
94 | new Handler().postDelayed(new Runnable() {
95 | @Override
96 | public void run() {
97 | if (loadMore) {
98 | loading = false;
99 | adapter.removeItem(footerItem);
100 | } else {
101 | refreshing = false;
102 | refreshingView.setRefreshing(false);
103 | // remove all other items, just keep headerItem
104 | adapter.setItem(headerItem);
105 | }
106 | retrieveItems(loadMore);
107 | adapter.notifyDataSetChanged();
108 | }
109 | }, 2000);
110 | }
111 |
112 | private void retrieveItems(boolean loadMore) {
113 | // result = 0, network error
114 | // result = 1, empty
115 | // result = 2, last page data
116 | // result = 3 and other, normal result
117 | int resultType = (new Random()).nextInt(100) % 5;
118 | if (resultType == 0) {
119 | adapter.addItem(loadMore ? footerItem.setState(FooterItem.ERROR) : errorItem);
120 | } else if (resultType == 1) {
121 | adapter.addItem(loadMore ? footerItem.setState(FooterItem.NO_MORE) : emptyItem);
122 | } else if (resultType == 2) {
123 | addDataItems(PER_PAGE_COUNT / 2);
124 | // here depends whether you want to display no more data state
125 | // if you don't want to display this state when has no more data
126 | // then just don't add it back,
127 | // but still need set no more state for footerItem
128 | adapter.addItem(footerItem.setState(FooterItem.NO_MORE));
129 | } else {
130 | addDataItems(PER_PAGE_COUNT);
131 | // pre-display loading state to improve user experience
132 | adapter.addItem(footerItem.setState(FooterItem.LOADING));
133 | }
134 | }
135 |
136 | private void addDataItems(int count) {
137 | for (int i = 0; i < count; i++) {
138 | adapter.addItem(ModelFaker.fake().createItem(adapter));
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/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 |
--------------------------------------------------------------------------------
/MultiTypeAdapterTutorial/app/src/main/java/com/baurine/multitypeadaptertutorial/presenter/MainPresenter.java:
--------------------------------------------------------------------------------
1 | package com.baurine.multitypeadaptertutorial.presenter;
2 |
3 | import android.os.Handler;
4 | import android.view.View;
5 |
6 | import com.baurine.multitypeadapter.MultiTypeAdapter;
7 | import com.baurine.multitypeadaptertutorial.activity.RefreshingView;
8 | import com.baurine.multitypeadaptertutorial.item.EmptyItem;
9 | import com.baurine.multitypeadaptertutorial.item.ErrorItem;
10 | import com.baurine.multitypeadaptertutorial.item.FooterItem;
11 | import com.baurine.multitypeadaptertutorial.item.HeaderItem;
12 | import com.baurine.multitypeadaptertutorial.model.ModelFaker;
13 |
14 | import java.util.Random;
15 |
16 | /**
17 | * Created by baurine on 1/16/17.
18 | */
19 |
20 | public class MainPresenter {
21 | private RefreshingView refreshingView;
22 |
23 | private MultiTypeAdapter adapter = new MultiTypeAdapter();
24 | private HeaderItem headerItem;
25 | private EmptyItem emptyItem;
26 | private ErrorItem errorItem;
27 | private FooterItem footerItem;
28 |
29 | private boolean refreshing = false;
30 | private boolean loading = false;
31 | private static final int PER_PAGE_COUNT = 8;
32 |
33 | public MainPresenter(RefreshingView refreshingView) {
34 | this.refreshingView = refreshingView;
35 | initItems();
36 | }
37 |
38 | public MultiTypeAdapter getAdapter() {
39 | return adapter;
40 | }
41 |
42 | private void initItems() {
43 | headerItem = new HeaderItem();
44 | emptyItem = new EmptyItem();
45 | errorItem = new ErrorItem();
46 | footerItem = new FooterItem();
47 |
48 | emptyItem.setOnClickListener(new View.OnClickListener() {
49 | @Override
50 | public void onClick(View view) {
51 | adapter.notifyItemRemoved(adapter.removeItem(emptyItem));
52 | refreshData();
53 | }
54 | });
55 | errorItem.setOnClickListener(new View.OnClickListener() {
56 | @Override
57 | public void onClick(View view) {
58 | adapter.notifyItemRemoved(adapter.removeItem(errorItem));
59 | refreshData();
60 | }
61 | });
62 | footerItem.setOnClickListener(new View.OnClickListener() {
63 | @Override
64 | public void onClick(View view) {
65 | loadMoreData();
66 | }
67 | });
68 |
69 | adapter.addItem(headerItem);
70 | adapter.addItem(emptyItem);
71 | }
72 |
73 | public void refreshData() {
74 | if (!refreshing) {
75 | refreshing = true;
76 | refreshingView.setRefreshing(true);
77 | footerItem.setState(FooterItem.LOADING);
78 | fetchData(false);
79 | }
80 | }
81 |
82 | public void loadMoreData() {
83 | int footerPos = adapter.findPos(footerItem);
84 | if (!loading &&
85 | footerPos >= 0 &&
86 | !footerItem.isNoMore()) {
87 | if (!footerItem.isLoading()) {
88 | footerItem.setState(FooterItem.LOADING);
89 | adapter.notifyItemChanged(adapter.findPos(footerItem));
90 | }
91 | loading = true;
92 | fetchData(true);
93 | }
94 | }
95 |
96 | ////////////////////////////////////////////////////////
97 | // fetch data from server, for refreshing or load more
98 | private void fetchData(final boolean loadMore) {
99 | // mock network request
100 | new Handler().postDelayed(new Runnable() {
101 | @Override
102 | public void run() {
103 | if (loadMore) {
104 | loading = false;
105 | adapter.removeItem(footerItem);
106 | } else {
107 | refreshing = false;
108 | refreshingView.setRefreshing(false);
109 | // remove all other items, just keep headerItem
110 | adapter.setItem(headerItem);
111 | }
112 | retrieveItems(loadMore);
113 | adapter.notifyDataSetChanged();
114 | }
115 | }, 2000);
116 | }
117 |
118 | private void retrieveItems(boolean loadMore) {
119 | // result = 0, network error
120 | // result = 1, empty
121 | // result = 2, last page
122 | // result = 3 and other, normal result
123 | int resultType = (new Random()).nextInt(100) % 5;
124 | if (resultType == 0) {
125 | adapter.addItem(loadMore ? footerItem.setState(FooterItem.ERROR) : errorItem);
126 | } else if (resultType == 1) {
127 | adapter.addItem(loadMore ? footerItem.setState(FooterItem.NO_MORE) : emptyItem);
128 | } else if (resultType == 2) {
129 | addDataItems(PER_PAGE_COUNT / 2);
130 | // here depends whether you want to display no more data state
131 | // if you don't want to display it when has no more data
132 | // then just don't add it back,
133 | // but still need set no more state for footerItem
134 | adapter.addItem(footerItem.setState(FooterItem.NO_MORE));
135 | } else {
136 | addDataItems(PER_PAGE_COUNT);
137 | // pre-display loading state to improve user experience
138 | adapter.addItem(footerItem.setState(FooterItem.LOADING));
139 | }
140 | }
141 |
142 | private void addDataItems(int count) {
143 | for (int i = 0; i < count; i++) {
144 | adapter.addItem(ModelFaker.fake().createItem(adapter));
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MultiTypeAdapter
2 |
3 | [](https://jitpack.io/#baurine/multi-type-adapter)
4 |
5 | Implement a super simple, powerful, and easy to use MultiTypeAdapter for RecyclerView by android databinding, it is only about 100 lines code and just one java file, use this adapter, you can never to implement kinds of ViewHolder anymore.
6 |
7 | I write a very detail tutorial to explain how to implement this MultiTypeAdapter, and how to use it to implement a complete sample that support refresh, load more, retry, header item, emtpy item, error item, footer item, any kinds of data item step by step.
8 |
9 | ## Tutorial
10 |
11 | 1. [Escape the nightmare of adapter and viewholder by android databinding (1)](./note/multi-type-adapter-tutorial-1.md)
12 | 1. [Escape the nightmare of adapter and viewholder by android databinding (2)](./note/multi-type-adapter-tutorial-2.md)
13 |
14 | ## Sample
15 |
16 | 1. Demo HeaderItem, EmptyItem, ErrorItem, refresh, load more, load error and retry:
17 |
18 | 
19 |
20 | 1. Demo load more but has no more data:
21 |
22 | 
23 |
24 | 1. Polish the UI, add event handler for item:
25 |
26 | 
27 |
28 | The sample includes following features, I think it should fullfill 90% needs:
29 |
30 | 1. Refresh
31 | 1. Load more
32 | 1. Support header item
33 | 1. Support empty item and enable refresh again
34 | 1. Support error item and enable refresh again
35 | 1. Support footer item, includes 3 states: loading, load error and enable retry, no more data
36 | 1. Support any kind of data item, here just demo ImageItem and TextItem
37 |
38 | [Download APK](https://github.com/baurine/multi-type-adapter/releases/tag/v1.0.5_release) | [GitHub](https://github.com/baurine/multi-type-adapter)
39 |
40 | There are two folders in this project, MultiTypeAdapterSample and MultiTypeAdapterTutorial, their codes are nearly same, the latter is created for the above tutorial articles, I tag the every key step so you can easily compare the code with article.
41 |
42 | ## Getting Started
43 |
44 | Add JitPack as library source in your project `build.gradle`:
45 |
46 | allprojects {
47 | repositories {
48 | ...
49 | maven { url 'https://jitpack.io' }
50 | }
51 | }
52 |
53 | Then, add dependency in your app module `build.gradle`:
54 |
55 | dependencies {
56 | compile 'com.github.baurine:multi-type-adapter:${latest-version}'
57 | }
58 |
59 | `latest-version`: see top jitpack badge.
60 |
61 | And enable databinding in your app module `build.gradle`:
62 |
63 | android {
64 | ...
65 | dataBinding {
66 | enabled = true
67 | }
68 | }
69 |
70 | ## Usage
71 |
72 | Please read the above super detail tutorial to learn how exactly to use it. Following are some simple instruction extract from tutorial.
73 |
74 | After you use this MultiTypeAdapter, you just need to implement kinds of items, and add to or remove from adapter at the right time. The item represents a whole body that display in recyclerview, includes layout, data and event, so it is a wrapper, wrap the layout, data model and event handler together, but the data model and event handler are not necessary, just layout is required, it depends on what's the kind of item. All items must inherit from `IItem` interface:
75 |
76 | public interface IItem {
77 | // get the xml layout this type item used in
78 | int getLayout();
79 |
80 | // get the variable name in the xml
81 | int getVariableId();
82 | }
83 |
84 | `getLayout()` method should return the xml layout, likes `R.layout.item_header`, and `getVariableId()` return the variable name this item used in xml, likes `BR.item`. Becasuse we usually use a same variable name in all items, and the event handler, usually it can be a `View.OnClickListener`, so we define a `BaseItem`:
85 |
86 | public abstract class BaseItem implements MultiTypeAdapter.IItem {
87 | @Override
88 | public int getVariableId() {
89 | return BR.item;
90 | }
91 |
92 | ////////////////////////////////////////////
93 | // handle event
94 | private View.OnClickListener onClickListener;
95 |
96 | public View.OnClickListener getOnClickListener() {
97 | return onClickListener;
98 | }
99 |
100 | public void setOnClickListener(View.OnClickListener onClickListener) {
101 | this.onClickListener = onClickListener;
102 | }
103 | }
104 |
105 | Here is an example, a most simple item - HeaderItem, just has layout, no data and no event:
106 |
107 | public class HeaderItem extends BaseItem {
108 | @Override
109 | public int getLayout() {
110 | return R.layout.item_header;
111 | }
112 | }
113 |
114 | And HeaderItem used in `item_header.xml`:
115 |
116 |
118 |
119 |
122 |
123 |
124 |
131 |
132 |
139 |
140 |
141 |
142 |
143 | A most complex item - ImageItem, display a random image, and you can like it, hide it, and comment it, the image data from ImageModel:
144 |
145 | ImageModel:
146 |
147 | public class ImageModel extends BaseModel {
148 | @Override
149 | public MultiTypeAdapter.IItem createItem(MultiTypeAdapter adapter) {
150 | return new ImageItem(this, adapter);
151 | }
152 |
153 | ////////////////////////////////////////
154 | public final String url;
155 | public boolean liked;
156 |
157 | public ImageModel() {
158 | super();
159 | url = "https://unsplash.it/200/200?random&" + new Random().nextInt(40);
160 | liked = (new Random()).nextBoolean();
161 | }
162 | }
163 |
164 | ImageItem:
165 |
166 | public class ImageItem extends BaseItem {
167 | @Override
168 | public int getLayout() {
169 | return R.layout.item_image;
170 | }
171 |
172 | ///////////////////////////////////////
173 | public ImageItem(ImageModel imageModel, final MultiTypeAdapter adapter) {
174 | this.imageModel = imageModel;
175 |
176 | setOnClickListener(new View.OnClickListener() {
177 | @Override
178 | public void onClick(View view) {
179 | switch (view.getId()) {
180 | case R.id.tv_like:
181 | toggleLiked();
182 | adapter.notifyItemChanged(adapter.findPos(ImageItem.this));
183 | break;
184 | case R.id.tv_hide:
185 | adapter.notifyItemRemoved(adapter.removeItem(ImageItem.this));
186 | break;
187 | case R.id.tv_comment:
188 | CommonUtil.showToast(view.getContext(),
189 | "TODO: comment image, id: " +
190 | String.valueOf(getId()));
191 | break;
192 | }
193 | }
194 | });
195 | }
196 |
197 | ///////////////////////////////////////
198 | // data model part
199 | private final ImageModel imageModel;
200 |
201 | public String getUrl() {
202 | return imageModel.url;
203 | }
204 |
205 | public boolean isLiked() {
206 | return imageModel.liked;
207 | }
208 |
209 | public int getId() {
210 | return imageModel.id;
211 | }
212 |
213 | public void toggleLiked() {
214 | imageModel.liked = !imageModel.liked;
215 | }
216 | }
217 |
218 | ImageItem used in `item_image.xml`:
219 |
220 |
223 |
224 |
227 |
228 |
229 |
234 |
235 |
238 |
239 |
246 |
247 |
252 |
253 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
266 |
267 |
270 |
273 |
274 |
275 |
278 |
279 |
289 |
290 |
299 |
300 |
309 |
310 |
311 |
312 | Then call `adapter.addItem()`, `adapter.removeItem()`, `adapter.notifyItemChanged(adapter.findPos(item))` to operate the adapter at the right time. Following is an example to handle the network response result:
313 |
314 | private void retrieveItems(boolean loadMore) {
315 | // result = 0, network error
316 | // result = 1, empty
317 | // result = 2, last page data
318 | // result = 3 and other, normal result
319 | int resultType = (new Random()).nextInt(100) % 5;
320 | if (resultType == 0) {
321 | adapter.addItem(loadMore ? footerItem.setState(FooterItem.ERROR) : errorItem);
322 | } else if (resultType == 1) {
323 | adapter.addItem(loadMore ? footerItem.setState(FooterItem.NO_MORE) : emptyItem);
324 | } else if (resultType == 2) {
325 | addDataItems(PER_PAGE_COUNT / 2);
326 | // here depends whether you want to display no more data state
327 | // if you don't want to display this state when has no more data
328 | // then just don't add it back
329 | adapter.addItem(footerItem.setState(FooterItem.NO_MORE));
330 | } else {
331 | addDataItems(PER_PAGE_COUNT);
332 | // pre-display loading state to improve user experience
333 | adapter.addItem(footerItem.setState(FooterItem.LOADING));
334 | }
335 | }
336 |
337 | License
338 | -------
339 |
340 | Copyright 2017 baurine.
341 |
342 | Licensed under the Apache License, Version 2.0 (the "License");
343 | you may not use this file except in compliance with the License.
344 | You may obtain a copy of the License at
345 |
346 | http://www.apache.org/licenses/LICENSE-2.0
347 |
348 | Unless required by applicable law or agreed to in writing, software
349 | distributed under the License is distributed on an "AS IS" BASIS,
350 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
351 | See the License for the specific language governing permissions and
352 | limitations under the License.
353 |
--------------------------------------------------------------------------------
/note/multi-type-adapter-tutorial-1.md:
--------------------------------------------------------------------------------
1 | # 借助 android databinding 框架,逃离 adapter 和 viewholder 的噩梦 (1)
2 |
3 | ## 前言
4 |
5 | 理解这篇文章最好有 databinding 的基础知识,如果之前没有了解过,推荐下面三篇文章:
6 |
7 | 1. [官方文档](https://developer.android.com/topic/libraries/data-binding/index.html)
8 | 1. [connorlin 的中文翻译](http://connorlin.github.io/2016/07/02/Android-Data-Binding-%E7%B3%BB%E5%88%97-%E4%B8%80-%E8%AF%A6%E7%BB%86%E4%BB%8B%E7%BB%8D%E4%B8%8E%E4%BD%BF%E7%94%A8/)
9 | 1. [棉花糖给 Android 带来的 Data Bindings](https://realm.io/cn/news/data-binding-android-boyar-mount/)
10 |
11 | 但你也可以先看完这篇文章,大致了解 databinding 可以怎么帮助到我们后,再回去看这些基本介绍。
12 |
13 | 对于 android 开发者来说,诸多噩梦中,adapter 和 viewholder 绝对算一个,倒不是难,而是烦,千遍一率的相似代码,对于程序员来说,重复是最令人讨厌的。所以这才有这么多仁人志士,前俯后继地进行通用型,万能型 adapter 的抽象,这不,最近,我就在鸿洋的公众号又看见这么一篇投稿文章:[优雅的实现多类型列表的Adapter](http://www.jianshu.com/p/1297d2e4d27a),当然,还有 drakeet 的 [MultiType 项目](https://github.com/drakeet/MultiType)。
14 |
15 | 但是,由于受限于传统的 android 开发,即使他们已经做得很极致了,但用起来还是不够爽,我们还是要不停地去实现 ViewHolder。
16 |
17 | 直到我开始学习 databinding 框架,在 [棉花糖给 Android 带来的 Data Bindings](https://realm.io/cn/news/data-binding-android-boyar-mount/) 这篇文章中说到,databinding 可以轻松地实现多类型的 viewholder 时,我在想,我干嘛不用它来解决这个世界性的大难题呢(呵呵)。当下就立马开始尝试,实际,只要你写起来,就会发现,实现起来是非常 easy 和自然的。
18 |
19 | 使用 databinding 框架实现的 adapter 只有 100 行左右的代码,单一 java 文件,理解起来非常容易。从此你就可以忘记 viewholder 了。
20 |
21 | 当然,根据代码守恒定律,代码总量总体是恒定的,我们能使用这么少的代码,背后是 databinding 框架为我们生成的大量代码,眼不见,心不烦,更何况这是 google 为我们生成的代码。
22 |
23 | 是不是已经按捺不住激动的心情啦。好吧,我们言归正转。其实在之前我已经写 [一篇文章](https://github.com/baurine/android-data-binding-study/blob/master/note/multi-type-adapter.md) 来阐述这种思想,并写了一个简陋的例子,但后来我还是觉得这个例子太简单了,说服力不够,没有解决很多人关心的问题,在每个通用型 adapter 的文章下面,都有一堆人在问,如果用你这个 adapter,怎么刷新,怎么加载更多,怎么实现 header item,怎么实现 footer item。那么,我就决定,写一个完整的例子,一次性解决你们所有的疑问。并且,我把这个过程写下来,如何一步步实现这些功能,如何一步步重构代码,使代码优雅。最后,即使没有打动你投入 databinding 的怀抱,我觉得你也可以学习到很多。
24 |
25 | 先来看一下最后的效果,UI 就别吐槽了,毕竟对于工程师来说,独立开发一个应用,最大的问题就是选颜色了(其实是我啦),本来想用一个 GIF 来展示所有效果的,但一个 GIF 体积太大了,所以就拆成了三个:
26 |
27 | 1. 演示 HeaderItem,EmptyItem,ErrorItem,刷新,加载更多,加载出错并重试:
28 |
29 | 
30 |
31 | 1. 演示 没有更多数据:
32 |
33 | 
34 |
35 | 1. 稍微润色了一下 UI,为数据 Item 增加各种点击事件:
36 |
37 | 
38 |
39 | 这个完整的例子包括了以下功能,我想应该能满足 90% 的需求吧:
40 |
41 | 1. 刷新
42 | 1. 加载更多
43 | 1. 支持 header item
44 | 1. 支持 empty item,并允许再次刷新
45 | 1. 支持 error item,并允许再次刷新
46 | 1. 支持 footer item,包括 3 种状态:加载中,出错并允许重试,没有更多数据
47 | 1. 支持多种数据类型的 item,我们在这个例子中只展示了 ImageItem 和 TextItem 两种类型
48 |
49 | [下载 apk](https://github.com/baurine/multi-type-adapter/releases/tag/v1.0.5_release) | [项目地址](https://github.com/baurine/multi-type-adapter)
50 |
51 | 这个项目中有两个文件夹,MultiTyepAdapterSample 和 MultiTypeAdapterTutorial,两者代码是几乎相同的,后者是我为了写这篇文章重新创建的,每一个关键步骤我都打好了 tag,以方便读者进行对照。
52 |
53 | PS: 下面的内容完全是基于 databinding 思想来展开讲的,所以如果你对它不感兴趣,那么下面的内容对你就没什么帮助。另外,文章比较长且啰索 (力争讲解到每一个细节),需要比较充裕的时间来阅读和练习。如果你对 databinding 感兴趣,欢迎提交 issue 探讨。
54 |
55 | ## 大纲
56 |
57 | 1. [实现篇](#实现篇)
58 | 1. [一步一步实现极简的 adapter](#一步一步实现极简的-adapter)
59 |
60 | 1. [使用篇](./multi-type-adapter-tutorial-2.md#使用篇)
61 | 1. [设置 RecyclerView 和 SwipeRefreshLayout](./multi-type-adapter-tutorial-2.md#设置-recyclerView-和-swipeRefreshLayout)
62 | 1. [实现各种状态类 item](./multi-type-adapter-tutorial-2.md#实现各种状态类-item)
63 | 1. [实现刷新](./multi-type-adapter-tutorial-2.md#实现刷新)
64 | 1. [实现加载更多](./multi-type-adapter-tutorial-2.md#实现加载更多)
65 | 1. [为 item 增加事件处理](./multi-type-adapter-tutorial-2.md#为-item-增加事件处理)
66 | 1. [获取 item 的 position](./multi-type-adapter-tutorial-2.md#获取-item-的-position)
67 | 1. [item 与 model 的关系](./multi-type-adapter-tutorial-2.md#item-与-model-的关系)
68 |
69 | 1. [优化篇](./multi-type-adapter-tutorial-2.md#优化篇)
70 | 1. [将 adapter 独立成库](./multi-type-adapter-tutorial-2.md#将-adapter-独立成库)
71 | 1. [使用 MVP 简化 Activity 的逻辑](./multi-type-adapter-tutorial-2.md#使用-mvp-简化-activity-的逻辑)
72 |
73 | 1. [总结篇](./multi-type-adapter-tutorial-2.md#总结篇)
74 |
75 | ------------------------
76 |
77 | ## 实现篇
78 |
79 | ### 一步一步实现极简的 adapter
80 |
81 | 首先创建一个新的 Android Studio 工程,在 app module 的 build.gradle 中加上 databinding 的支持,并导入 recyclerview support 库:
82 |
83 | // build.gradle
84 | android {
85 | //...
86 |
87 | dataBinding {
88 | enabled = true
89 | }
90 | }
91 |
92 | dependencies {
93 | //...
94 | compile 'com.android.support:recyclerview-v7:25.1.0'
95 | }
96 |
97 | 接着,我们来开始来实现这个 adapter,取名为 MultiTypeAdapter,因为我们要支持多类型,那么 adapter 里的 item 必然是抽象的,我们定义为 IItem:
98 |
99 | // MultiTypeAdapter.java
100 | public interface IItem {
101 | }
102 |
103 | private List items = new ArrayList<>();
104 |
105 | 我们先从简单的入手,先来看看 `getItemCount()`,我们用 `showHeader` 和 `showFooter` 两个变量来控制是否显示 header 或 footer,那么 `getItemCount()` 的实现如下:
106 |
107 | // MultiTypeAdapter.java
108 | @Override
109 | public int getItemCount() {
110 | int cnt = items.size();
111 | if (showHeader) {
112 | cnt++;
113 | }
114 | if (showFooter) {
115 | cnt++;
116 | }
117 | return cnt;
118 | }
119 |
120 | 接着来实现 `getItemViewType(int position)`,关于这个方法,一般的实现,我们要根据 position 和相应位置的 item 类型来返回不同的值,比如:
121 |
122 | // MultiTypeAdapter.java
123 | @Override
124 | public int getItemViewType(int position) {
125 | if (position == 0 && showHeader) {
126 | return ITEM_TYPE_HEADER;
127 | } else if (position == getItemCount() -1 && showFooter) {
128 | return ITEM_TYPE_FOOTER;
129 | } else {
130 | if (items.get(position) instanceof ImageItem) {
131 | return ITEM_TYPE_IMAGE;
132 | } else {
133 | return ITEM_TYPE_TEXT;
134 | }
135 | }
136 | }
137 |
138 | 这样的实现,很烦很丑是不是。关于这个方法的优化,我们很容易达成一种共识,首先,我们不再返回类似 `ITEM_TYPE_IMAGE` 这种常量类型,而是直接返回它的 xml layout,其次,我们直接从 item 自身得到这个 layout。因此,我们为 IItem 增加一个 `getType()` 的接口方法。代码如下:
139 |
140 | public interface IItem {
141 | // should directly return layout
142 | int getType();
143 | }
144 |
145 | @Override
146 | public int getItemViewType(int position) {
147 | if (position == 0 && showHeader) {
148 | return R.layout.item_header;
149 | } else if (position == getItemCount() -1 && showFooter) {
150 | return R.layout.item_footer;
151 | } else {
152 | return items.get(position).getType();
153 | }
154 | }
155 |
156 | (2017/2/15 Update: 由于 `getType()` 实际是应该返回一个 xml layout 的,为了让这个方法名意义更明确,从 1.0.7 开始,这个方法重命名为 `getLayout()`,但整个教程仍然保留为 `getType()`)
157 |
158 | 因为 header 和 footer,尤其是 footer,只是单纯地用来显示 正在 loading 等一些状态,我们很容易把它跟常规的数据 item 区别对待,但是,实际上我们可以把它看成一个伪 item,没有数据,只有布局的 item。我们分别实现只有布局的 HeaerItem 和 FooterItem,并在合适的时机加到 items 里面或从 items 里移除,就可以控制 header 和 footer 的显示与隐藏了。
159 |
160 | // HeaerItem.java
161 | public class HeaderItem implements MulitTypeAdapter.IItem {
162 | @Override
163 | public int getType() {
164 | return R.layout.item_header;
165 | }
166 | }
167 |
168 | // FooterItem.java
169 | public class FooterItem implements MulitTypeAdapter.IItem {
170 | @Override
171 | public int getType() {
172 | return R.layout.item_footer;
173 | }
174 | }
175 |
176 | 这样,我们的 `getItemViewType()` 终于可以简化成一行代码了,清爽!
177 |
178 | @Override
179 | public int getItemViewType(int position) {
180 | return items.get(position).getType();
181 | }
182 |
183 | 这样,我们也不需要 showHeader 和 showFooter 这样的状态变量了,那么 `getItemCount()` 也可以简化成一行代码了。
184 |
185 | public int getItemCount() {
186 | return items.size();
187 | }
188 |
189 | 刚才说到我们要在合适的时机把 HeaerItem 或 FooterItem 加到 items 或从 items 中移除,所以我们给 adapter 加上一些操作 items 的方法。如下所示:
190 |
191 | // MultiTypeAdapter.java
192 | public void setItem(IItem item) {
193 | clearItems();
194 | addItem(item);
195 | }
196 |
197 | public void setItems(List items) {
198 | clearItems();
199 | addItems(items);
200 | }
201 |
202 | public void addItem(IItem item) {
203 | items.add(item);
204 | }
205 |
206 | public void addItem(IItem item, int index) {
207 | items.add(index, item);
208 | }
209 |
210 | public void addItems(List items) {
211 | this.items.addAll(items);
212 | }
213 |
214 | public void removeItem(IItem item) {
215 | items.remove(item);
216 | }
217 |
218 | public void clearItems() {
219 | items.clear();
220 | }
221 |
222 | 你可能会想,诶,在这些操作函数里最后再加上 `notifyDatasetChanged()` 是不是会更方便点,这样我在上层就不用再手动调用一下 `adapter.notifyDatasetChanged()`,实际当你自己写起来的时候,你就会发现这样并不灵活。因为,我可能并不想每一次 `addItem` 都刷新一次 UI,我可能要多次 `addItem` 后才刷新一次 UI,这样,在上层由调用者来决定何时刷新 UI 会更灵活,更何况,我可能并不想只调用 `notifyDatasetChanged()`,我有时想调用 `notifyItemRemoved()`,或是 `notifyItemChaned()`。
223 |
224 | 当然,你也可以给 adapter 加上一个 `getItems()` 的方法,然后把这些对 items 的操作逻辑都移动上层去处理,但我自己还是倾向于在 adapter 内封装这些方法。
225 |
226 | // MulitTypeAdapter.java
227 | public List getItems() {
228 | return items;
229 | }
230 |
231 | OK,至此,我们仅仅实现了 adapter 的 `getItemCount()` 和 `getItemViewType()` 方法,但是别着急。
232 |
233 | 截止目前为止的代码:[`tutorial_step_1`](https://github.com/baurine/multi-type-adapter/tree/tutorial_step_1)
234 |
235 | 接下来,就该处理难啃的的 `onCreateViewHolder()` 和 `onBindViewHolder()` 了,先来看 `onCreateViewHolder()` 吧。
236 |
237 | 在 `onCreateViewHolder()` 中,我们要根据 viewType 来生成不同的 ViewHolder,假设这里我们只显示 ImageViewHolder 和 TextViewHolder。要显示的 item 分别为 ImageItem 和 TextItem。我们先定义一个抽象基类 ItemViewHolder,代码如下:
238 |
239 | // ItemViewHolder.java
240 | public abstract class ItemViewHolder extends RecyclerView.ViewHolder {
241 | public ItemViewHolder(View itemView) {
242 | super(itemView);
243 | }
244 |
245 | public abstract void bindTo(MulitTypeAdapter.IItem item);
246 | }
247 |
248 | 分别实现 ImageViewHolder 和 TextViewHolder:
249 |
250 | // ImageViewHolder.java
251 | public class ImageViewHolder extends ItemViewHolder {
252 | public ImageViewHolder(View itemView) {
253 | super(itemView);
254 | }
255 |
256 | public void bindTo(MulitTypeAdapter.IItem item) {
257 | ImageItem imageItem = (ImageItem) item;
258 | // then do something
259 | }
260 | }
261 |
262 | // TextViewHolder.java
263 | public class TextViewHolder extends ItemViewHolder {
264 | public TextViewHolder(View itemView) {
265 | super(itemView);
266 | }
267 |
268 | public void bindTo(MulitTypeAdapter.IItem item) {
269 | TextItem textItem = (TextItem) item;
270 | // then do something
271 | }
272 | }
273 |
274 | 然后实现 `onCreateViewHolder()`:
275 |
276 | // MulitTypeAdapter.java
277 | @Override
278 | public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
279 | View itemView = LayoutInflater.from(parent.getContext())
280 | .inflate(viewType, parent, false);
281 | if (viewType == R.layout.item_image) {
282 | return new ImageViewHolder(itemView);
283 | } else if (viewType == R.layout.item_text) {
284 | return new TextViewHolder(itemView);
285 | }
286 | return null;
287 | }
288 |
289 | 实现 `onBindViewHolder()`:
290 |
291 | // MulitTypeAdapter.java
292 | @Override
293 | public void onBindViewHolder(ItemViewHolder holder, int position) {
294 | holder.bindTo(items.get(position));
295 | }
296 |
297 | 可以看到,`onBindViewHolder()` 的实现也已经变得非常简洁。那么就剩下 `onCreateViewHolder()` 了。一般来说,我们会把这一部分逻辑通过工厂方法来优化,代码如下所示:
298 |
299 | // ViewHolderFactory.java
300 | public class ViewHolderFactory {
301 | public static ItemViewHolder create(ViewGroup parent, int viewType) {
302 | View itemView = LayoutInflater.from(parent.getContext())
303 | .inflate(viewType, parent, false);
304 | switch (viewType) {
305 | case R.layout.item_image:
306 | return new ImageViewHolder(itemView);
307 | case R.layout.item_text:
308 | return new TextViewHolder(itemView);
309 | default:
310 | return null;
311 | }
312 | }
313 | }
314 |
315 | 那么 onCreateViewHolder 就可以同样简化成一行代码,如下所示:
316 |
317 | public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
318 | return ViewHolderFactory.create(parent, viewType);
319 | }
320 |
321 | 截止目前为止的代码:[`tutorial_step_2`](https://github.com/baurine/multi-type-adapter/tree/tutorial_step_2)
322 |
323 | 到目前为止,我们所做的和其它开发者所做的优化并没有什么不同,但是别着急,因为我们都还没有用上 databinding。接下来我们看看 databinding 的表现,看它是如何消除手动创建多个 ViewHolder 的。
324 |
325 | 我们要把 ImageItem 显示在 `item_image.xml` 上,把 TextItem 显示在 `item_text.xml` 上,我们分别用 databinding 的方式实现这两个 xml。在此之前,我们先来为 ImageItem 和 TextItem 填充一些数据。
326 |
327 | 借助 [unsplash](https://unsplash.it/) 提供的 url 让 ImageItem 产生随机图片 (别忘了在 AndroidManifest.xml 中加上网络访问权限),用当前日期时间作为 TextItem 的内容。
328 |
329 | // ImageItem.java
330 | public class ImageItem implements MulitTypeAdapter.IItem {
331 | @Override
332 | public int getType() {
333 | return R.layout.item_image;
334 | }
335 |
336 | ////////////////////////////////////////////////
337 | public final String url;
338 |
339 | public ImageItem() {
340 | url = "https://unsplash.it/200/200?random&" + new Random().nextInt(40);
341 | }
342 | }
343 |
344 | // TextItem.java
345 | public class TextItem implements MulitTypeAdapter.IItem {
346 | @Override
347 | public int getType() {
348 | return R.layout.item_text;
349 | }
350 |
351 | ///////////////////////////////////////////
352 | public final String content;
353 |
354 | public TextItem() {
355 | content = new Date().toString();
356 | }
357 | }
358 |
359 | `item_image.xml`:
360 |
361 |
362 |
363 |
366 |
367 |
368 |
374 |
375 |
381 |
382 |
383 |
384 | 其中 ImageView 的 imageUrl/error/placeholder 属性是使用 [强大的 BindingAdapter](https://github.com/baurine/android-data-binding-study/blob/master/note/powerful-binding-adapter.md) 实现的,代码如下:
385 |
386 | // BindingUtil.java
387 | public class BindingUtil {
388 | @BindingAdapter({"imageUrl", "error", "placeholder"})
389 | public static void loadImage(ImageView imgView,
390 | String url,
391 | Drawable error,
392 | Drawable placeholder) {
393 | Glide.with(imgView.getContext())
394 | .load(url)
395 | .error(error)
396 | .placeholder(placeholder)
397 | .into(imgView);
398 | }
399 | }
400 |
401 | `item_text.xml`:
402 |
403 |
404 |
405 |
408 |
409 |
410 |
415 |
416 |
420 |
421 |
422 |
423 | 在使用了 databinding 后,在创建 ViewHolder 时,ViewHolder 里需要保存就是不再是 itemView,而是 ViewDataBinding,每一个使用 `` 形式的 xml 布局都会被 databinding 框架自动生成一个 ViewDataBinding 类的派生类,比如 `item_image.xml` 会生成 ItemImageBinding,`item_text.xml` 会生成 ItemTextBinding,而 ViewDataBinding 是它们的基类。因此我们改写 ItemViewHolder/ImageViewHolder/TextViewHolder。
424 |
425 | public abstract class ItemViewHolder extends RecyclerView.ViewHolder {
426 | protected final ViewDataBinding binding;
427 |
428 | public ItemViewHolder(ViewDataBinding binding) {
429 | super(binding.getRoot());
430 | this.binding = binding;
431 | }
432 |
433 | public abstract void bindTo(MulitTypeAdapter.IItem item);
434 | }
435 |
436 | public class ImageViewHolder extends ItemViewHolder {
437 | public ImageViewHolder(ViewDataBinding binding) {
438 | super(binding);
439 | }
440 |
441 | public void bindTo(MulitTypeAdapter.IItem item) {
442 | ImageItem imageItem = (ImageItem) item;
443 | ((ItemImageBinding) binding).setItem(imageItem);
444 | }
445 | }
446 |
447 | public class TextViewHolder extends ItemViewHolder {
448 | public TextViewHolder(ViewDataBinding binding) {
449 | super(binding);
450 | }
451 |
452 | public void bindTo(MulitTypeAdapter.IItem item) {
453 | TextItem textItem = (TextItem) item;
454 | ((ItemTextBinding) binding).setItem(textItem);
455 | }
456 | }
457 |
458 | 此时,ViewHolderFactory 中的代码是这样的,我们要 inflate 得到 ViewDataBinding,如下所示:
459 |
460 | public class ViewHolderFactory {
461 | public static ItemViewHolder create(ViewGroup parent, int viewType) {
462 | ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
463 | viewType, parent, false);
464 | switch (viewType) {
465 | case R.layout.item_image:
466 | return new ImageViewHolder(binding);
467 | case R.layout.item_text:
468 | return new TextViewHolder(binding);
469 | default:
470 | return null;
471 | }
472 | }
473 | }
474 |
475 | 截止目前为止的代码:[`tutorial_step_3`](https://github.com/baurine/multi-type-adapter/tree/tutorial_step_3)
476 |
477 | 接下来,终于到了最关键最核心的一步,下面注意啦,我要开始变形啦。
478 |
479 | 在 ImageViewHolder 和 TextViewHolder 的 `bindTo()` 方法中,我们分别进行了两次类型转化,但是,实际上,ViewDataBinding 为我们提供了一个另外一个更通用的方法 `setVariable(int variableId, Object obj)` 来对 xml 中的变量进行赋值,注意,它的第二个参数是一个 Object。
480 |
481 | 比如,在 ImageViewHolder 中,我们持有了 `item_image.xml` 对应的 ItemImageBinding 实例对象,我们可以用自动生成的 `setItem((ImageItem)item)` 方法来进行赋值,也可以使用 `setVariable(BR.item, item)` 来进行赋值,因为这个 ViewDataBinding 实例知道,这个 xml 中 `BR.item` 对应的类型是 ImageItem,所以它会自动把 item 转化成 ImageItem 类型。我们直接来看一下 ItemImageBinding 内部是怎么来实现 `setVariable()`:
482 |
483 | public boolean setVariable(int variableId, Object variable) {
484 | switch(variableId) {
485 | case BR.item :
486 | setItem((com.baurine.multitypeadaptertutorial.item.ImageItem) variable);
487 | return true;
488 | }
489 | return false;
490 | }
491 |
492 | 可见,这个方法就是对各种 `setXyz` 方法的一层封装。而因为这个方法是由基类 ViewDataBinding 定义的,根据 OOP 的多态特性,
493 | 我们直接调用基类的 `setVariable()` 方法即可,因此,ImageViewHolder 中的 `bindTo()` 方法就可以简化成一行代码:
494 |
495 | public void bindTo(MulitTypeAdapter.IItem item) {
496 | binding.setVariable(BR.item, item);
497 | }
498 |
499 | 而对于 TextViewHolder 来说,也是一样的。
500 |
501 | 如此一来,如果我们在不同的 item xml 中使用相同的 variable name,如上例中都使用了 `name="item"`,那么 `bindTo()` 方法就可以统一成一种写法了,如上面所示。
502 |
503 | ImageViewHolder 和 TextViewHolder 从形式上已经是一样的了,那我们就没有必要实现多个 ViewHolder 了,统一用一个 ItemViewHolder 来实现,并在 `setVariable()` 后执行 `binding.executePendingBindings()` 来让 UI 马上变化:
504 |
505 | public class ItemViewHolder extends RecyclerView.ViewHolder {
506 | private final ViewDataBinding binding;
507 |
508 | public ItemViewHolder(ViewDataBinding binding) {
509 | super(binding.getRoot());
510 | this.binding = binding;
511 | }
512 |
513 | public void bindTo(MulitTypeAdapter.IItem item) {
514 | binding.setVariable(BR.item, item);
515 | binding.executePendingBindings();
516 | }
517 | }
518 |
519 | 但是我们一定要理解的是,单一 ViewHolder 的背后,是由 databinding 框架生成的多个 ViewDataBinding。总体上来说,代码量并没有减少,但对于我们开发者来说,要写的代码和逻辑确是大大减少了。
520 |
521 | 此时,ViewHolderFactory 可以简化成如下所示:
522 |
523 | public class ViewHolderFactory {
524 | public static ItemViewHolder create(ViewGroup parent, int viewType) {
525 | ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
526 | viewType, parent, false);
527 | return new ItemViewHolder(binding);
528 | }
529 | }
530 |
531 | 但是实际上,由于我们并不需要多个 ViewHolder 了,这个工厂类也就失去意义了,我们把 `create()` 这个方法移到 ItemViewHolder 中,删除 ViewHolderFactory 类,并修改 adapter 的 `onCreateViewHolder()` 方法,如下所示:
532 |
533 | // ItemViewHolder.java
534 | public static ItemViewHolder create(ViewGroup parent, int viewType) {
535 | ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
536 | viewType, parent, false);
537 | return new ItemViewHolder(binding);
538 | }
539 |
540 | // MulitTypeAdapter.java
541 | public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
542 | return ItemViewHolder.create(parent, viewType);
543 | }
544 |
545 | 更进一步,由于我们只有一个 ItemViewHolder,而且不需要对外公开,因此我们把它整体移入到 MulitTypeAdapter 类中,作为内部静态类。至此,整个 adapter 全部完成,全部代码如下所示 ([`tutorial_step_4`](https://github.com/baurine/multi-type-adapter/tree/tutorial_step_4)):
546 |
547 | public class MultiTypeAdapter extends RecyclerView.Adapter {
548 |
549 | public interface IItem {
550 | // should directly return layout
551 | int getType();
552 | }
553 |
554 | private List items = new ArrayList<>();
555 |
556 | ///////////////////////////////////////////////////////
557 |
558 | @Override
559 | public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
560 | return ItemViewHolder.create(parent, viewType);
561 | }
562 |
563 | @Override
564 | public void onBindViewHolder(ItemViewHolder holder, int position) {
565 | holder.bindTo(items.get(position));
566 | }
567 |
568 | @Override
569 | public int getItemCount() {
570 | return items.size();
571 | }
572 |
573 | @Override
574 | public int getItemViewType(int position) {
575 | return items.get(position).getType();
576 | }
577 |
578 | ///////////////////////////////////////////////////////
579 | // operate items
580 |
581 | public List getItems() {
582 | return items;
583 | }
584 |
585 | public void setItem(IItem item) {
586 | clearItems();
587 | addItem(item);
588 | }
589 |
590 | public void setItems(List items) {
591 | clearItems();
592 | addItems(items);
593 | }
594 |
595 | public void addItem(IItem item) {
596 | items.add(item);
597 | }
598 |
599 | public void addItem(IItem item, int index) {
600 | items.add(index, item);
601 | }
602 |
603 | public void addItems(List items) {
604 | this.items.addAll(items);
605 | }
606 |
607 | public void removeItem(IItem item) {
608 | items.remove(item);
609 | }
610 |
611 | public void clearItems() {
612 | items.clear();
613 | }
614 |
615 | ///////////////////////////////////////////////////
616 | static class ItemViewHolder extends RecyclerView.ViewHolder {
617 | private final ViewDataBinding binding;
618 |
619 | static ItemViewHolder create(ViewGroup parent, int viewType) {
620 | ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
621 | viewType, parent, false);
622 | return new ItemViewHolder(binding);
623 | }
624 |
625 | ItemViewHolder(ViewDataBinding binding) {
626 | super(binding.getRoot());
627 | this.binding = binding;
628 | }
629 |
630 | void bindTo(MultiTypeAdapter.IItem item) {
631 | binding.setVariable(BR.item, item);
632 | binding.executePendingBindings();
633 | }
634 | }
635 | }
636 |
637 | 从此,我们就可以和 viewholder 说拜拜了,我们的重心转移到实现一个又一个的 Item 上,而 Item 是极为轻量的。
638 |
639 | 至此,我们一步一步地实现了这个目前还不到 100 行的极简 adapter,那如何使用它来,来轻松地实现 header, footer 呢,且听 [下回](./multi-type-adapter-tutorial-2.md) 分解。
640 |
--------------------------------------------------------------------------------