├── .gitignore
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── aidl
│ └── com
│ │ └── zhpan
│ │ └── sample
│ │ └── binder
│ │ └── aidl
│ │ └── IGradeService.aidl
│ ├── java
│ └── com
│ │ └── zhpan
│ │ └── sample
│ │ ├── App.java
│ │ ├── EntryFragment.kt
│ │ ├── MainActivity.kt
│ │ ├── adapter
│ │ ├── DataAdapter.java
│ │ └── ImageAdapter.java
│ │ ├── animation
│ │ ├── AnimateEntryActivity.java
│ │ ├── propertyanim
│ │ │ ├── CircleCenter.java
│ │ │ ├── CircleCenterEvaluator.java
│ │ │ ├── InterpolatorActivity.java
│ │ │ ├── ObjectAnimationActivity.java
│ │ │ ├── PropertyEntryActivity.java
│ │ │ └── ValueAnimatorActivity.java
│ │ └── viewanim
│ │ │ └── ViewAnimationActivity.java
│ │ ├── banner3d
│ │ ├── BackgroundAdapter.kt
│ │ ├── Banner3DData.kt
│ │ ├── Banner3dActivity.kt
│ │ ├── ForegroundAdapter.kt
│ │ └── SensorLayout.java
│ │ ├── binder
│ │ ├── BinderEntryActivity.java
│ │ ├── StudentMap.java
│ │ ├── aidl
│ │ │ └── AidlActivity.java
│ │ ├── client
│ │ │ └── BinderActivity.java
│ │ ├── client2
│ │ │ ├── BinderProxy.java
│ │ │ ├── BinderProxyActivity.java
│ │ │ └── IGradeInterface.java
│ │ └── server
│ │ │ ├── AidlGradeService.java
│ │ │ ├── GradeBinder.java
│ │ │ └── GradeService.java
│ │ ├── jetpack
│ │ ├── JetpackEntryActivity.kt
│ │ ├── hilt
│ │ │ └── HiltActivity.kt
│ │ ├── lifecycle
│ │ │ ├── FragmentLifecycleActivity.kt
│ │ │ ├── LifecycleActivity.kt
│ │ │ └── LifecycleView.kt
│ │ ├── paging3
│ │ │ ├── ArticleAdapter.kt
│ │ │ ├── ArticlePagingSource.kt
│ │ │ ├── MainViewModel.kt
│ │ │ ├── PagingActivity.kt
│ │ │ └── Repository.kt
│ │ └── workmanager
│ │ │ ├── OnceTaskWorker.kt
│ │ │ └── WorkManagerActivity.kt
│ │ ├── material
│ │ └── behavior
│ │ │ ├── HeaderBehaviorActivity.kt
│ │ │ ├── HeaderFloatBehavior.java
│ │ │ ├── HeaderScrollingBehavior.java
│ │ │ └── VerticalFabBehavior.java
│ │ ├── nestedscroll
│ │ ├── NestedEntryActivity.java
│ │ ├── demo1
│ │ │ ├── FlingHelper.java
│ │ │ ├── NestedFragment.java
│ │ │ ├── NestedFragmentAdapter.java
│ │ │ ├── NestedRecyclerView.java
│ │ │ ├── NestedScrollActivity.kt
│ │ │ └── NestedScrollLayout.java
│ │ ├── demo2
│ │ │ ├── NestedScrollActivity2.kt
│ │ │ ├── ext
│ │ │ │ ├── Extentions.kt
│ │ │ │ ├── TypedValue.kt
│ │ │ │ └── ViewExtentions.kt
│ │ │ └── view
│ │ │ │ ├── BehavioralScrollView.kt
│ │ │ │ ├── BottomSheetLayout.kt
│ │ │ │ └── LinkageScrollLayout.kt
│ │ └── toolbar
│ │ │ ├── BehaviorToolbar.java
│ │ │ ├── ToolbarBehavior.java
│ │ │ └── ToolbarBehaviorActivity.kt
│ │ └── view
│ │ ├── ViewEntryActivity.kt
│ │ ├── dispatch
│ │ ├── DispatchActivity.java
│ │ ├── DispatchLayout.java
│ │ ├── DispatchView.java
│ │ └── TestLayout.java
│ │ └── viewpager2
│ │ ├── ScaleInTransformer.kt
│ │ ├── ViewPager2Container.kt
│ │ ├── activity
│ │ ├── VP2FragmentActivity.kt
│ │ ├── VP2ViewsActivity.kt
│ │ ├── VPFragmentActivity.kt
│ │ └── ViewPager2EntryActivity.kt
│ │ ├── adapter
│ │ ├── VPFragmentAdapter.java
│ │ └── ViewPager2Adapter.kt
│ │ ├── cards
│ │ ├── Card.kt
│ │ ├── CardView.kt
│ │ └── CardViewAdapter.kt
│ │ └── fragment
│ │ ├── TestFragment.kt
│ │ └── TestLifecycleFragment.kt
│ └── res
│ ├── drawable-anydpi
│ ├── ic_action_back.xml
│ └── ic_action_back_white.xml
│ ├── drawable-hdpi
│ ├── ic_action_back.png
│ └── ic_action_back_white.png
│ ├── drawable-mdpi
│ ├── bg_banner.png
│ ├── ic_action_back.png
│ └── ic_action_back_white.png
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable-xhdpi
│ ├── ic_action_back.png
│ └── ic_action_back_white.png
│ ├── drawable-xxhdpi
│ ├── background1.png
│ ├── background2.png
│ ├── background3.png
│ ├── foreground1.png
│ ├── foreground2.png
│ ├── foreground3.png
│ ├── ic_action_back.png
│ ├── ic_action_back_white.png
│ ├── mid1.png
│ ├── mid2.png
│ └── mid3.png
│ ├── drawable-xxxhdpi
│ ├── advertise.png
│ └── home_top_2.png
│ ├── drawable
│ ├── banner_indicator_focus.xml
│ ├── banner_indicator_nornal.xml
│ ├── ic_floating_add.xml
│ ├── ic_launcher_background.xml
│ └── icon.png
│ ├── layout
│ ├── activity_aidl_activity.xml
│ ├── activity_animate_entry.xml
│ ├── activity_banner_3d.xml
│ ├── activity_behavior.xml
│ ├── activity_binder.xml
│ ├── activity_binder_entry.xml
│ ├── activity_dispatch.xml
│ ├── activity_fragment.xml
│ ├── activity_fragment_lifecycle.xml
│ ├── activity_header_scale.xml
│ ├── activity_hilt.xml
│ ├── activity_interpolator.xml
│ ├── activity_jetpack_entry.xml
│ ├── activity_lifecycle.xml
│ ├── activity_main.xml
│ ├── activity_nested_enter.xml
│ ├── activity_nested_scroll.xml
│ ├── activity_nested_scroll2.xml
│ ├── activity_object_animation.xml
│ ├── activity_pager.xml
│ ├── activity_paging.xml
│ ├── activity_property_entry.xml
│ ├── activity_value_animator.xml
│ ├── activity_view_animation.xml
│ ├── activity_view_entry.xml
│ ├── activity_view_model.xml
│ ├── activity_view_pager.xml
│ ├── activity_vp_entry.xml
│ ├── activity_work_manager.xml
│ ├── behavior_tool_bar.xml
│ ├── fragment_main_entry.xml
│ ├── fragment_nested.xml
│ ├── item_3d_background.xml
│ ├── item_3d_foreground.xml
│ ├── item_3d_foreground2.xml
│ ├── item_article.xml
│ ├── item_behavior.xml
│ ├── item_card_layout.xml
│ ├── item_image.xml
│ ├── item_page.xml
│ └── layout_behavior_header.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── navigation
│ └── nav_graph.xml
│ └── values
│ ├── attrs.xml
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── zhpan
│ │ └── library
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── zhpan
│ │ │ └── library
│ │ │ ├── BaseViewBindingActivity.kt
│ │ │ ├── BaseViewBindingFragment.kt
│ │ │ ├── model
│ │ │ ├── Article.kt
│ │ │ ├── ArticleResponse.kt
│ │ │ └── response
│ │ │ │ └── BaseResponse.kt
│ │ │ ├── recyclerview
│ │ │ ├── listener
│ │ │ │ ├── ICustomClickListener.java
│ │ │ │ ├── ICustomScrollListener.java
│ │ │ │ └── IScrollListener.java
│ │ │ ├── module
│ │ │ │ └── ViewConfig.java
│ │ │ └── ui
│ │ │ │ ├── CustomAdapter.java
│ │ │ │ ├── CustomRecyclerView.java
│ │ │ │ └── ScrollWrapRecycler.java
│ │ │ ├── server
│ │ │ ├── ApiService.kt
│ │ │ └── LoggingInterceptor.kt
│ │ │ └── view
│ │ │ ├── CircleView.java
│ │ │ ├── CornerImageView.kt
│ │ │ └── ItemView.kt
│ └── res
│ │ ├── layout
│ │ ├── item_defalut_loadmore_view.xml
│ │ ├── item_defalut_refresh_view.xml
│ │ ├── item_head_foot_parent.xml
│ │ └── item_view.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── zhpan
│ └── library
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | .idea
16 | /captures
17 | .externalNativeBuild
18 |
19 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 |
4 | android {
5 | compileSdkVersion 29
6 | buildToolsVersion "29.0.3"
7 | defaultConfig {
8 | applicationId "com.zhpan.sample"
9 | minSdkVersion 21
10 | targetSdkVersion 29
11 | versionCode 1
12 | versionName "1.0"
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | compileOptions {
22 | sourceCompatibility JavaVersion.VERSION_1_8
23 | targetCompatibility JavaVersion.VERSION_1_8
24 | }
25 | kotlinOptions {
26 | jvmTarget = '1.8'
27 | }
28 | buildFeatures {
29 | viewBinding true
30 | }
31 | }
32 |
33 | dependencies {
34 | implementation fileTree(dir: 'libs', include: ['*.jar'])
35 | implementation 'androidx.appcompat:appcompat:1.3.0'
36 | implementation 'com.google.android.material:material:1.4.0-rc01'
37 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
38 | implementation 'androidx.viewpager2:viewpager2:1.0.0'
39 | implementation "androidx.core:core-ktx:1.5.0"
40 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
41 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
42 | implementation project(path: ':library')
43 | implementation "com.google.android.material:material:1.3.0"
44 | implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
45 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
46 | implementation "androidx.work:work-runtime-ktx:2.5.0"
47 | implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
48 | implementation 'com.github.zhpanvip:bannerviewpager:3.5.3'
49 | }
50 | repositories {
51 | mavenCentral()
52 | }
53 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/aidl/com/zhpan/sample/binder/aidl/IGradeService.aidl:
--------------------------------------------------------------------------------
1 | // IGradeService.aidl
2 | package com.zhpan.sample.binder.aidl;
3 |
4 | // Declare any non-default types here with import statements
5 |
6 | interface IGradeService {
7 | /**
8 | * Demonstrates some basic types that you can use as parameters
9 | * and return values in AIDL.
10 | */
11 | void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
12 | double aDouble, String aString);
13 |
14 | int getStudentGrade(String name);
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/App.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample;
2 |
3 | import android.app.Application;
4 |
5 | import androidx.lifecycle.Lifecycle;
6 | import androidx.lifecycle.LifecycleObserver;
7 | import androidx.lifecycle.OnLifecycleEvent;
8 | import androidx.lifecycle.ProcessLifecycleOwner;
9 |
10 | import com.blankj.utilcode.util.ToastUtils;
11 |
12 | /**
13 | *
14 | * Created by zhpan on 2020/1/13.
15 | * Description: ProcessLifecycleOwner.
16 | *
17 | */
18 | public class App extends Application {
19 | @Override
20 | public void onCreate() {
21 | super.onCreate();
22 | ProcessLifecycleOwner.get().getLifecycle().addObserver(new LifecycleObserver() {
23 | @OnLifecycleEvent(Lifecycle.Event.ON_START)
24 | public void onAppForeground() {
25 | ToastUtils.showShort("App已进入前台");
26 | }
27 |
28 | @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
29 | public void onBackground() {
30 | ToastUtils.showShort("App已进入后台运行");
31 | }
32 | });
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/EntryFragment.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample
2 |
3 | import android.view.View
4 | import android.view.ViewGroup
5 | import androidx.navigation.fragment.findNavController
6 | import com.zhpan.library.BaseViewBindingFragment
7 | import com.zhpan.sample.databinding.FragmentMainEntryBinding
8 |
9 | class EntryFragment : BaseViewBindingFragment() {
10 |
11 | override fun onViewBindingCreated(rootView: View?) {
12 | val navController = findNavController()
13 | binding.itemAnimation.setOnClickListener {
14 | navController.navigate(R.id.action_MainEntryFragment_to_AnimateEntryActivity)
15 | }
16 | binding.itemJetpack.setOnClickListener {
17 | navController.navigate(R.id.action_MainEntryFragment_to_JetpackEntryActivity)
18 | }
19 |
20 | binding.itemNestedScroll.setOnClickListener {
21 | navController.navigate(R.id.action_MainEntryFragment_to_NestedEntryActivity)
22 | }
23 |
24 | binding.itemView.setOnClickListener {
25 | navController.navigate(R.id.action_MainEntryFragment_to_ViewEntryActivity)
26 | }
27 |
28 | binding.itemBinder.setOnClickListener {
29 | navController.navigate(R.id.action_MainEntryFragment_to_BinderActivity)
30 | }
31 | }
32 |
33 | override fun createViewBinding(container: ViewGroup?): FragmentMainEntryBinding {
34 | return FragmentMainEntryBinding.inflate(layoutInflater)
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample
2 |
3 | import android.view.View
4 | import com.zhpan.library.BaseViewBindingActivity
5 | import com.zhpan.sample.databinding.ActivityMainBinding
6 |
7 | class MainActivity : BaseViewBindingActivity() {
8 |
9 | override fun createViewBinding(): ActivityMainBinding {
10 | return ActivityMainBinding.inflate(layoutInflater)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/adapter/DataAdapter.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.adapter;
2 |
3 | import com.zhpan.bannerview.BaseBannerAdapter;
4 | import com.zhpan.bannerview.BaseViewHolder;
5 | import com.zhpan.library.model.Article;
6 | import com.zhpan.sample.R;
7 |
8 | /**
9 | *
10 | * Created by zhangpan on 2020/4/16.
11 | * Description:
12 | *
13 | */
14 |
15 | public class DataAdapter extends BaseBannerAdapter {
16 |
17 | public DataAdapter() {
18 | for (int i = 0; i < 20; i++) {
19 | mList.add(new Article("Item " + i));
20 | }
21 | }
22 |
23 | @Override protected void bindData(BaseViewHolder holder, Article data, int position,
24 | int pageSize) {
25 | holder.setText(R.id.tv_title, data.getTitle());
26 | }
27 |
28 | @Override public int getLayoutId(int viewType) {
29 | return R.layout.item_behavior;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/adapter/ImageAdapter.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.adapter;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.ImageView;
7 | import androidx.annotation.NonNull;
8 | import androidx.recyclerview.widget.RecyclerView;
9 | import com.zhpan.library.view.CornerImageView;
10 | import com.zhpan.sample.R;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | /**
14 | * @author zhangpan
15 | * @date 2021/6/24
16 | */
17 | public class ImageAdapter extends RecyclerView.Adapter {
18 |
19 | @NonNull @NotNull @Override
20 | public TestViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) {
21 | View itemView =
22 | LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false);
23 | return new TestViewHolder(itemView);
24 | }
25 |
26 | @Override public void onBindViewHolder(@NonNull @NotNull TestViewHolder holder, int position) {
27 | holder.imageView.setBackgroundColor(
28 | holder.itemView.getContext()
29 | .getResources()
30 | .getColor(position % 2 == 0 ? R.color.red_500
31 | : R.color.green_500));
32 | }
33 |
34 | @Override public int getItemCount() {
35 | return 20;
36 | }
37 |
38 | public static class TestViewHolder extends RecyclerView.ViewHolder {
39 | CornerImageView imageView;
40 |
41 | public TestViewHolder(
42 | @NonNull @NotNull View itemView) {
43 | super(itemView);
44 | imageView = itemView.findViewById(R.id.image_view);
45 | imageView.setRoundCorner(
46 | itemView.getContext().getResources().getDimensionPixelOffset(R.dimen.dp_10));
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/animation/AnimateEntryActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.animation;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.zhpan.library.BaseViewBindingActivity;
8 | import com.zhpan.sample.R;
9 | import com.zhpan.sample.animation.propertyanim.InterpolatorActivity;
10 | import com.zhpan.sample.animation.propertyanim.PropertyEntryActivity;
11 | import com.zhpan.sample.animation.viewanim.ViewAnimationActivity;
12 | import com.zhpan.sample.databinding.ActivityAnimateEntryBinding;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | public class AnimateEntryActivity extends BaseViewBindingActivity
16 | implements
17 | View.OnClickListener {
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | binding.btnInterpolator.setOnClickListener(this);
23 | binding.btnPropertyAnimation.setOnClickListener(this);
24 | binding.btnInterpolator.setOnClickListener(this);
25 | }
26 |
27 | public void onClick(View view) {
28 | Intent intent = null;
29 | if (view.getId() == R.id.btn_view_animation) {
30 | intent = new Intent(this, ViewAnimationActivity.class);
31 | } else if (view.getId() == R.id.btn_property_animation) {
32 | intent = new Intent(this, PropertyEntryActivity.class);
33 | } else if (view.getId() == R.id.btn_interpolator) {
34 | intent = new Intent(this, InterpolatorActivity.class);
35 | }
36 | if (null != intent) {
37 | startActivity(intent);
38 | }
39 | }
40 |
41 | @NotNull @Override protected ActivityAnimateEntryBinding createViewBinding() {
42 | return ActivityAnimateEntryBinding.inflate(getLayoutInflater());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/animation/propertyanim/CircleCenter.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.animation.propertyanim;
2 |
3 |
4 | public class CircleCenter {
5 | private float CenterX;
6 | private float CenterY;
7 |
8 | public CircleCenter(float centerX, float centerY) {
9 | CenterX = centerX;
10 | CenterY = centerY;
11 | }
12 |
13 | public float getCenterX() {
14 | return CenterX;
15 | }
16 |
17 | public void setCenterX(float centerX) {
18 | CenterX = centerX;
19 | }
20 |
21 | public float getCenterY() {
22 | return CenterY;
23 | }
24 |
25 | public void setCenterY(float centerY) {
26 | CenterY = centerY;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/animation/propertyanim/CircleCenterEvaluator.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.animation.propertyanim;
2 |
3 | import android.animation.TypeEvaluator;
4 |
5 | public class CircleCenterEvaluator implements TypeEvaluator {
6 | @Override
7 | public CircleCenter evaluate(float fraction, CircleCenter startValue, CircleCenter endValue) {
8 | // x方向匀速移动
9 | float centerX = startValue.getCenterX() + fraction * (endValue.getCenterX() - startValue.getCenterX());
10 | // y方向抛物线加速移动
11 | float centerY = startValue.getCenterY() + fraction * fraction * (endValue.getCenterY() - startValue.getCenterY());
12 | return new CircleCenter(centerX, centerY);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/animation/propertyanim/InterpolatorActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.animation.propertyanim;
2 |
3 | import android.animation.AnimatorSet;
4 | import android.animation.ObjectAnimator;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.view.animation.AccelerateInterpolator;
8 | import android.view.animation.AnticipateInterpolator;
9 | import android.view.animation.BounceInterpolator;
10 | import android.view.animation.DecelerateInterpolator;
11 | import android.view.animation.OvershootInterpolator;
12 |
13 | import androidx.appcompat.app.AppCompatActivity;
14 |
15 | import com.zhpan.sample.R;
16 |
17 |
18 | public class InterpolatorActivity extends AppCompatActivity {
19 | private View mCircleView;
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_interpolator);
25 | mCircleView = findViewById(R.id.circle_view);
26 | }
27 |
28 | public void onClick(View view) {
29 | ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mCircleView,"ScaleX", 0f,1f);
30 | ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mCircleView,"ScaleY", 0f,1f);
31 | AnimatorSet animatorSet = new AnimatorSet();
32 | animatorSet.setDuration(2000);
33 |
34 | switch (view.getId()) {
35 | case R.id.btn_accelerate:
36 |
37 | objectAnimator.setInterpolator(new AccelerateInterpolator(2));
38 | objectAnimator2.setInterpolator(new AccelerateInterpolator(2));
39 | break;
40 | case R.id.btn_decelerate:
41 | objectAnimator.setInterpolator(new DecelerateInterpolator());
42 | objectAnimator2.setInterpolator(new DecelerateInterpolator());
43 | break;
44 | case R.id.btn_bounce:
45 | objectAnimator.setInterpolator(new BounceInterpolator());
46 | objectAnimator2.setInterpolator(new BounceInterpolator());
47 | break;
48 | case R.id.btn_anticipate:
49 | objectAnimator.setInterpolator(new AnticipateInterpolator());
50 | objectAnimator2.setInterpolator(new AnticipateInterpolator());
51 | break;
52 | case R.id.btn_overshoot:
53 | objectAnimator.setInterpolator(new OvershootInterpolator());
54 | objectAnimator2.setInterpolator(new OvershootInterpolator());
55 | break;
56 | }
57 | animatorSet.playTogether(objectAnimator,objectAnimator2);
58 | animatorSet.start();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/animation/propertyanim/PropertyEntryActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.animation.propertyanim;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.zhpan.library.BaseViewBindingActivity;
8 | import com.zhpan.sample.R;
9 | import com.zhpan.sample.databinding.ActivityPropertyEntryBinding;
10 | import org.jetbrains.annotations.NotNull;
11 |
12 | public class PropertyEntryActivity extends BaseViewBindingActivity implements
13 | View.OnClickListener {
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | binding.btnObjectAnimation.setOnClickListener(this);
19 | binding.btnValueAnimation.setOnClickListener(this);
20 | }
21 |
22 | @Override
23 | public void onClick(View view) {
24 | Intent intent = null;
25 | if (view.getId() == R.id.btn_value_animation) {
26 | intent = new Intent(this, ValueAnimatorActivity.class);
27 | } else if (view.getId() == R.id.btn_object_animation) {
28 | intent = new Intent(this, ObjectAnimationActivity.class);
29 | }
30 | if (intent != null) {
31 | startActivity(intent);
32 | }
33 | }
34 |
35 | @NotNull @Override protected ActivityPropertyEntryBinding createViewBinding() {
36 | return ActivityPropertyEntryBinding.inflate(getLayoutInflater());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/animation/propertyanim/ValueAnimatorActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.animation.propertyanim;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.view.animation.AccelerateDecelerateInterpolator;
7 |
8 | import androidx.appcompat.app.AppCompatActivity;
9 |
10 | import com.blankj.utilcode.util.ScreenUtils;
11 | import com.zhpan.sample.R;
12 | import com.zhpan.library.view.CircleView;
13 |
14 | public class ValueAnimatorActivity extends AppCompatActivity {
15 | private CircleView mCircleView;
16 | private ValueAnimator valueAnimator;
17 |
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_value_animator);
22 | mCircleView = findViewById(R.id.circleView);
23 | }
24 |
25 | public void startAnim(View view) {
26 | switch (view.getId()) {
27 | case R.id.button:
28 | ofArgb();
29 | break;
30 | case R.id.button2:
31 | ofObject();
32 | break;
33 | }
34 | }
35 |
36 | private void ofArgb() {
37 | valueAnimator = ValueAnimator.ofArgb(0xffff0000, 0xff00ff00);
38 | valueAnimator.setDuration(3000);
39 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
40 | @Override
41 | public void onAnimationUpdate(ValueAnimator animation) {
42 | int color = (int) animation.getAnimatedValue();
43 | mCircleView.setCirCleColor(color);
44 | }
45 | });
46 | valueAnimator.start();
47 | }
48 |
49 | private void ofObject() {
50 | CircleCenter startValue = new CircleCenter(0, 150);
51 | CircleCenter endValue = new CircleCenter(ScreenUtils.getScreenWidth(), ScreenUtils.getScreenHeight());
52 | valueAnimator = ValueAnimator.ofObject(new CircleCenterEvaluator(), startValue, endValue);
53 | valueAnimator.setDuration(3000);
54 | valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
55 | valueAnimator.setEvaluator(new CircleCenterEvaluator());
56 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
57 | @Override
58 | public void onAnimationUpdate(ValueAnimator animation) {
59 | CircleCenter circleCenter = (CircleCenter) animation.getAnimatedValue();
60 | mCircleView.setX(circleCenter.getCenterX());
61 | mCircleView.setY(circleCenter.getCenterY());
62 | mCircleView.invalidate();
63 | }
64 | });
65 | valueAnimator.start();
66 |
67 | }
68 |
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/banner3d/BackgroundAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.banner3d
2 |
3 | import android.widget.ImageView
4 | import com.zhpan.bannerview.BaseBannerAdapter
5 | import com.zhpan.bannerview.BaseViewHolder
6 | import com.zhpan.sample.R
7 | import com.zhpan.sample.banner3d.SensorLayout.DIRECTION_RIGHT
8 |
9 | /**
10 | *
11 | * @author zhangpan
12 | * @date 2021/7/29
13 | */
14 | class BackgroundAdapter : BaseBannerAdapter() {
15 |
16 | override fun bindData(
17 | holder: BaseViewHolder?,
18 | data: Banner3DData?,
19 | position: Int,
20 | pageSize: Int
21 | ) {
22 | holder?.findViewById(R.id.iv_background)?.setImageResource(data?.background!!)
23 | }
24 |
25 | override fun getLayoutId(viewType: Int): Int {
26 | return R.layout.item_3d_background
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/banner3d/Banner3DData.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.banner3d
2 |
3 | /**
4 | *
5 | * @author zhangpan
6 | * @date 2021/7/29
7 | */
8 | class Banner3DData(background: Int, mid: Int, foreground: Int) {
9 | var background: Int? = background
10 | var mid: Int? = mid
11 | var foreground: Int? = foreground
12 | var type: Int = 0
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/banner3d/Banner3dActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.banner3d
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import android.view.View
6 | import android.widget.ImageView
7 | import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
8 | import com.zhpan.bannerview.BannerViewPager
9 | import com.zhpan.bannerview.constants.IndicatorGravity
10 | import com.zhpan.indicator.IndicatorView
11 | import com.zhpan.indicator.base.IIndicator
12 | import com.zhpan.indicator.enums.IndicatorSlideMode
13 | import com.zhpan.indicator.enums.IndicatorStyle
14 | import com.zhpan.sample.R
15 |
16 | class Banner3dActivity : AppCompatActivity() {
17 |
18 | private lateinit var mBannerForeground: BannerViewPager
19 | private lateinit var mIvBackGround: ImageView
20 |
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | setContentView(R.layout.activity_banner_3d)
24 | mBannerForeground = findViewById(R.id.bvp_foreground)
25 | mIvBackGround = findViewById(R.id.iv_background)
26 |
27 | val arrayList = ArrayList()
28 | arrayList.add(Banner3DData(R.drawable.background1, R.drawable.mid1, R.drawable.foreground1))
29 | arrayList.add(Banner3DData(R.drawable.background2, R.drawable.mid2, R.drawable.foreground2))
30 | val banner3DData =
31 | Banner3DData(R.drawable.background3, R.drawable.mid3, R.drawable.foreground3)
32 | banner3DData.type = 1
33 | arrayList.add(banner3DData)
34 | mIvBackGround.setImageResource(arrayList[0].background!!)
35 |
36 | mBannerForeground.apply {
37 | adapter = ForegroundAdapter()
38 | setAutoPlay(true)
39 | setIndicatorStyle(IndicatorStyle.ROUND_RECT)
40 | setIndicatorSlideMode(IndicatorSlideMode.COLOR)
41 | setIndicatorSliderWidth(
42 | resources.getDimensionPixelOffset(R.dimen.dp_9)
43 | )
44 | setIndicatorHeight(resources.getDimensionPixelOffset(R.dimen.dp_3))
45 | setIndicatorMargin(0, 0, resources.getDimensionPixelOffset(R.dimen.dp_16), 0)
46 | setIndicatorSliderColor(
47 | resources.getColor(R.color.gray_BB),
48 | resources.getColor(R.color.dark_gray)
49 | )
50 | setIndicatorGravity(IndicatorGravity.END)
51 | setScrollDuration(800)
52 | setIndicatorSliderGap(resources.getDimensionPixelOffset(R.dimen.dp_5))
53 | }.registerOnPageChangeCallback(object : OnPageChangeCallback() {
54 | override fun onPageSelected(position: Int) {
55 | val banner3DData = mBannerForeground.data[position]
56 | mIvBackGround.setImageResource(banner3DData?.background!!)
57 | }
58 | }).create(arrayList)
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/banner3d/ForegroundAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.banner3d
2 |
3 | import android.widget.ImageView
4 | import com.zhpan.bannerview.BaseBannerAdapter
5 | import com.zhpan.bannerview.BaseViewHolder
6 | import com.zhpan.sample.R
7 | import com.zhpan.sample.banner3d.SensorLayout.DIRECTION_RIGHT
8 |
9 | /**
10 | *
11 | * @author zhangpan
12 | * @date 2021/7/29
13 | */
14 | class ForegroundAdapter : BaseBannerAdapter() {
15 |
16 | override fun bindData(
17 | holder: BaseViewHolder?,
18 | data: Banner3DData?,
19 | position: Int,
20 | pageSize: Int
21 | ) {
22 | holder?.findViewById(R.id.sensor_layout)?.setDirection(DIRECTION_RIGHT)
23 | holder?.findViewById(R.id.iv_mid)?.setImageResource(data?.mid!!)
24 | holder?.findViewById(R.id.iv_foreground)?.setImageResource(data?.foreground!!)
25 | }
26 |
27 | override fun getViewType(position: Int): Int {
28 | return mList[position].type
29 | }
30 |
31 | override fun getLayoutId(viewType: Int): Int {
32 | if(viewType==1){
33 | return R.layout.item_3d_foreground2
34 | }
35 | return R.layout.item_3d_foreground
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/binder/BinderEntryActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.binder;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 |
6 | import com.zhpan.library.BaseViewBindingActivity;
7 | import com.zhpan.sample.binder.aidl.AidlActivity;
8 | import com.zhpan.sample.binder.client.BinderActivity;
9 | import com.zhpan.sample.binder.client2.BinderProxyActivity;
10 | import com.zhpan.sample.databinding.ActivityBinderEntryBinding;
11 |
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | public class BinderEntryActivity extends BaseViewBindingActivity {
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | binding.itemBinder.setOnClickListener(v ->
20 | startActivity(new Intent(BinderEntryActivity.this, BinderActivity.class)));
21 | binding.itemBinderProxy.setOnClickListener(v ->
22 | startActivity(new Intent(BinderEntryActivity.this, BinderProxyActivity.class)));
23 | binding.itemAidl.setOnClickListener(v ->
24 | startActivity(new Intent(BinderEntryActivity.this, AidlActivity.class)));
25 | }
26 |
27 | @NotNull
28 | @Override
29 | protected ActivityBinderEntryBinding createViewBinding() {
30 | return ActivityBinderEntryBinding.inflate(getLayoutInflater());
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/binder/StudentMap.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.binder;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | /**
7 | * @author zhangpan
8 | * @date 2021/7/20
9 | */
10 | public class StudentMap {
11 |
12 | private static Map map;
13 |
14 | public static int getStudentGrade(String name) {
15 | if (map == null) {
16 | map = new HashMap<>();
17 | map.put("Andy", 96);
18 | map.put("Frank", 89);
19 | map.put("Anna", 92);
20 | }
21 | if (map.get(name) == null) {
22 | return 0;
23 | }
24 | return map.get(name);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/binder/aidl/AidlActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.binder.aidl;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Intent;
5 | import android.content.ServiceConnection;
6 | import android.os.Bundle;
7 | import android.os.IBinder;
8 | import android.os.RemoteException;
9 |
10 | import com.blankj.utilcode.util.ToastUtils;
11 | import com.zhpan.library.BaseViewBindingActivity;
12 | import com.zhpan.sample.databinding.ActivityBinderBinding;
13 |
14 | import org.jetbrains.annotations.NotNull;
15 |
16 | public class AidlActivity extends BaseViewBindingActivity {
17 |
18 | private IGradeService mBinderProxy;
19 |
20 | private final ServiceConnection mServiceConnection = new ServiceConnection() {
21 | @Override
22 | public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
23 | mBinderProxy = IGradeService.Stub.asInterface(iBinder);
24 | ToastUtils.showShort("已连接远程服务,可以查询成绩了。");
25 | }
26 |
27 | @Override
28 | public void onServiceDisconnected(ComponentName componentName) {
29 | mBinderProxy = null;
30 | ToastUtils.showShort("已断开远程服务");
31 | }
32 | };
33 |
34 | @Override
35 | protected void onCreate(Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 | binding.btnBindService.setOnClickListener(view -> bindGradeService());
38 | binding.btnFindGrade.setOnClickListener(view -> getStudentGrade("Anna"));
39 | }
40 |
41 | private void getStudentGrade(String name) {
42 | int grade = 0;
43 | try {
44 | grade = mBinderProxy.getStudentGrade(name);
45 | } catch (RemoteException e) {
46 | e.printStackTrace();
47 | }
48 | ToastUtils.showShort("Anna grade is " + grade);
49 | }
50 |
51 | private void bindGradeService() {
52 | String action = "android.intent.action.server.aidl.gradeservice";
53 | Intent intent = new Intent(action);
54 | intent.setPackage(getPackageName());
55 | bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
56 | }
57 |
58 | @NotNull
59 | @Override
60 | protected ActivityBinderBinding createViewBinding() {
61 | return ActivityBinderBinding.inflate(getLayoutInflater());
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/binder/client/BinderActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.binder.client;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Intent;
5 | import android.content.ServiceConnection;
6 | import android.os.Bundle;
7 | import android.os.IBinder;
8 | import android.os.Parcel;
9 | import android.os.RemoteException;
10 |
11 | import com.blankj.utilcode.util.ToastUtils;
12 | import com.zhpan.library.BaseViewBindingActivity;
13 | import com.zhpan.sample.databinding.ActivityBinderBinding;
14 |
15 | import org.jetbrains.annotations.NotNull;
16 |
17 | import static com.zhpan.sample.binder.server.GradeService.REQUEST_CODE;
18 |
19 | public class BinderActivity extends BaseViewBindingActivity {
20 |
21 | private IBinder mRemoteBinder;
22 |
23 | private final ServiceConnection mServiceConnection = new ServiceConnection() {
24 | @Override
25 | public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
26 | mRemoteBinder = iBinder;
27 | ToastUtils.showShort("已连接远程服务,可以查询成绩了。");
28 | }
29 |
30 | @Override
31 | public void onServiceDisconnected(ComponentName componentName) {
32 | mRemoteBinder = null;
33 | ToastUtils.showShort("已断开远程服务");
34 | }
35 | };
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | binding.btnBindService.setOnClickListener(view -> bindGradeService());
41 | binding.btnFindGrade.setOnClickListener(view -> ToastUtils.showShort("Anna grade is "
42 | + getStudentGrade("Anna")));
43 | }
44 |
45 | private void bindGradeService() {
46 | String action = "android.intent.action.server.gradeservice";
47 | Intent intent = new Intent(action);
48 | intent.setPackage(getPackageName());
49 | bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
50 | }
51 |
52 | private int getStudentGrade(String name) {
53 | Parcel data = Parcel.obtain();
54 | Parcel reply = Parcel.obtain();
55 | int grade = 0;
56 | data.writeString(name);
57 | try {
58 | if (mRemoteBinder == null) {
59 | throw new IllegalStateException("Need Bind Remote Server...");
60 | }
61 | mRemoteBinder.transact(REQUEST_CODE, data, reply, 0);
62 | grade = reply.readInt();
63 | } catch (RemoteException e) {
64 | e.printStackTrace();
65 | }
66 | return grade;
67 | }
68 |
69 | @NotNull
70 | @Override
71 | protected ActivityBinderBinding createViewBinding() {
72 | return ActivityBinderBinding.inflate(getLayoutInflater());
73 | }
74 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/binder/client2/BinderProxy.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.binder.client2;
2 |
3 | import android.os.IBinder;
4 | import android.os.Parcel;
5 | import android.os.RemoteException;
6 |
7 | import com.blankj.utilcode.util.LogUtils;
8 |
9 | import static com.zhpan.sample.binder.server.GradeService.REQUEST_CODE;
10 |
11 | /**
12 | * @author zhangpan
13 | * @date 2021/7/20
14 | */
15 | public class BinderProxy implements IGradeInterface {
16 | private final IBinder mBinder;
17 |
18 | private BinderProxy(IBinder binder) {
19 | mBinder = binder;
20 | }
21 |
22 | @Override
23 | public int getStudentGrade(String name) {
24 | Parcel data = Parcel.obtain();
25 | Parcel reply = Parcel.obtain();
26 | int grade = 0;
27 | data.writeString(name);
28 | try {
29 | if (mBinder == null) {
30 | throw new IllegalStateException("Need Bind Remote Server...");
31 | }
32 | mBinder.transact(REQUEST_CODE, data, reply, 0);
33 | grade = reply.readInt();
34 | } catch (RemoteException e) {
35 | e.printStackTrace();
36 | }
37 | return grade;
38 | }
39 |
40 | public static IGradeInterface asInterface(IBinder iBinder) {
41 | if (iBinder == null) {
42 | return null;
43 | }
44 | if (iBinder instanceof IGradeInterface) {
45 | LogUtils.e("当前进程");
46 | return (IGradeInterface) iBinder;
47 | } else {
48 | LogUtils.e("远程进程");
49 | return new BinderProxy(iBinder);
50 | }
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/binder/client2/BinderProxyActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.binder.client2;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Intent;
5 | import android.content.ServiceConnection;
6 | import android.os.Bundle;
7 | import android.os.IBinder;
8 |
9 | import com.blankj.utilcode.util.ToastUtils;
10 | import com.zhpan.library.BaseViewBindingActivity;
11 |
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import com.zhpan.sample.databinding.ActivityBinderBinding;
15 |
16 |
17 | public class BinderProxyActivity extends BaseViewBindingActivity {
18 |
19 | private IGradeInterface mBinderProxy;
20 |
21 | private final ServiceConnection mServiceConnection = new ServiceConnection() {
22 | @Override
23 | public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
24 | mBinderProxy = BinderProxy.asInterface(iBinder);
25 | ToastUtils.showShort("已连接远程服务,可以查询成绩了。");
26 | }
27 |
28 | @Override
29 | public void onServiceDisconnected(ComponentName componentName) {
30 | mBinderProxy = null;
31 | ToastUtils.showShort("已断开远程服务");
32 | }
33 | };
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | binding.btnBindService.setOnClickListener(view -> bindGradeService());
39 | binding.btnFindGrade.setOnClickListener(view -> ToastUtils.showShort("Anna grade is "
40 | + mBinderProxy.getStudentGrade("Anna")));
41 | }
42 |
43 |
44 | private void bindGradeService() {
45 | String action = "android.intent.action.server.gradeservice";
46 | Intent intent = new Intent(action);
47 | intent.setPackage(getPackageName());
48 | bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
49 | }
50 |
51 | @NotNull
52 | @Override
53 | protected ActivityBinderBinding createViewBinding() {
54 | return ActivityBinderBinding.inflate(getLayoutInflater());
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/binder/client2/IGradeInterface.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.binder.client2;
2 |
3 | /**
4 | * @author zhangpan
5 | * @date 2021/7/20
6 | */
7 | public interface IGradeInterface {
8 | int getStudentGrade(String name);
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/binder/server/AidlGradeService.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.binder.server;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.IBinder;
6 | import android.os.RemoteException;
7 |
8 | import androidx.annotation.Nullable;
9 |
10 | import com.zhpan.sample.binder.StudentMap;
11 | import com.zhpan.sample.binder.aidl.IGradeService;
12 | import com.zhpan.sample.binder.server.GradeBinder;
13 |
14 |
15 | /**
16 | * @author zhangpan
17 | * @date 2021/7/20
18 | */
19 | public class AidlGradeService extends Service {
20 |
21 | private final IBinder mBinder = new IGradeService.Stub() {
22 | @Override
23 | public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
24 |
25 | }
26 |
27 | @Override
28 | public int getStudentGrade(String name) throws RemoteException {
29 | return StudentMap.getStudentGrade(name);
30 | }
31 | };
32 |
33 | @Nullable
34 | @Override
35 | public IBinder onBind(Intent intent) {
36 | return mBinder;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/binder/server/GradeBinder.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.binder.server;
2 |
3 | import android.os.Binder;
4 | import android.os.Parcel;
5 | import android.os.RemoteException;
6 |
7 | import androidx.annotation.NonNull;
8 | import androidx.annotation.Nullable;
9 |
10 | import com.zhpan.sample.binder.StudentMap;
11 | import com.zhpan.sample.binder.client2.IGradeInterface;
12 |
13 | import static com.zhpan.sample.binder.server.GradeService.REQUEST_CODE;
14 |
15 | /**
16 | * @author zhangpan
17 | * @date 2021/7/20
18 | */
19 | public class GradeBinder extends Binder implements IGradeInterface {
20 |
21 | @Override
22 | public int getStudentGrade(String name) {
23 | return StudentMap.getStudentGrade(name);
24 | }
25 |
26 | @Override
27 | protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
28 | if (code == REQUEST_CODE) {
29 | String name = data.readString();
30 | int studentGrade = getStudentGrade(name);
31 | if (reply != null)
32 | reply.writeInt(studentGrade);
33 | return true;
34 | }
35 | return super.onTransact(code, data, reply, flags);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/binder/server/GradeService.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.binder.server;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.Binder;
6 | import android.os.IBinder;
7 | import android.os.Parcel;
8 | import android.os.RemoteException;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.annotation.Nullable;
12 |
13 | import com.zhpan.sample.binder.StudentMap;
14 |
15 |
16 | /**
17 | * @author zhangpan
18 | * @date 2021/7/20
19 | */
20 | public class GradeService extends Service {
21 |
22 | public static final int REQUEST_CODE=1000;
23 |
24 | @Nullable
25 | @Override
26 | public IBinder onBind(Intent intent) {
27 | return new GradeBinder();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/JetpackEntryActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import com.zhpan.library.BaseViewBindingActivity
6 | import com.zhpan.sample.banner3d.Banner3dActivity
7 | import com.zhpan.sample.databinding.ActivityJetpackEntryBinding
8 | import com.zhpan.sample.jetpack.lifecycle.LifecycleActivity
9 | import com.zhpan.sample.jetpack.paging3.PagingActivity
10 | import com.zhpan.sample.jetpack.workmanager.WorkManagerActivity
11 |
12 | class JetpackEntryActivity : BaseViewBindingActivity() {
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | binding.itemLifecycle.setOnClickListener {
16 | startActivity(Intent(this, LifecycleActivity::class.java))
17 | }
18 | binding.itemPaging.setOnClickListener {
19 | startActivity(Intent(this, PagingActivity::class.java))
20 | }
21 | binding.itemWorkManager.setOnClickListener {
22 | startActivity(Intent(this, WorkManagerActivity::class.java))
23 | }
24 | }
25 |
26 | override fun createViewBinding(): ActivityJetpackEntryBinding {
27 | return ActivityJetpackEntryBinding.inflate(layoutInflater)
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/hilt/HiltActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.hilt
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import com.zhpan.sample.R
6 |
7 | class HiltActivity : AppCompatActivity() {
8 | override fun onCreate(savedInstanceState: Bundle?) {
9 | super.onCreate(savedInstanceState)
10 | setContentView(R.layout.activity_hilt)
11 | }
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/lifecycle/FragmentLifecycleActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.lifecycle
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import android.view.View
6 | import androidx.fragment.app.Fragment
7 | import androidx.lifecycle.Lifecycle
8 | import androidx.viewpager2.integration.testapp.cards.Card
9 | import com.zhpan.sample.R
10 | import com.zhpan.sample.view.viewpager2.fragment.TestLifecycleFragment
11 |
12 | class FragmentLifecycleActivity : AppCompatActivity() {
13 | private lateinit var fragment: Fragment
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setContentView(R.layout.activity_fragment_lifecycle)
17 | fragment = TestLifecycleFragment.getInstance(Card.DECK[0], 0)
18 | val fragmentTransaction = supportFragmentManager.beginTransaction()
19 | fragmentTransaction.add(R.id.ll_fragment, fragment)
20 | // fragmentTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED)
21 | fragmentTransaction.commit()
22 | }
23 |
24 | fun onClick(view: View) {
25 | val maxLifecycle: Lifecycle.State = when (view.id) {
26 | R.id.btn_created -> Lifecycle.State.CREATED
27 | R.id.btn_started -> Lifecycle.State.STARTED
28 | else -> Lifecycle.State.RESUMED
29 | }
30 | setMaxLifecycle(maxLifecycle)
31 | }
32 |
33 | private fun setMaxLifecycle(created: Lifecycle.State) {
34 | val fragmentTransaction = supportFragmentManager.beginTransaction()
35 | fragmentTransaction.setMaxLifecycle(fragment, created)
36 | fragmentTransaction.commit()
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/lifecycle/LifecycleActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.lifecycle
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 |
5 | import android.os.Bundle
6 |
7 | import com.zhpan.sample.R
8 |
9 | class LifecycleActivity : AppCompatActivity() {
10 |
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | setContentView(R.layout.activity_lifecycle)
14 | val lifecycleView=findViewById(R.id.lifecycle_view)
15 | lifecycle.addObserver(lifecycleView)
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/lifecycle/LifecycleView.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.lifecycle
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import androidx.lifecycle.Lifecycle
7 | import androidx.lifecycle.LifecycleObserver
8 | import androidx.lifecycle.OnLifecycleEvent
9 |
10 | import com.blankj.utilcode.util.LogUtils
11 |
12 | /**
13 | *
14 | * Created by zhangpan on 2020-01-10.
15 | * Description:
16 |
*
17 | */
18 | class LifecycleView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr), LifecycleObserver {
19 |
20 |
21 | @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
22 | internal fun onPause() {
23 | LogUtils.e("LifecycleView onPause")
24 | }
25 |
26 | @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
27 | internal fun onResume() {
28 | LogUtils.e("LifecycleView onResume")
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/paging3/ArticleAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.paging3
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.TextView
7 | import androidx.paging.PagingDataAdapter
8 | import androidx.recyclerview.widget.DiffUtil
9 | import androidx.recyclerview.widget.RecyclerView
10 | import com.zhpan.sample.R
11 | import com.zhpan.sample.jetpack.paging3.ArticleAdapter.ArticleViewHolder
12 | import com.zhpan.library.model.Article
13 |
14 | /**
15 | *
16 | * @author zhangpan
17 | * @date 2021/3/23
18 | */
19 | class ArticleAdapter : PagingDataAdapter(COMPARATOR) {
20 |
21 | companion object {
22 | private val COMPARATOR = object : DiffUtil.ItemCallback() {
23 | override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
24 | return oldItem.link == newItem.link
25 | }
26 |
27 | override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
28 | return oldItem == newItem
29 | }
30 |
31 | }
32 | }
33 |
34 | class ArticleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
35 | val title: TextView = itemView.findViewById(R.id.tv_title)
36 | val authorName: TextView = itemView.findViewById(R.id.tv_auther)
37 | }
38 |
39 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
40 | val view = LayoutInflater.from(parent.context).inflate(R.layout.item_article, parent, false)
41 | return ArticleViewHolder(view)
42 | }
43 |
44 | override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
45 |
46 | val item = getItem(position)
47 | if (item != null) {
48 | holder.title.text = item.title
49 | holder.authorName.text = item.author
50 | }
51 | }
52 |
53 |
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/paging3/ArticlePagingSource.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.paging3
2 |
3 | import androidx.paging.PagingSource
4 | import androidx.paging.PagingState
5 | import com.zhpan.library.model.Article
6 | import com.zhpan.library.server.ApiService
7 | import java.lang.Exception
8 |
9 | /**
10 | *
11 | * @author zhangpan
12 | * @date 2021/3/23
13 | */
14 | class ArticlePagingSource(private val apiService: ApiService) : PagingSource() {
15 |
16 | override suspend fun load(params: LoadParams): LoadResult {
17 | return try {
18 | val page = params.key ?: 0
19 | val articleResponse = apiService.getHomeArticles(page)
20 | val articleList = articleResponse.data?.datas
21 | val preKey = if (page > 0) page - 1 else null
22 | val nextKey = if (articleList!!.isEmpty()) null else page + 1
23 | LoadResult.Page(articleList, preKey, nextKey)
24 | } catch (e: Exception) {
25 | LoadResult.Error(e)
26 | }
27 | }
28 |
29 | override fun getRefreshKey(state: PagingState): Int? = null
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/paging3/MainViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.paging3
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import androidx.paging.PagingData
6 | import androidx.paging.cachedIn
7 | import com.zhpan.library.model.Article
8 | import kotlinx.coroutines.flow.Flow
9 |
10 | /**
11 | * @author zhangpan
12 | * @date 2021/3/23
13 | */
14 | internal class MainViewModel : ViewModel() {
15 | fun fetchPagingData(): Flow> {
16 | return Repository.fetchPagingData().cachedIn(viewModelScope)
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/paging3/PagingActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.paging3
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import android.widget.ProgressBar
6 | import android.widget.Toast
7 | import androidx.appcompat.app.AppCompatActivity
8 | import androidx.lifecycle.ViewModelProvider
9 | import androidx.lifecycle.lifecycleScope
10 | import androidx.paging.LoadState
11 | import androidx.recyclerview.widget.DividerItemDecoration
12 | import androidx.recyclerview.widget.LinearLayoutManager
13 | import androidx.recyclerview.widget.RecyclerView
14 | import com.zhpan.sample.R
15 | import kotlinx.coroutines.flow.collect
16 | import kotlinx.coroutines.launch
17 |
18 | class PagingActivity : AppCompatActivity() {
19 | private val viewModel by lazy { ViewModelProvider(this).get(MainViewModel::class.java) }
20 | private val articleAdapter = ArticleAdapter()
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | setContentView(R.layout.activity_paging)
24 | title = "Paging"
25 | val recyclerView = findViewById(R.id.recycler_view)
26 | recyclerView.addItemDecoration(DividerItemDecoration(this@PagingActivity, DividerItemDecoration.VERTICAL))
27 | val progressBar = findViewById(R.id.progress_bar)
28 | recyclerView.layoutManager = LinearLayoutManager(this)
29 | recyclerView.adapter = articleAdapter
30 | lifecycleScope.launch {
31 | viewModel.fetchPagingData().collect { pagingData ->
32 | articleAdapter.submitData(pagingData)
33 | }
34 | }
35 | articleAdapter.addLoadStateListener {
36 | when (it.refresh) {
37 | is LoadState.NotLoading -> {
38 | progressBar.visibility = View.INVISIBLE
39 | recyclerView.visibility = View.VISIBLE
40 | }
41 | is LoadState.Loading -> {
42 | progressBar.visibility = View.VISIBLE
43 | recyclerView.visibility = View.INVISIBLE
44 | }
45 | is LoadState.Error -> {
46 | val state = it.refresh as LoadState.Error
47 | progressBar.visibility = View.INVISIBLE
48 | Toast.makeText(this, "Load Error: ${state.error.message}", Toast.LENGTH_SHORT).show()
49 | }
50 |
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/paging3/Repository.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.paging3
2 |
3 | import androidx.paging.Pager
4 | import androidx.paging.PagingConfig
5 | import androidx.paging.PagingData
6 | import com.zhpan.library.model.Article
7 | import com.zhpan.library.server.ApiService
8 | import kotlinx.coroutines.flow.Flow
9 |
10 | /**
11 | *
12 | * @author zhangpan
13 | * @date 2021/3/23
14 | */
15 | object Repository {
16 | private const val PAGE_SIZE = 50
17 | private val apiService = ApiService.create()
18 |
19 | fun fetchPagingData(): Flow> {
20 | return Pager(config = PagingConfig(PAGE_SIZE), pagingSourceFactory = { ArticlePagingSource(apiService) }).flow
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/workmanager/OnceTaskWorker.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.workmanager
2 |
3 | import android.content.Context
4 | import androidx.work.Worker
5 | import androidx.work.WorkerParameters
6 | import com.blankj.utilcode.util.LogUtils
7 | import com.blankj.utilcode.util.ToastUtils
8 |
9 | /**
10 | * @author zhangpan
11 | * @date 2021/6/28
12 | */
13 | class OnceTaskWorker(
14 | context: Context,
15 | workerParams: WorkerParameters
16 | ) : Worker(context, workerParams) {
17 | override fun doWork(): Result {
18 | try {
19 | ToastUtils.showShort("MyWorker is start")
20 | LogUtils.e("MyWorker is start")
21 | Thread.sleep(4000)
22 | LogUtils.e("MyWorker finished")
23 | ToastUtils.showShort("MyWorker finished")
24 | } catch (e: InterruptedException) {
25 | e.printStackTrace()
26 | return Result.failure()
27 | }
28 | return Result.success()
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/jetpack/workmanager/WorkManagerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.jetpack.workmanager
2 |
3 | import android.os.Bundle
4 | import androidx.work.Constraints
5 | import androidx.work.NetworkType
6 | import androidx.work.OneTimeWorkRequest
7 | import androidx.work.OneTimeWorkRequest.Builder
8 | import androidx.work.PeriodicWorkRequest
9 | import androidx.work.WorkManager
10 | import com.blankj.utilcode.util.LogUtils
11 | import com.zhpan.library.BaseViewBindingActivity
12 | import com.zhpan.sample.databinding.ActivityWorkManagerBinding
13 | import java.util.concurrent.TimeUnit
14 |
15 | class WorkManagerActivity : BaseViewBindingActivity() {
16 |
17 | companion object {
18 | const val PERIOD_TAG = "period_task";
19 | }
20 |
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | // 执行单次任务
24 | binding.btnUsage.setOnClickListener {
25 | val oneTimeWorkRequest = Builder(OnceTaskWorker::class.java).build()
26 | WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)
27 | }
28 |
29 | // 执行周期任务
30 | binding.btnPeriod.setOnClickListener {
31 | // 制定一个每隔15分钟执行一次的Request
32 | val periodicWorkRequest =
33 | PeriodicWorkRequest.Builder(OnceTaskWorker::class.java, 15, TimeUnit.MINUTES)
34 | .addTag(PERIOD_TAG)
35 | .build()
36 | // 监听状态
37 | WorkManager.getInstance(this).getWorkInfoByIdLiveData(periodicWorkRequest.id)
38 | .observe(this, { workInfo ->
39 | LogUtils.d("状态:" + workInfo?.state?.name) // 这里只会是状态只会是ENQUEUE,因为是周期任务。
40 | if (workInfo?.state?.isFinished == true) {
41 | LogUtils.d("状态:isFinished=true 后台任务已经完成了...")
42 | }
43 | })
44 |
45 | WorkManager.getInstance(this).enqueue(periodicWorkRequest)
46 | }
47 |
48 | binding.btnStopPeriod.setOnClickListener {
49 | WorkManager.getInstance(this).cancelAllWorkByTag(PERIOD_TAG)
50 | }
51 |
52 | // 添加约束条件,必须满足条件,才能执行后台任务 (在连接网络,插入电源 并且 处于空闲时)
53 | binding.btnConstraints.setOnClickListener {
54 | val constraints: Constraints = Constraints.Builder()
55 | .setRequiredNetworkType(NetworkType.CONNECTED) // 网络已连接
56 | // .setRequiresCharging(true) // 充电中..
57 | // .setRequiresDeviceIdle(true) // 空闲时
58 | .build()
59 |
60 | val request = Builder(OnceTaskWorker::class.java)
61 | .setConstraints(constraints) // Request关联 约束条件
62 | .build()
63 |
64 | WorkManager.getInstance(this).enqueue(request)
65 | }
66 | }
67 |
68 | override fun createViewBinding(): ActivityWorkManagerBinding {
69 | return ActivityWorkManagerBinding.inflate(layoutInflater)
70 | }
71 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/material/behavior/HeaderBehaviorActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.material.behavior
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.recyclerview.widget.DividerItemDecoration
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.zhpan.sample.R
8 | import com.zhpan.sample.adapter.DataAdapter
9 |
10 | class HeaderBehaviorActivity : AppCompatActivity() {
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | setContentView(R.layout.activity_header_scale)
14 | val recyclerView=findViewById(R.id.recyclerView)
15 | recyclerView.addItemDecoration(DividerItemDecoration(this,
16 | DividerItemDecoration.VERTICAL))
17 | recyclerView.adapter = DataAdapter()
18 | }
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/material/behavior/HeaderFloatBehavior.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.material.behavior;
2 |
3 | import android.animation.ArgbEvaluator;
4 | import android.content.Context;
5 | import android.content.res.Resources;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import androidx.coordinatorlayout.widget.CoordinatorLayout;
11 |
12 | import com.zhpan.sample.R;
13 |
14 | import java.lang.ref.WeakReference;
15 |
16 | /**
17 | * @author zhangpan
18 | * @date 2021/2/3
19 | */
20 | public class HeaderFloatBehavior extends CoordinatorLayout.Behavior {
21 |
22 | private WeakReference dependentView;
23 | private final ArgbEvaluator argbEvaluator;
24 |
25 | public HeaderFloatBehavior(Context context, AttributeSet attrs) {
26 | super(context, attrs);
27 |
28 | argbEvaluator = new ArgbEvaluator();
29 | }
30 |
31 | @Override
32 | public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
33 | if (dependency != null && dependency.getId() == R.id.scrolling_header) {
34 | dependentView = new WeakReference<>(dependency);
35 | return true;
36 | }
37 | return false;
38 | }
39 |
40 | @Override
41 | public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
42 | Resources resources = getDependentView().getResources();
43 | final float progress = 1.f -
44 | Math.abs(dependency.getTranslationY() / (dependency.getHeight() - resources.getDimension(R.dimen.collapsed_header_height)));
45 |
46 | // Translation
47 | final float collapsedOffset = resources.getDimension(R.dimen.collapsed_float_offset_y);
48 | final float initOffset = resources.getDimension(R.dimen.init_float_offset_y);
49 | final float translateY = collapsedOffset + (initOffset - collapsedOffset) * progress;
50 | child.setTranslationY(translateY);
51 |
52 | // Background
53 | child.setBackgroundColor((int) argbEvaluator.evaluate(
54 | progress,
55 | resources.getColor(R.color.colorCollapsedFloatBackground),
56 | resources.getColor(R.color.colorInitFloatBackground)));
57 | ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) child.getLayoutParams();
58 | // Margins
59 | final int initMargin = resources.getDimensionPixelOffset(R.dimen.collapsed_float_margin);
60 | final float collapsedMargin = resources.getDimension(R.dimen.collapsed_header_height);
61 | final int margin = (int) ((collapsedMargin) * (1 - progress)) + initMargin;
62 | CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
63 | lp.setMargins(margin, 0, margin, 0);
64 | child.setLayoutParams(lp);
65 |
66 | return true;
67 | }
68 |
69 | private View getDependentView() {
70 | return dependentView.get();
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/NestedEntryActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.zhpan.library.BaseViewBindingActivity;
8 | import com.zhpan.sample.R;
9 | import com.zhpan.sample.databinding.ActivityNestedEnterBinding;
10 | import com.zhpan.sample.nestedscroll.demo1.NestedScrollActivity;
11 | import com.zhpan.sample.nestedscroll.demo2.NestedScrollActivity2;
12 | import com.zhpan.sample.nestedscroll.toolbar.ToolbarBehaviorActivity;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | public class NestedEntryActivity extends BaseViewBindingActivity
16 | implements
17 | View.OnClickListener {
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | binding.btnToolbarBehavior.setOnClickListener(this);
23 | binding.nestedScroll1.setOnClickListener(this);
24 | binding.nestedScroll2.setOnClickListener(this);
25 | }
26 |
27 | @Override
28 | public void onClick(View view) {
29 | Intent intent = null;
30 | if (view.getId() == R.id.btn_toolbar_behavior) {
31 | intent = new Intent(this, ToolbarBehaviorActivity.class);
32 | } else if (view.getId() == R.id.nested_scroll1) {
33 | intent = new Intent(this, NestedScrollActivity.class);
34 | } else if (view.getId() == R.id.nested_scroll2) {
35 | intent = new Intent(this, NestedScrollActivity2.class);
36 | }
37 | if (intent != null) {
38 | startActivity(intent);
39 | }
40 | }
41 |
42 | @NotNull @Override protected ActivityNestedEnterBinding createViewBinding() {
43 | return ActivityNestedEnterBinding.inflate(getLayoutInflater());
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/demo1/FlingHelper.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.demo1;
2 |
3 | import android.content.Context;
4 | import android.view.ViewConfiguration;
5 |
6 | public class FlingHelper {
7 | private static final float DECELERATION_RATE = ((float) (Math.log(0.78d) / Math.log(0.9d)));
8 | private static final float mFlingFriction = ViewConfiguration.getScrollFriction();
9 | private static float mPhysicalCoeff;
10 |
11 | public FlingHelper(Context context) {
12 | mPhysicalCoeff = context.getResources().getDisplayMetrics().density * 160.0f * 386.0878f * 0.84f;
13 | }
14 |
15 | private double getSplineDeceleration(int i) {
16 | return Math.log((double) ((0.35f * ((float) Math.abs(i))) / (mFlingFriction * mPhysicalCoeff)));
17 | }
18 |
19 | private double getSplineDecelerationByDistance(double d) {
20 | return ((((double) DECELERATION_RATE) - 1.0d) * Math.log(d / ((double) (mFlingFriction * mPhysicalCoeff)))) / ((double) DECELERATION_RATE);
21 | }
22 |
23 | /**
24 | * 速度转距离
25 | *
26 | * @param velocityY filing 速度
27 | * @return 可以filing的距离
28 | */
29 | public double getSplineFlingDistance(int velocityY) {
30 | return Math.exp(getSplineDeceleration(velocityY) * (((double) DECELERATION_RATE) / (((double) DECELERATION_RATE) - 1.0d))) * ((double) (mFlingFriction * mPhysicalCoeff));
31 | }
32 |
33 | public int getVelocityByDistance(double d) {
34 | return Math.abs((int) (((Math.exp(getSplineDecelerationByDistance(d)) * ((double) mFlingFriction)) * ((double) mPhysicalCoeff)) / 0.3499999940395355d));
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/demo1/NestedFragment.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.demo1;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 | import androidx.fragment.app.Fragment;
11 | import androidx.recyclerview.widget.LinearLayoutManager;
12 | import androidx.recyclerview.widget.RecyclerView;
13 |
14 | import com.zhpan.sample.R;
15 | import com.zhpan.sample.adapter.DataAdapter;
16 |
17 | /**
18 | * @author zhangpan
19 | * @date 2021/4/14
20 | */
21 | public class NestedFragment extends Fragment {
22 |
23 | @Nullable
24 | @Override
25 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
26 | View itemView = LayoutInflater.from(getContext()).inflate(R.layout.fragment_nested, container, false);
27 | RecyclerView recyclerView = itemView.findViewById(R.id.recycler_view);
28 | recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
29 | recyclerView.setAdapter(new DataAdapter());
30 | return itemView;
31 | }
32 |
33 | public static NestedFragment getInstance() {
34 | return new NestedFragment();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/demo1/NestedFragmentAdapter.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.demo1;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.fragment.app.Fragment;
5 | import androidx.fragment.app.FragmentActivity;
6 | import androidx.viewpager2.adapter.FragmentStateAdapter;
7 |
8 | /**
9 | * @author zhangpan
10 | * @date 2021/4/14
11 | */
12 | class NestedFragmentAdapter extends FragmentStateAdapter {
13 |
14 | public NestedFragmentAdapter(@NonNull FragmentActivity fragmentActivity) {
15 | super(fragmentActivity);
16 | }
17 |
18 | @NonNull
19 | @Override
20 | public Fragment createFragment(int position) {
21 | if (position == 0) {
22 | return NestedFragment.getInstance();
23 | } else if (position == 1) {
24 | return NestedFragment.getInstance();
25 | } else {
26 | return NestedFragment.getInstance();
27 | }
28 | }
29 |
30 | @Override
31 | public int getItemCount() {
32 | return 3;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/demo1/NestedRecyclerView.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.demo1;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import androidx.annotation.NonNull;
6 | import androidx.annotation.Nullable;
7 | import androidx.recyclerview.widget.RecyclerView;
8 |
9 | /**
10 | * @author zhangpan
11 | * @date 2021/6/22
12 | */
13 | public class NestedRecyclerView extends RecyclerView {
14 |
15 | public NestedRecyclerView(@NonNull Context context) {
16 | super(context);
17 | }
18 |
19 | public NestedRecyclerView(@NonNull Context context,
20 | @Nullable AttributeSet attrs) {
21 | super(context, attrs);
22 | }
23 |
24 | public NestedRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs,
25 | int defStyleAttr) {
26 | super(context, attrs, defStyleAttr);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/demo1/NestedScrollActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.demo1
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import androidx.viewpager2.integration.testapp.cards.Card
6 | import androidx.viewpager2.widget.ViewPager2
7 | import com.google.android.material.tabs.TabLayout
8 | import com.google.android.material.tabs.TabLayoutMediator
9 | import com.zhpan.sample.R
10 |
11 | class NestedScrollActivity : AppCompatActivity() {
12 | private lateinit var viewPager2: ViewPager2;
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setContentView(R.layout.activity_nested_scroll)
17 | viewPager2 = findViewById(R.id.view_pager2)
18 | viewPager2.adapter =
19 | NestedFragmentAdapter(this)
20 | val tabLayout = findViewById(R.id.tab_layout)
21 | TabLayoutMediator(tabLayout, viewPager2) { tab, position ->
22 | tab.text = Card.DECK[position].toString()
23 | }.attach()
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/demo2/NestedScrollActivity2.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.demo2
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.recyclerview.widget.LinearLayoutManager
6 | import com.zhpan.library.BaseViewBindingActivity
7 | import com.zhpan.sample.databinding.ActivityNestedScroll2Binding
8 | import com.zhpan.sample.adapter.DataAdapter
9 | import com.zhpan.sample.adapter.ImageAdapter
10 | import com.zhpan.sample.nestedscroll.demo2.ext.dp
11 | import com.zhpan.sample.nestedscroll.demo2.view.BehavioralScrollListener
12 | import com.zhpan.sample.nestedscroll.demo2.view.BehavioralScrollView
13 | import com.zhpan.sample.nestedscroll.demo2.view.BottomSheetLayout.Companion.POSITION_MIN
14 |
15 | class NestedScrollActivity2 : BaseViewBindingActivity() {
16 |
17 | private val floatingHeight = 100.dp
18 |
19 | override fun onCreate(savedInstanceState: Bundle?) {
20 | super.onCreate(savedInstanceState)
21 |
22 | binding.rvLinkageTop.apply {
23 | layoutManager = LinearLayoutManager(this@NestedScrollActivity2)
24 | adapter = ImageAdapter()
25 | }
26 |
27 | binding.rvLinkageBottom.apply {
28 | layoutManager = LinearLayoutManager(this@NestedScrollActivity2)
29 | adapter = DataAdapter()
30 | }
31 |
32 | binding.linkageScroll.topScrollTarget = { binding.rvLinkageTop }
33 | binding.linkageScroll.listeners.add(object : BehavioralScrollListener {
34 | override fun onScrollChanged(v: BehavioralScrollView, from: Int, to: Int) {
35 | super.onScrollChanged(v, from, to)
36 | updateFloatState()
37 | }
38 | })
39 |
40 | binding.bottomSheet.setup(POSITION_MIN, floatingHeight)
41 | updateFloatState()
42 | }
43 |
44 | private fun updateFloatState() {
45 | if (binding.bottomSheet.indexOfChild(binding.rvLinkageBottom) >= 0) {
46 | val scrollY = binding.linkageScroll.scrollY
47 | if (scrollY >= floatingHeight) {
48 | binding.bottomSheet.visibility = View.GONE
49 | binding.bottomSheet.removeView(binding.rvLinkageBottom)
50 | if (binding.layoutBottom.indexOfChild(binding.rvLinkageBottom) < 0) {
51 | binding.layoutBottom.addView(binding.rvLinkageBottom)
52 | }
53 | binding.linkageScroll.bottomScrollTarget = { binding.rvLinkageBottom }
54 | }
55 | } else {
56 | if (binding.linkageScroll.scrollY < floatingHeight) {
57 | binding.linkageScroll.bottomScrollTarget = null
58 | if (binding.layoutBottom.indexOfChild(binding.rvLinkageBottom) >= 0) {
59 | binding.layoutBottom.removeView(binding.rvLinkageBottom)
60 | }
61 | if (binding.bottomSheet.indexOfChild(binding.rvLinkageBottom) < 0) {
62 | binding.bottomSheet.addView(binding.rvLinkageBottom)
63 | }
64 | binding.bottomSheet.visibility = View.VISIBLE
65 | }
66 | }
67 | }
68 |
69 | override fun createViewBinding(): ActivityNestedScroll2Binding {
70 | return ActivityNestedScroll2Binding.inflate(layoutInflater)
71 | }
72 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/demo2/ext/Extentions.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.demo2.ext
2 |
3 | import androidx.core.view.ViewCompat
4 | import com.zhpan.sample.nestedscroll.demo2.view.BehavioralScrollView
5 |
6 | /**
7 | * 这里放一些只访问公共属性/方法的扩展方法
8 | *
9 | * @author https://github.com/funnywolfdadada
10 | * @since 2020/10/24
11 | */
12 | /**
13 | * 当前滚动的百分比
14 | */
15 | fun BehavioralScrollView.currProcess(): Float {
16 | return when(nestedScrollAxes) {
17 | ViewCompat.SCROLL_AXIS_HORIZONTAL -> if (scrollX > 0) {
18 | if (maxScroll != 0) { scrollX.toFloat() / maxScroll } else { 0F }
19 | } else {
20 | if (minScroll != 0) { scrollX.toFloat() / minScroll } else { 0F }
21 | }
22 | ViewCompat.SCROLL_AXIS_VERTICAL -> if (scrollY > 0) {
23 | if (maxScroll != 0) { scrollY.toFloat() / maxScroll } else { 0F }
24 | } else {
25 | if (minScroll != 0) { scrollY.toFloat() / minScroll } else { 0F }
26 | }
27 | else -> 0F
28 | }
29 | }
30 |
31 | fun BehavioralScrollView.isScrolled(): Boolean = when (nestedScrollAxes) {
32 | ViewCompat.SCROLL_AXIS_VERTICAL -> scrollY != 0
33 | ViewCompat.SCROLL_AXIS_HORIZONTAL -> scrollX != 0
34 | else -> false
35 | }
36 |
37 | /**
38 | * 当前滚动位置在 0 或者最大最小值,则认为是稳定位置
39 | */
40 | fun BehavioralScrollView.inStablePosition(): Boolean {
41 | val scroll = when (nestedScrollAxes) {
42 | ViewCompat.SCROLL_AXIS_VERTICAL -> scrollY
43 | ViewCompat.SCROLL_AXIS_HORIZONTAL -> scrollX
44 | else -> return true
45 | }
46 | return scroll == 0 || scroll == minScroll || scroll == maxScroll
47 | }
48 |
49 | /**
50 | * 发生嵌套滚动的直接子 view 是否完全展示出来
51 | */
52 | fun BehavioralScrollView.isScrollChildTotalShowing(): Boolean {
53 | val v = nestedScrollChild ?: return true
54 | return when (nestedScrollAxes) {
55 | ViewCompat.SCROLL_AXIS_VERTICAL -> v.y - scrollY >= 0 && v.y + v.height - scrollY <= height
56 | ViewCompat.SCROLL_AXIS_HORIZONTAL -> v.x - scrollX >= 0 && v.x + v.width - scrollX <= width
57 | else -> return true
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/demo2/ext/TypedValue.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.demo2.ext
2 |
3 | import android.content.res.Resources
4 | import android.util.TypedValue
5 |
6 | /**
7 | * @author https://github.com/funnywolfdadada
8 | * @since 2020/5/30
9 | */
10 | val Number.dp: Int
11 | get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics).toInt()
12 |
13 | val Number.sp: Int
14 | get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this.toFloat(), Resources.getSystem().displayMetrics).toInt()
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/demo2/view/LinkageScrollLayout.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.demo2.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import androidx.core.view.ViewCompat
7 | import com.zhpan.sample.nestedscroll.demo2.ext.isScrollChildTotalShowing
8 |
9 | /**
10 | * 联动滚动布局
11 | *
12 | * @author https://github.com/funnywolfdadada
13 | * @since 2020/9/26
14 | */
15 | class LinkageScrollLayout @JvmOverloads constructor(
16 | context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
17 | ) : BehavioralScrollView(context, attrs, defStyleAttr), NestedScrollBehavior {
18 |
19 | var topScrollTarget: (()-> View?)? = null
20 | var bottomScrollTarget: (()-> View?)? = null
21 |
22 | override var behavior: NestedScrollBehavior? = this
23 |
24 | override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {
25 | // 为了能够将滚动传递下去,需要把 fling 拦截下来
26 | fling(velocityY)
27 | return true
28 | }
29 |
30 | override fun handleNestedPreScrollFirst(scroll: Int, type: Int): Boolean? {
31 | return if (isScrollChildTotalShowing()) {
32 | null
33 | } else {
34 | false
35 | }
36 | }
37 |
38 | override fun handleNestedScrollFirst(scroll: Int, type: Int): Boolean? {
39 | return true
40 | }
41 |
42 | override fun handleScrollSelf(scroll: Int, type: Int): Boolean? {
43 | return if (type == ViewCompat.TYPE_TOUCH) {
44 | handleDrag(scroll)
45 | } else {
46 | handleFling(scroll)
47 | }
48 | }
49 |
50 | private fun handleDrag(scroll: Int): Boolean? {
51 | scrollBy(0, if (scrollY > 0) { scroll } else { scroll / 2 })
52 | return true
53 | }
54 |
55 | private fun handleFling(scroll: Int): Boolean? {
56 | if (isScrollChildTotalShowing() && nestedScrollTarget?.canScrollVertically(scroll) == true) {
57 | nestedScrollTarget?.scrollBy(0, scroll)
58 | return true
59 | }
60 | // 自己可以滚动时,默认处理
61 | if (canScrollVertically(scroll)) {
62 | return null
63 | }
64 | // 自己无法滚动时根据方向确定滚动传递的目标
65 | val target = if (scroll < 0) {
66 | topScrollTarget?.invoke()
67 | } else {
68 | bottomScrollTarget?.invoke()
69 | }
70 | if (target != null && target.canScrollVertically(scroll)) {
71 | target.scrollBy(0, scroll)
72 | return true
73 | }
74 | return false
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/toolbar/ToolbarBehavior.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.toolbar;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 |
7 | import androidx.annotation.NonNull;
8 | import androidx.coordinatorlayout.widget.CoordinatorLayout;
9 |
10 | /**
11 | * Created by zhangpan on 2020/04/11.
12 | */
13 | public class ToolbarBehavior extends CoordinatorLayout.Behavior {
14 |
15 | private int scrollY = 0;
16 |
17 | public ToolbarBehavior(Context context, AttributeSet attrs) {
18 | super(context, attrs);
19 | }
20 |
21 | @Override
22 | public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
23 | @NonNull BehaviorToolbar child, @NonNull View directTargetChild, @NonNull View target,
24 | int axes, int type) {
25 | return true;
26 | }
27 |
28 | @Override
29 | public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull BehaviorToolbar toolbar, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type, @NonNull int[] consumed) {
30 | super.onNestedScroll(coordinatorLayout, toolbar, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed);
31 | int endOffset = toolbar.getHeaderHeight() - toolbar.getHeight();
32 | scrollY += dyConsumed;
33 | Context context = coordinatorLayout.getContext();
34 | float fraction = (float)scrollY / endOffset;
35 | if(scrollY <= 0) {
36 | toolbar.setToolbarTransparent();
37 | } else if(scrollY < endOffset) {
38 | toolbar.changingColorGradually(context, fraction);
39 | } else if(scrollY < 2 * endOffset) {
40 | toolbar.setToolbarFullColor(context);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/nestedscroll/toolbar/ToolbarBehaviorActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.nestedscroll.toolbar
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import androidx.appcompat.app.AppCompatActivity
6 | import androidx.recyclerview.widget.DividerItemDecoration
7 | import androidx.recyclerview.widget.LinearLayoutManager
8 | import com.zhpan.library.recyclerview.ui.CustomRecyclerView
9 | import com.zhpan.sample.R
10 | import com.zhpan.sample.adapter.DataAdapter
11 |
12 | class ToolbarBehaviorActivity : AppCompatActivity() {
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | setContentView(R.layout.activity_behavior)
16 | val recyclerView=findViewById(R.id.recyclerView)
17 | val toolbar=findViewById(R.id.toolbar)
18 | recyclerView.layoutManager = LinearLayoutManager(this)
19 | val headerView = LayoutInflater.from(this).inflate(R.layout.layout_behavior_header, recyclerView, false)
20 | recyclerView.addHeadView(headerView)
21 | recyclerView.addItemDecoration(DividerItemDecoration(this,
22 | DividerItemDecoration.VERTICAL))
23 | recyclerView.adapter = DataAdapter()
24 | toolbar.setTitle(getString(R.string.behavior))
25 | toolbar.setupWithHeader(headerView)
26 | toolbar.setNavigationOnClickListener {
27 | onBackPressed()
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/ViewEntryActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import com.zhpan.library.BaseViewBindingActivity
6 | import com.zhpan.sample.banner3d.Banner3dActivity
7 | import com.zhpan.sample.databinding.ActivityViewEntryBinding
8 | import com.zhpan.sample.view.dispatch.DispatchActivity
9 | import com.zhpan.sample.view.viewpager2.activity.ViewPager2EntryActivity
10 |
11 | class ViewEntryActivity : BaseViewBindingActivity() {
12 | override fun onCreate(savedInstanceState: Bundle?) {
13 | super.onCreate(savedInstanceState)
14 | binding.viewpager2.setOnClickListener {
15 | startActivity(Intent(this, ViewPager2EntryActivity::class.java))
16 | }
17 | binding.dispatchView.setOnClickListener {
18 | startActivity(Intent(this, DispatchActivity::class.java))
19 | }
20 |
21 | binding.itemBanner.setOnClickListener {
22 | startActivity(Intent(this, Banner3dActivity::class.java))
23 | }
24 | }
25 |
26 | override fun createViewBinding(): ActivityViewEntryBinding {
27 | return ActivityViewEntryBinding.inflate(layoutInflater)
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/dispatch/DispatchActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view.dispatch;
2 |
3 | import androidx.appcompat.app.AppCompatActivity;
4 |
5 | import android.os.Bundle;
6 | import android.util.Log;
7 | import android.view.MotionEvent;
8 |
9 | import com.zhpan.sample.R;
10 |
11 | public class DispatchActivity extends AppCompatActivity {
12 |
13 | public static final String TAG = "DispatchEvent";
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_dispatch);
19 | // findViewById(R.id.dispatch_view).setOnClickListener(new View.OnClickListener() {
20 | // @Override
21 | // public void onClick(View v) {
22 | // Log.e(TAG, "DispatchView clicked");
23 | // }
24 | // });
25 |
26 | // findViewById(R.id.dl_inner).setOnClickListener(new View.OnClickListener() {
27 | // @Override
28 | // public void onClick(View v) {
29 | // Log.e(TAG, "DispatchLayout clicked");
30 | // }
31 | // });
32 |
33 | // findViewById(R.id.dl_inner).setOnTouchListener(new View.OnTouchListener() {
34 | // @Override
35 | // public boolean onTouch(View v, MotionEvent event) {
36 | // Log.e(TAG, "DispatchLayout setOnTouchListener");
37 | // return false;
38 | // }
39 | // });
40 |
41 | }
42 |
43 | @Override
44 | public boolean dispatchTouchEvent(MotionEvent event) {
45 | Log.e(TAG, "Activity dispatchTouchEvent" + getActionStr(event.getAction()));
46 | return super.dispatchTouchEvent(event);
47 | }
48 |
49 | @Override
50 | public boolean onTouchEvent(MotionEvent event) {
51 | Log.e(TAG, "Activity onTouchEvent" + getActionStr(event.getAction()));
52 | return super.onTouchEvent(event);
53 | }
54 |
55 | public static String getActionStr(int action) {
56 | switch (action) {
57 | case MotionEvent.ACTION_DOWN:
58 | return ",Action Down";
59 | case MotionEvent.ACTION_MOVE:
60 | return ",Action Move";
61 | case MotionEvent.ACTION_UP:
62 | return ",Action Up";
63 | }
64 | return "";
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/dispatch/DispatchLayout.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view.dispatch;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.util.Log;
6 | import android.view.MotionEvent;
7 | import android.widget.FrameLayout;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.annotation.Nullable;
11 |
12 | import com.zhpan.sample.R;
13 |
14 | import static com.zhpan.sample.view.dispatch.DispatchActivity.TAG;
15 | import static com.zhpan.sample.view.dispatch.DispatchActivity.getActionStr;
16 |
17 | /**
18 | *
19 | * Created by zhangpan on 2020/4/23.
20 | * Description:
21 | *
22 | */
23 | public class DispatchLayout extends FrameLayout {
24 | private String idStr;
25 |
26 | public DispatchLayout(@NonNull Context context) {
27 | this(context, null);
28 | }
29 |
30 | public DispatchLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
31 | this(context, attrs, 0);
32 | }
33 |
34 | public DispatchLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
35 | super(context, attrs, defStyleAttr);
36 | if (getId() == R.id.dl_outer) {
37 | idStr = "Outer";
38 | } else if (getId() == R.id.dl_inner) {
39 | idStr = "Inner";
40 | }
41 | }
42 |
43 | @Override
44 | public boolean dispatchTouchEvent(MotionEvent event) {
45 | Log.e(TAG, idStr + " DispatchLayout dispatchTouchEvent" + getActionStr(event.getAction()));
46 | boolean dispatched = super.dispatchTouchEvent(event);
47 | return dispatched;
48 | }
49 |
50 | @Override
51 | public boolean onInterceptTouchEvent(MotionEvent event) {
52 | Log.e(TAG, idStr + " DispatchLayout onInterceptTouchEvent" + getActionStr(event.getAction()));
53 | boolean intercept = true;
54 | // 如果拦截了ACTION_DOWN事件,则包括ACTION_DOWN以及其后的一系列ACTION_DOWN事件都无法再被分发到其子View。
55 | if (event.getAction() != MotionEvent.ACTION_DOWN) {
56 | intercept = false;
57 | }
58 | return intercept;
59 | }
60 |
61 | @Override
62 | public boolean onTouchEvent(MotionEvent event) {
63 | Log.e(TAG, idStr + " DispatchLayout onTouchEvent" + getActionStr(event.getAction()));
64 | return super.onTouchEvent(event);
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/dispatch/DispatchView.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view.dispatch;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.util.Log;
6 | import android.view.MotionEvent;
7 | import android.view.View;
8 |
9 | import androidx.annotation.Nullable;
10 |
11 | import static com.zhpan.sample.view.dispatch.DispatchActivity.TAG;
12 | import static com.zhpan.sample.view.dispatch.DispatchActivity.getActionStr;
13 |
14 | /**
15 | *
16 | * Created by zhangpan on 2020/4/23.
17 | * Description:
18 | *
19 | */
20 | public class DispatchView extends View {
21 |
22 |
23 | public DispatchView(Context context) {
24 | this(context, null);
25 | }
26 |
27 | public DispatchView(Context context, @Nullable AttributeSet attrs) {
28 | this(context, attrs, 0);
29 | }
30 |
31 | public DispatchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
32 | super(context, attrs, defStyleAttr);
33 | }
34 |
35 | @Override
36 | public boolean dispatchTouchEvent(MotionEvent event) {
37 | int id = getId();
38 | Log.e(TAG, "DispatchView dispatchTouchEvent" + ",Action:" + getActionStr(event.getAction()));
39 | return super.dispatchTouchEvent(event);
40 | }
41 |
42 | @Override
43 | public boolean onTouchEvent(MotionEvent event) {
44 | Log.e(TAG, "DispatchView onTouchEvent" + ",Action:" + getActionStr(event.getAction()));
45 | return super.onTouchEvent(event);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/viewpager2/ScaleInTransformer.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view.viewpager2
2 |
3 | import android.view.View
4 | import androidx.viewpager2.widget.ViewPager2
5 | import java.lang.Math.abs
6 |
7 | class ScaleInTransformer : ViewPager2.PageTransformer {
8 | private val mMinScale = DEFAULT_MIN_SCALE
9 |
10 | override fun transformPage(view: View, position: Float) {
11 | view.elevation = -abs(position)
12 | val pageWidth = view.width
13 | val pageHeight = view.height
14 |
15 | view.pivotY = (pageHeight / 2).toFloat()
16 | view.pivotX = (pageWidth / 2).toFloat()
17 | if (position < -1) {
18 | view.scaleX = mMinScale
19 | view.scaleY = mMinScale
20 | view.pivotX = pageWidth.toFloat()
21 | } else if (position <= 1) {
22 | if (position < 0) {
23 | val scaleFactor = (1 + position) * (1 - mMinScale) + mMinScale
24 | view.scaleX = scaleFactor
25 | view.scaleY = scaleFactor
26 | view.pivotX = pageWidth * (DEFAULT_CENTER + DEFAULT_CENTER * -position)
27 | } else {
28 | val scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale
29 | view.scaleX = scaleFactor
30 | view.scaleY = scaleFactor
31 | view.pivotX = pageWidth * ((1 - position) * DEFAULT_CENTER)
32 | }
33 | } else {
34 | view.pivotX = 0f
35 | view.scaleX = mMinScale
36 | view.scaleY = mMinScale
37 | }
38 | }
39 |
40 | companion object {
41 |
42 | const val DEFAULT_MIN_SCALE = 0.85f
43 | const val DEFAULT_CENTER = 0.5f
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/viewpager2/activity/VP2FragmentActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view.viewpager2.activity
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 |
5 | import android.os.Bundle
6 | import androidx.fragment.app.Fragment
7 | import androidx.viewpager2.adapter.FragmentStateAdapter
8 | import androidx.viewpager2.integration.testapp.cards.Card
9 | import androidx.viewpager2.widget.ViewPager2
10 | import com.google.android.material.tabs.TabLayout
11 | import com.google.android.material.tabs.TabLayoutMediator
12 | import com.zhpan.sample.R
13 | import com.zhpan.sample.view.viewpager2.fragment.TestFragment
14 |
15 | class VP2FragmentActivity : AppCompatActivity() {
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setContentView(R.layout.activity_fragment)
20 | val viewPager=findViewById(R.id.view_pager)
21 | val tabLayout=findViewById(R.id.tab_layout)
22 | // view_pager.offscreenPageLimit=1
23 | viewPager.adapter = object : FragmentStateAdapter(this) {
24 | override fun getItemCount(): Int {
25 | return Card.DECK.size
26 | }
27 |
28 | override fun createFragment(position: Int): Fragment {
29 | return TestFragment.getInstance(Card.DECK[position],position)
30 | }
31 | }
32 |
33 | TabLayoutMediator(tabLayout, viewPager) { tab, position ->
34 | tab.text = Card.DECK[position].toString()
35 | }.attach()
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/viewpager2/activity/VPFragmentActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view.viewpager2.activity
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import androidx.fragment.app.FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
6 | import androidx.viewpager.widget.ViewPager
7 | import com.zhpan.sample.R
8 | import com.zhpan.sample.view.viewpager2.adapter.VPFragmentAdapter
9 |
10 | class VPFragmentActivity : AppCompatActivity() {
11 |
12 | override fun onCreate(savedInstanceState: Bundle?) {
13 | super.onCreate(savedInstanceState)
14 | setContentView(R.layout.activity_view_pager)
15 | val viewPager = findViewById(R.id.view_pager)
16 | viewPager.adapter = VPFragmentAdapter(supportFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/viewpager2/activity/ViewPager2EntryActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view.viewpager2.activity
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import androidx.appcompat.app.AppCompatActivity
6 | import android.os.Bundle
7 | import android.view.View
8 | import com.zhpan.sample.R
9 | import com.zhpan.sample.jetpack.lifecycle.FragmentLifecycleActivity
10 |
11 | class ViewPager2EntryActivity : AppCompatActivity() {
12 |
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | setContentView(R.layout.activity_vp_entry)
16 | }
17 |
18 | fun onClick(view: View) {
19 | startActivity(Intent(this, getIntentActivity(view)))
20 | }
21 |
22 | private fun getIntentActivity(view: View): Class? {
23 | return when (view.id) {
24 | R.id.btn_view_pager2_fragment -> VP2FragmentActivity::class.java
25 | R.id.btn_view_pager_fragment -> VPFragmentActivity::class.java
26 | R.id.btn_fragment_lifecycle -> FragmentLifecycleActivity::class.java
27 | else -> VP2ViewsActivity::class.java
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/viewpager2/adapter/VPFragmentAdapter.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view.viewpager2.adapter;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.fragment.app.Fragment;
5 | import androidx.fragment.app.FragmentManager;
6 | import androidx.fragment.app.FragmentStatePagerAdapter;
7 | import androidx.viewpager2.integration.testapp.cards.Card;
8 |
9 | import com.zhpan.sample.view.viewpager2.fragment.TestFragment;
10 |
11 | /**
12 | *
13 | * Created by zhpan on 2019/12/21.
14 | * Description:
15 | *
16 | */
17 | public class VPFragmentAdapter extends FragmentStatePagerAdapter {
18 |
19 |
20 | public VPFragmentAdapter(@NonNull FragmentManager fm, int behavior) {
21 | super(fm, behavior);
22 | }
23 |
24 | @NonNull
25 | @Override
26 | public Fragment getItem(int position) {
27 | return TestFragment.Companion.getInstance(Card.Companion.getDECK().get(position),position);
28 | }
29 |
30 | @Override
31 | public int getCount() {
32 | return Card.Companion.getDECK().size();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/viewpager2/adapter/ViewPager2Adapter.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view.viewpager2.adapter
2 |
3 | import android.graphics.Color
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.zhpan.sample.R
10 |
11 | import java.util.ArrayList
12 |
13 | /**
14 | *
15 | * Created by zhpan on 2019/12/9.
16 | * Description:
17 |
*
18 | */
19 | class ViewPager2Adapter : RecyclerView.Adapter() {
20 | private var mList: List = ArrayList()
21 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PagerViewHolder {
22 | val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_page, parent, false)
23 | return PagerViewHolder(itemView)
24 | }
25 |
26 | override fun onBindViewHolder(holder: PagerViewHolder, position: Int) {
27 | holder.bindData(mList[position])
28 | }
29 |
30 | fun setList(list: List) {
31 | mList = list
32 | }
33 |
34 | override fun getItemCount(): Int {
35 | return mList.size
36 | }
37 |
38 | class PagerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
39 | private val mTextView: TextView = itemView.findViewById(R.id.tv_text)
40 | private var colors = arrayOf("#CCFF99","#41F1E5","#8D41F1","#FF99CC")
41 |
42 | fun bindData(i: Int) {
43 | mTextView.text = i.toString()
44 | mTextView.setBackgroundColor(Color.parseColor(colors[i]))
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/viewpager2/cards/Card.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package androidx.viewpager2.integration.testapp.cards
18 |
19 | import android.os.Bundle
20 | import androidx.core.text.BidiFormatter
21 |
22 | /**
23 | * Playing card
24 | */
25 | class Card private constructor(val suit: String, val value: String) {
26 |
27 | val cornerLabel: String
28 | get() = value + "\n" + suit
29 |
30 | /** Use in conjunction with [Card.fromBundle] */
31 | fun toBundle(): Bundle {
32 | val args = Bundle(1)
33 | args.putStringArray(ARGS_BUNDLE, arrayOf(suit, value))
34 | return args
35 | }
36 |
37 | override fun toString(): String {
38 | val bidi = BidiFormatter.getInstance()
39 | if (!bidi.isRtlContext) {
40 | return bidi.unicodeWrap("$value $suit")
41 | } else {
42 | return bidi.unicodeWrap("$suit $value")
43 | }
44 | }
45 |
46 | companion object {
47 | internal val ARGS_BUNDLE = Card::class.java.name + ":Bundle"
48 |
49 | val SUITS = setOf("♣" /* clubs*/, "♦" /* diamonds*/, "♥" /* hearts*/, "♠" /*spades*/)
50 | val VALUES = setOf("2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A")
51 | val DECK = SUITS.flatMap { suit ->
52 | VALUES.map { value -> Card(suit, value) }
53 | }
54 |
55 | fun List.find(value: String, suit: String): Card? {
56 | return find { it.value == value && it.suit == suit }
57 | }
58 |
59 | /** Use in conjunction with [Card.toBundle] */
60 | fun fromBundle(bundle: Bundle): Card {
61 | val spec = bundle.getStringArray(ARGS_BUNDLE)
62 | return Card(spec!![0], spec[1])
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/viewpager2/cards/CardView.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package androidx.viewpager2.integration.testapp.cards
18 |
19 | import android.view.LayoutInflater
20 | import android.view.View
21 | import android.view.ViewGroup
22 | import android.widget.TextView
23 |
24 | import androidx.annotation.ColorRes
25 | import com.zhpan.sample.R
26 |
27 |
28 | /** Inflates and populates a [View] representing a [Card] */
29 | class CardView(layoutInflater: LayoutInflater, container: ViewGroup?) {
30 | val view: View = layoutInflater.inflate(R.layout.item_card_layout, container, false)
31 | private val textSuite: TextView
32 | private val textCorner1: TextView
33 | private val textCorner2: TextView
34 |
35 | init {
36 | textSuite = view.findViewById(R.id.label_center)
37 | textCorner1 = view.findViewById(R.id.label_top)
38 | textCorner2 = view.findViewById(R.id.label_bottom)
39 | }
40 |
41 | /**
42 | * Updates the view to represent the passed in card
43 | */
44 | fun bind(card: Card) {
45 | textSuite.text = card.suit
46 | view.setBackgroundResource(getColorRes(card))
47 |
48 | val cornerLabel = card.cornerLabel
49 | textCorner1.text = cornerLabel
50 | textCorner2.text = cornerLabel
51 | }
52 |
53 | @ColorRes
54 | private fun getColorRes(card: Card): Int {
55 | val shade = getShade(card)
56 | val color = getColor(card)
57 | return COLOR_MAP[color][shade]
58 | }
59 |
60 | private fun getShade(card: Card): Int {
61 | when (card.value) {
62 | "2", "6", "10", "A" -> return 2
63 | "3", "7", "J" -> return 3
64 | "4", "8", "Q" -> return 0
65 | "5", "9", "K" -> return 1
66 | }
67 | throw IllegalStateException("Card value cannot be $card.value")
68 | }
69 |
70 | private fun getColor(card: Card): Int {
71 | when (card.suit) {
72 | "♣" -> return 0
73 | "♦" -> return 1
74 | "♥" -> return 2
75 | "♠" -> return 3
76 | }
77 | throw IllegalStateException("Card suit cannot be $card.suit")
78 | }
79 |
80 | companion object {
81 | private val COLOR_MAP = arrayOf(
82 | intArrayOf(R.color.red_100, R.color.red_300, R.color.red_500, R.color.red_700),
83 | intArrayOf(R.color.blue_100, R.color.blue_300, R.color.blue_500, R.color.blue_700),
84 | intArrayOf(R.color.green_100, R.color.green_300, R.color.green_500,
85 | R.color.green_700),
86 | intArrayOf(R.color.yellow_100, R.color.yellow_300, R.color.yellow_500,
87 | R.color.yellow_700))
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/viewpager2/cards/CardViewAdapter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package androidx.viewpager2.integration.testapp.cards
18 |
19 | import android.view.LayoutInflater
20 | import android.view.ViewGroup
21 | import androidx.recyclerview.widget.RecyclerView
22 |
23 | class CardViewAdapter : RecyclerView.Adapter() {
24 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
25 | return CardViewHolder(CardView(LayoutInflater.from(parent.context), parent))
26 | }
27 |
28 | override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
29 | holder.bind(Card.DECK[position])
30 | }
31 |
32 | override fun getItemCount(): Int {
33 | return Card.DECK.size
34 | }
35 | }
36 |
37 | class CardViewHolder internal constructor(private val cardView: CardView) :
38 | RecyclerView.ViewHolder(cardView.view) {
39 | internal fun bind(card: Card) {
40 | cardView.bind(card)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhpan/sample/view/viewpager2/fragment/TestFragment.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.sample.view.viewpager2.fragment
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.util.Log
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.widget.Toast
10 | import androidx.fragment.app.Fragment
11 | import androidx.viewpager2.integration.testapp.cards.Card
12 | import androidx.viewpager2.integration.testapp.cards.CardView
13 |
14 | /**
15 | *
16 | * Created by zhangpan on 2019-12-17.
17 | * Description:
18 |
*
19 | */
20 | class TestFragment : Fragment() {
21 | private var position: Int = 0
22 |
23 | override fun onAttach(context: Context) {
24 | super.onAttach(context)
25 | // showToast("onAttach:$position")
26 | Log.e("TestFragment", "onAttach,position:$position")
27 | val bundle = arguments
28 | position = bundle!!.getInt(KEY_POSITION)
29 | }
30 |
31 | override fun onCreate(savedInstanceState: Bundle?) {
32 | super.onCreate(savedInstanceState)
33 | // showToast("onCreate:$position")
34 | Log.e("TestFragment", "onCreate,position:$position")
35 | }
36 |
37 | override fun setUserVisibleHint(isVisibleToUser: Boolean) {
38 | super.setUserVisibleHint(isVisibleToUser)
39 | }
40 |
41 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
42 | Log.e("TestFragment", "onCreateView,position:$position")
43 | // showToast("onCreateView:$position")
44 | val cardView = CardView(inflater, container)
45 | cardView.bind(Card.fromBundle(arguments!!))
46 | return cardView.view
47 | }
48 |
49 | override fun onStart() {
50 | super.onStart()
51 | // showToast("onStart:$position")
52 | Log.e("TestFragment", "onStart,position:$position")
53 | }
54 |
55 | override fun onResume() {
56 | super.onResume()
57 | // showToast("onResume:$position")
58 | Log.e("TestFragment", "onResume,position:$position")
59 | }
60 |
61 |
62 | override fun onPause() {
63 | super.onPause()
64 | // showToast("onPause:$position")
65 | Log.e("TestFragment", "onPause,position:$position")
66 | }
67 |
68 | override fun onStop() {
69 | super.onStop()
70 | // showToast("onStop:$position")
71 | Log.e("TestFragment", "onStop,position:$position")
72 | }
73 |
74 | override fun onDestroyView() {
75 | super.onDestroyView()
76 | // showToast("onDestroyView:$position")
77 | Log.e("TestFragment", "onDestroyView,position:$position")
78 | }
79 |
80 | override fun onDestroy() {
81 | super.onDestroy()
82 | // showToast("onDestroy:$position")
83 | Log.e("TestFragment", "onDestroy,position:$position")
84 | }
85 |
86 | override fun onDetach() {
87 | super.onDetach()
88 | // showToast("onDetach:$position")
89 | Log.e("TestFragment", "onDetach,position:$position")
90 | }
91 |
92 | companion object {
93 |
94 | private const val KEY_POSITION = "position"
95 |
96 | fun getInstance(card: Card, position: Int): TestFragment {
97 | val fragment = TestFragment()
98 | val bundle = card.toBundle()
99 | bundle.putInt(KEY_POSITION, position)
100 | fragment.arguments = bundle
101 | return fragment
102 | }
103 | }
104 |
105 | private fun showToast(content: String) {
106 | Toast.makeText(context, content, Toast.LENGTH_SHORT).show()
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/ic_action_back.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/ic_action_back_white.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-hdpi/ic_action_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_back_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-hdpi/ic_action_back_white.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/bg_banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-mdpi/bg_banner.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-mdpi/ic_action_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_back_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-mdpi/ic_action_back_white.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xhdpi/ic_action_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_back_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xhdpi/ic_action_back_white.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/background1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/background1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/background2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/background2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/background3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/background3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/foreground1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/foreground1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/foreground2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/foreground2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/foreground3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/foreground3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/ic_action_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_back_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/ic_action_back_white.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/mid1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/mid1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/mid2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/mid2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/mid3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxhdpi/mid3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/advertise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxxhdpi/advertise.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/home_top_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable-xxxhdpi/home_top_2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/banner_indicator_focus.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/banner_indicator_nornal.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_floating_add.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/drawable/icon.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_aidl_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_animate_entry.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
22 |
23 |
29 |
30 |
36 |
37 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_banner_3d.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
21 |
22 |
23 |
24 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_behavior.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
25 |
26 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_binder.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_binder_entry.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
21 |
22 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_dispatch.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_fragment_lifecycle.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
23 |
24 |
31 |
32 |
33 |
40 |
41 |
42 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_header_scale.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
25 |
26 |
33 |
34 |
35 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_hilt.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_interpolator.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
23 |
24 |
31 |
32 |
39 |
40 |
47 |
48 |
55 |
56 |
57 |
62 |
63 |
68 |
69 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_jetpack_entry.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
26 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_lifecycle.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_nested_enter.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_nested_scroll.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
17 |
18 |
23 |
24 |
29 |
30 |
31 |
39 |
40 |
41 |
45 |
46 |
54 |
55 |
59 |
60 |
61 |
62 |
63 |
64 |
69 |
70 |
75 |
76 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_nested_scroll2.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
24 |
25 |
26 |
27 |
33 |
34 |
38 |
39 |
40 |
41 |
42 |
43 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_object_animation.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
24 |
25 |
32 |
33 |
40 |
41 |
48 |
49 |
56 |
57 |
58 |
59 |
65 |
66 |
72 |
73 |
74 |
79 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_pager.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
21 |
22 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_paging.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_property_entry.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_value_animator.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
25 |
26 |
35 |
36 |
37 |
38 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_view_animation.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
22 |
23 |
30 |
31 |
38 |
39 |
46 |
47 |
54 |
55 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_view_entry.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
18 |
19 |
20 |
27 |
28 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_view_model.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_view_pager.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_vp_entry.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
19 |
20 |
21 |
29 |
30 |
31 |
39 |
40 |
41 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_work_manager.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
22 |
23 |
29 |
30 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/behavior_tool_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
18 |
19 |
25 |
26 |
32 |
33 |
42 |
43 |
50 |
51 |
52 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_main_entry.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
22 |
23 |
30 |
31 |
38 |
39 |
46 |
47 |
55 |
56 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_nested.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_3d_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_3d_foreground.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
16 |
17 |
22 |
23 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_3d_foreground2.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
23 |
24 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_article.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_behavior.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_card_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
24 |
25 |
33 |
34 |
41 |
42 |
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_page.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_behavior_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
16 |
17 |
20 |
21 |
24 |
25 |
28 |
29 |
32 |
33 |
34 |
39 |
40 |
41 |
42 |
47 |
48 |
49 |
50 |
55 |
56 |
61 |
62 |
63 |
64 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidSample
3 | ViewPager2 with Views
4 | ViewPager
5 | Behavior
6 | Search
7 |
8 | Hello blank fragment
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.5.10'
5 | repositories {
6 | google()
7 | jcenter()
8 |
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:4.1.3'
12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | jcenter()
23 | maven { url "https://jitpack.io" }
24 | }
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 |
21 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 14 16:01:10 CST 2021
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-6.5-all.zip
7 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "29.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 19
9 | targetSdkVersion 29
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 | consumerProguardFiles 'consumer-rules.pro'
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | buildFeatures {
24 | viewBinding true
25 | }
26 |
27 | }
28 |
29 | dependencies {
30 | implementation fileTree(dir: 'libs', include: ['*.jar'])
31 |
32 | implementation 'androidx.appcompat:appcompat:1.3.0'
33 | implementation 'com.google.android.material:material:1.2.1'
34 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
35 | implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
36 | testImplementation 'junit:junit:4.13.2'
37 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
38 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
39 | implementation 'androidx.recyclerview:recyclerview:1.2.1'
40 | api 'com.blankj:utilcodex:1.30.6'
41 | api 'androidx.paging:paging-runtime-ktx:3.0.0'
42 | api 'com.squareup.retrofit2:retrofit:2.9.0'
43 | api 'com.squareup.retrofit2:converter-gson:2.9.0'
44 | api 'com.github.zhpanvip:bannerviewpager:3.5.1'
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/library/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhpanvip/AndroidSample/9cfcf978b7cbc0d2d74348a193c44af8193c798d/library/consumer-rules.pro
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/zhpan/library/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.library;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("com.zhpan.library.test", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/BaseViewBindingActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.library
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.appcompat.app.AppCompatActivity
6 | import androidx.viewbinding.ViewBinding
7 |
8 | abstract class BaseViewBindingActivity : AppCompatActivity() {
9 | protected lateinit var binding: T
10 |
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | binding = createViewBinding()
14 | super.setContentView(binding.root)
15 | }
16 |
17 | override fun setContentView(layoutResID: Int) {
18 | throw IllegalArgumentException(
19 | "The method createViewBinding() has created a new content view to be add,So you should not set again."
20 | )
21 | }
22 |
23 | override fun setContentView(contentView: View?) {
24 | throw IllegalArgumentException(
25 | "The method createViewBinding() has created a new content view to be add,So you should not set again."
26 | )
27 | }
28 |
29 | protected abstract fun createViewBinding(): T
30 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/BaseViewBindingFragment.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.library
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import androidx.viewbinding.ViewBinding
9 |
10 | /**
11 | *
12 | * @author zhangpan
13 | * @date 2021/6/25
14 | */
15 | abstract class BaseViewBindingFragment : Fragment() {
16 |
17 | protected lateinit var binding: T
18 |
19 | override fun onCreateView(
20 | inflater: LayoutInflater, container: ViewGroup?,
21 | savedInstanceState: Bundle?
22 | ): View? {
23 | binding = createViewBinding(container)
24 | onViewBindingCreated(binding.root)
25 | return binding.root
26 | }
27 |
28 | abstract fun onViewBindingCreated(rootView:View?)
29 |
30 | abstract fun createViewBinding(container: ViewGroup?): T
31 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/model/Article.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.model
2 |
3 | /**
4 | *
5 | * Created by zhpan on 2020/7/11.
6 | * Description:
7 | *
8 | */
9 | class Article() {
10 |
11 | constructor(
12 | title: String?
13 | ) : this() {
14 | this.title = title
15 | this.author = author
16 | }
17 |
18 | var title: String? = null
19 | var link: String? = null
20 | var author: String? = null
21 | var publishTime: Long = 0
22 |
23 | override fun equals(other: Any?): Boolean {
24 | if (this === other) return true
25 | if (other !is Article) return false
26 |
27 | if (title != other.title) return false
28 | if (link != other.link) return false
29 | if (author != other.author) return false
30 | if (publishTime != other.publishTime) return false
31 |
32 | return true
33 | }
34 |
35 | override fun hashCode(): Int {
36 | var result = title?.hashCode() ?: 0
37 | result = 31 * result + (link?.hashCode() ?: 0)
38 | result = 31 * result + (author?.hashCode() ?: 0)
39 | result = 31 * result + publishTime.hashCode()
40 | return result
41 | }
42 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/model/ArticleResponse.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.model
2 |
3 | class ArticleResponse() {
4 |
5 | var datas: List? = emptyList()
6 | var curPage: Int? = 0
7 | var offset: Int? = 0
8 | var over: Boolean? = false
9 | var pageCount: Int? = 0
10 | var size: Int? = 0
11 | var total: Int? = 0
12 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/model/response/BaseResponse.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.model.response
2 |
3 | /**
4 | *
5 | * @author zhangpan
6 | * @date 2021/3/23
7 | */
8 | class BaseResponse {
9 | val data: T? = null
10 | val errorCode = 0
11 | val errorMsg = ""
12 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/recyclerview/listener/ICustomClickListener.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.recyclerview.listener;
2 |
3 | import android.view.View;
4 |
5 | public interface ICustomClickListener {
6 | void onClick(View view, int position, int type, Object... data);
7 |
8 | void onLongClick(View view, int position, int type, Object... data);
9 | }
10 |
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/recyclerview/listener/ICustomScrollListener.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.recyclerview.listener;
2 |
3 | /**
4 | * 2018.11.4
5 | * 使用了自己的刷新加载view时,需要实现改接口,不然接受不到数据
6 | * 如果不需要使用自定义的刷新View,可使用{@link IScrollListener}
7 | */
8 | public interface ICustomScrollListener {
9 | /**
10 | * 下拉刷新时候的回调
11 | * @param state
12 | */
13 | void scrollRefreshState(int state);
14 |
15 | /**
16 | * 上拉加载时候的回调
17 | * @param state
18 | */
19 | void scrollLoadMoreState(int state);
20 |
21 | /**
22 | * 在此方法内写刷新的逻辑
23 | */
24 | void refresh();
25 | /**
26 | * 在此方法内写加载的逻辑
27 | */
28 | void loadMore();
29 | }
30 |
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/recyclerview/listener/IScrollListener.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.recyclerview.listener;
2 |
3 | /**
4 | * 2018.11.4
5 | * 当使用默认刷新是调用该接口
6 | * 该接口只用于回调刷新和加载数据
7 | * 优先级小于{@link ICustomScrollListener}
8 | */
9 | public interface IScrollListener {
10 |
11 | /**
12 | * 在此方法内写刷新的逻辑
13 | */
14 | void refresh();
15 |
16 | /**
17 | * 在此方法内写加载的逻辑
18 | */
19 | void loadMore();
20 | }
21 |
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/recyclerview/module/ViewConfig.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.recyclerview.module;
2 |
3 |
4 | import android.view.View;
5 |
6 | public class ViewConfig {
7 | public static final String HEADVIEW = "_head_";
8 | public static final String FOOTVIEW = "_foot_";
9 | public static final int HEADVIEW_TYPE = 100000;
10 | public static final int FOOTVIEW_TYPE = 100001;
11 | private int type; // 100000 代表头部 100001 代表尾部
12 | private int view;
13 | private String tag;
14 | private View contentView;
15 | private boolean isCache; //是否需要缓存
16 |
17 | public boolean isCache() {
18 | return isCache;
19 | }
20 |
21 | public void setCache(boolean cache) {
22 | isCache = cache;
23 | }
24 |
25 | public View getContentView() {
26 | return contentView;
27 | }
28 |
29 | public void setContentView(View contentView) {
30 | this.contentView = contentView;
31 | }
32 |
33 | public int getType() {
34 | return type;
35 | }
36 |
37 | public void setType(int type) {
38 | this.type = type;
39 | }
40 |
41 | public int getView() {
42 | return view;
43 | }
44 |
45 | public void setView(int view) {
46 | this.view = view;
47 | }
48 |
49 | public String getTag() {
50 | return tag;
51 | }
52 |
53 | public void setTag(String tag) {
54 | this.tag = tag;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/server/ApiService.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.server
2 |
3 | import com.blankj.utilcode.util.Utils
4 | import com.zhpan.library.model.ArticleResponse
5 | import com.zhpan.library.model.response.BaseResponse
6 | import okhttp3.Cache
7 | import okhttp3.OkHttpClient
8 | import retrofit2.Retrofit
9 | import retrofit2.converter.gson.GsonConverterFactory
10 | import retrofit2.http.GET
11 | import retrofit2.http.Path
12 | import java.io.File
13 |
14 | /**
15 | * @author zhangpan
16 | * @date 2021/3/23
17 | */
18 | interface ApiService {
19 | @GET("article/list/{page}/json")
20 | suspend fun getHomeArticles(@Path("page") page: Int): BaseResponse
21 |
22 | companion object {
23 | private const val BASE_URL = "https://www.wanandroid.com/"
24 |
25 | private val okHttpClientBuilder: OkHttpClient.Builder
26 | get() {
27 | val cacheFile =
28 | File(Utils.getApp().cacheDir, "cache")
29 | val cache = Cache(cacheFile, 1024 * 1024 * 100) //100Mb
30 | return OkHttpClient.Builder()
31 | .addInterceptor(LoggingInterceptor())
32 | .cache(cache)
33 | }
34 |
35 | fun create(): ApiService {
36 | return Retrofit.Builder()
37 | .baseUrl(BASE_URL)
38 | .client(okHttpClientBuilder.build())
39 | .addConverterFactory(GsonConverterFactory.create())
40 | .build()
41 | .create(ApiService::class.java)
42 | }
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/server/LoggingInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.server
2 |
3 | import android.util.Log
4 | import okhttp3.Interceptor
5 | import okhttp3.Response
6 | import java.io.IOException
7 |
8 | /**
9 | * Created by zhpan on 2020/7/8.
10 | * Description:
11 | */
12 | class LoggingInterceptor : Interceptor {
13 | companion object {
14 | val TAG: String = "LOG"
15 | }
16 |
17 | @Throws(IOException::class)
18 | override fun intercept(chain: Interceptor.Chain): Response {
19 | //这个chain里面包含了request和response,所以你要什么都可以从这里拿
20 | val request = chain.request()
21 | val t1 = System.nanoTime() //请求发起的时间
22 | Log.e(
23 | TAG, String.format(
24 | "请求URL------%s on %s%n请求头------%s",
25 | request.url(), chain.connection(), request.headers()
26 | )
27 | )
28 |
29 | val response = chain.proceed(request)
30 | val t2 = System.nanoTime() //收到响应的时间
31 |
32 | //这里不能直接使用response.body().string()的方式输出日志
33 | //因为response.body().string()之后,response中的流会被关闭,程序会报错,我们需要创建出一
34 | //个新的response给应用层处理
35 | val responseBody = response.peekBody(1024 * 1024.toLong())
36 | Log.e(
37 | TAG, String.format(
38 | "响应URL-------: %s %n响应数据------%s 请求用时--------%.1fms%n%s",
39 | response.request().url(),
40 | responseBody.string(),
41 | (t2 - t1) / 1e6,
42 | response.headers()
43 | )
44 | )
45 | return response
46 | }
47 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/view/CircleView.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.view;
2 |
3 | import android.animation.ObjectAnimator;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.util.AttributeSet;
9 | import android.util.Log;
10 | import android.view.View;
11 |
12 | /**
13 | * Created by zhpan on 2019/07/20.
14 | */
15 |
16 | public class CircleView extends View {
17 | private Paint mPaint;
18 |
19 | public CircleView(Context context) {
20 | this(context, null);
21 | }
22 |
23 | public CircleView(Context context, AttributeSet attrs) {
24 | this(context, attrs, 0);
25 | }
26 |
27 | public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
28 | super(context, attrs, defStyleAttr);
29 | mPaint = new Paint();
30 | mPaint.setColor(Color.parseColor("#FF0000"));
31 | mPaint.setAntiAlias(true);
32 | }
33 |
34 | public void setCirCleColor(int color) {
35 | mPaint.setColor(color);
36 | invalidate();
37 | }
38 |
39 | @Override
40 | protected void onDraw(Canvas canvas) {
41 | super.onDraw(canvas);
42 | int width = getWidth();
43 | int height = getHeight();
44 | float radius = Math.min(width, height) / 2f;
45 | canvas.drawCircle(width / 2f, height / 2f, radius, mPaint);
46 | }
47 |
48 | public void setProgress(float progress) {
49 | Log.e("CircleView", "progress---->" + progress);
50 | }
51 |
52 | public void startAnimate() {
53 | ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "progress", 0, 1f);
54 | objectAnimator.setDuration(200);
55 | objectAnimator.start();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/view/CornerImageView.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.view
2 |
3 | import android.content.Context
4 | import android.os.Build
5 | import android.util.AttributeSet
6 |
7 | import androidx.appcompat.widget.AppCompatImageView
8 | import com.zhpan.bannerview.provider.ViewStyleSetter
9 |
10 | class CornerImageView @JvmOverloads constructor(
11 | context: Context,
12 | attrs: AttributeSet? = null,
13 | defStyleAttr: Int = 0
14 | ) : AppCompatImageView(context, attrs, defStyleAttr) {
15 |
16 | fun setRoundCorner(radius: Int) {
17 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
18 | ViewStyleSetter.applyRoundCorner(this, radius.toFloat())
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/library/src/main/java/com/zhpan/library/view/ItemView.kt:
--------------------------------------------------------------------------------
1 | package com.zhpan.library.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.widget.RelativeLayout
6 | import android.widget.TextView
7 | import com.blankj.utilcode.util.ConvertUtils
8 | import com.zhpan.library.R
9 |
10 | /**
11 | *
12 | * Created by zhpan on 2020/1/4.
13 | * Description:
14 | *
15 | */
16 | class ItemView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : RelativeLayout(context, attrs, defStyleAttr) {
17 |
18 | private val mTextView: TextView
19 |
20 | init {
21 | inflate(context, R.layout.item_view, this)
22 | mTextView = findViewById(R.id.item_text)
23 | layoutParams?.height = ConvertUtils.dp2px(45f)
24 | if (attrs != null) {
25 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ItemView)
26 | val string = typedArray.getString(R.styleable.ItemView_item_text)
27 | mTextView.text = string
28 | typedArray.recycle()
29 | }
30 | }
31 |
32 | fun setItemText(text: CharSequence) {
33 | mTextView.text = text
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/item_defalut_loadmore_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/item_defalut_refresh_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/item_head_foot_parent.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/item_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
7 | #F5F5F5
8 | #E0E0E0
9 | #F4C7C3
10 | #E67C73
11 | #DB4437
12 | #C53929
13 | #C6DAFC
14 | #7BAAF7
15 | #4285F4
16 | #3367D6
17 | #B7E1CD
18 | #57BB8A
19 | #0F9D58
20 | #0B8043
21 | #FCE8B2
22 | #F7CB4D
23 | #F4B400
24 | #F09300
25 |
26 | #efe5fd
27 | #d4bff9
28 | #6200EE
29 | #03DAC5
30 | #4DB6AC
31 |
32 | #FF4C39
33 | #935656
34 | #FAFAFA
35 | #212121
36 | #CCCCCC
37 | #FFFFFF
38 | #F7F7F7
39 | #00000000
40 |
41 | #b0ffffff
42 | #e4e4e4
43 |
44 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/library/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/library/src/test/java/com/zhpan/library/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.zhpan.library;
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() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name='ViewPagerSample'
3 | include ':library'
4 |
--------------------------------------------------------------------------------