├── .gitignore ├── .idea ├── caches │ ├── build_file_checksums.ser │ └── gradle_models.ser ├── codeStyles │ └── Project.xml ├── dbnavigator.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zinc │ │ └── jrecycleview │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zinc │ │ │ └── jrecycleview │ │ │ ├── MainActivity.java │ │ │ ├── MyApp.java │ │ │ ├── anim │ │ │ ├── AnimActivity.java │ │ │ ├── AnimAdapter.java │ │ │ ├── ScaleToMissAnimation.java │ │ │ └── dialog │ │ │ │ ├── AnimAdapter.java │ │ │ │ ├── AnimData.java │ │ │ │ └── AnimDialog.java │ │ │ ├── data │ │ │ └── SwipeData.java │ │ │ ├── diy │ │ │ ├── DiyArticleAdapter.java │ │ │ ├── DiyArticleListActivity.java │ │ │ ├── DiyData.java │ │ │ └── UIUtils.java │ │ │ ├── mix │ │ │ ├── Constant.java │ │ │ ├── MixActivity.java │ │ │ ├── MixAdapter.java │ │ │ ├── MixData.java │ │ │ └── dialog │ │ │ │ ├── MixAdapter.java │ │ │ │ ├── MixDialog.java │ │ │ │ └── MixShowInfoData.java │ │ │ ├── refreshAndLoad │ │ │ ├── RefreshAndLoadActivity.java │ │ │ └── RefreshAndLoadAdapter.java │ │ │ ├── stick │ │ │ ├── content │ │ │ │ ├── StickContentActivity.java │ │ │ │ └── StickContentAdapter.java │ │ │ └── header │ │ │ │ ├── StickHeaderActivity.java │ │ │ │ └── StickHeaderAdapter.java │ │ │ ├── swipe │ │ │ ├── SwipeActivity.java │ │ │ └── SwipeAdapter.java │ │ │ └── widget │ │ │ └── MyRefreshView.java │ └── res │ │ ├── drawable-xhdpi │ │ ├── logo.png │ │ ├── meituan_pull_image.png │ │ ├── meituan_pull_to_refresh_anim.xml │ │ ├── meituan_refreshing_anim.xml │ │ ├── pull_end_image_frame_01.png │ │ ├── pull_end_image_frame_02.png │ │ ├── pull_end_image_frame_03.png │ │ ├── pull_end_image_frame_04.png │ │ ├── pull_end_image_frame_05.png │ │ ├── refreshing_image_frame_01.png │ │ ├── refreshing_image_frame_02.png │ │ ├── refreshing_image_frame_03.png │ │ ├── refreshing_image_frame_04.png │ │ ├── refreshing_image_frame_05.png │ │ ├── refreshing_image_frame_06.png │ │ ├── refreshing_image_frame_07.png │ │ └── refreshing_image_frame_08.png │ │ ├── drawable │ │ ├── ic_check.xml │ │ ├── selector_background_round.xml │ │ ├── selector_blue_round_5dp.xml │ │ └── shape_dialog_bg.xml │ │ ├── layout │ │ ├── activity_anim.xml │ │ ├── activity_main.xml │ │ ├── activity_mix.xml │ │ ├── activity_refresh_and_load.xml │ │ ├── activity_stick.xml │ │ ├── activity_swipe.xml │ │ ├── activity_yctc_article_list.xml │ │ ├── dialog_anim.xml │ │ ├── dialog_mix.xml │ │ ├── item_anim.xml │ │ ├── item_article_banner.xml │ │ ├── item_article_content.xml │ │ ├── item_article_sort.xml │ │ ├── item_mix.xml │ │ ├── refresh_and_load_view_item.xml │ │ ├── stick_item.xml │ │ ├── swipe_content.xml │ │ ├── swipe_left_menu.xml │ │ ├── swipe_only_left.xml │ │ ├── swipe_only_right.xml │ │ ├── swipe_right_menu.xml │ │ └── view_my_refresh.xml │ │ ├── menu │ │ └── layout_menu.xml │ │ ├── values-v21 │ │ └── styles.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── zinc │ └── jrecycleview │ └── ExampleUnitTest.java ├── build.gradle ├── cer └── JRecycleView.jks ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── anim_item.gif ├── diy.gif ├── diy_pull_and_load.gif ├── multi_use.gif ├── pull_and_load.gif ├── stick_content.gif ├── stick_head.gif ├── swipe.gif └── zincPay.jpg ├── lib.recycleview ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zinc │ │ └── librecycleview │ │ └── ExampleInstrumentedTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── zinc │ │ └── jrecycleview │ │ ├── JRecycleView.java │ │ ├── adapter │ │ ├── JBaseRecycleAdapter.java │ │ └── JRefreshAndLoadMoreAdapter.java │ │ ├── anim │ │ ├── AlphaAnimation.java │ │ ├── AnimFactory.java │ │ ├── IBaseAnimation.java │ │ ├── ScaleAnimation.java │ │ ├── SlideInBottomAnimation.java │ │ ├── SlideInLeftAnimation.java │ │ ├── SlideInRightAnimation.java │ │ └── SlideInTopAnimation.java │ │ ├── config │ │ ├── JRecycleConfig.java │ │ └── JRecycleViewManager.java │ │ ├── listener │ │ └── JRecycleListener.java │ │ ├── loadview │ │ ├── OrdinaryLoadMoreView.java │ │ ├── OrdinaryRefreshLoadView.java │ │ ├── base │ │ │ ├── IBaseLoadMoreView.java │ │ │ ├── IBaseRefreshLoadView.java │ │ │ └── IBaseWrapperView.java │ │ └── bean │ │ │ └── MoveInfo.java │ │ ├── stick │ │ └── IStick.java │ │ ├── swipe │ │ ├── JSwipeConstant.java │ │ ├── JSwipeItemLayout.java │ │ └── JSwipeViewHolder.java │ │ ├── utils │ │ ├── LogUtils.java │ │ ├── MathUtil.java │ │ └── PointEvaluator.java │ │ └── widget │ │ ├── BallSpinFadeLoader.java │ │ └── StickDotView.java │ └── res │ ├── drawable-xhdpi │ └── red_bg.9.png │ ├── drawable │ ├── j_recycle_icon_refresh_arrow.png │ └── j_recycle_icon_reload.png │ ├── layout │ ├── j_swipe_wrapper.xml │ ├── j_widget_ordinary_load_more_view.xml │ └── j_widget_ordinary_load_refresh_view.xml │ ├── mipmap-xhdpi │ ├── explode1.png │ ├── explode2.png │ ├── explode3.png │ ├── explode4.png │ └── explode5.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ └── strings.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/caches/gradle_models.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/.idea/caches/gradle_models.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 26 | 27 | 28 | 29 | 31 | 32 | 33 |
34 | 35 | 36 | 37 | xmlns:android 38 | 39 | ^$ 40 | 41 | 42 | 43 |
44 |
45 | 46 | 47 | 48 | xmlns:.* 49 | 50 | ^$ 51 | 52 | 53 | BY_NAME 54 | 55 |
56 |
57 | 58 | 59 | 60 | .*:id 61 | 62 | http://schemas.android.com/apk/res/android 63 | 64 | 65 | 66 |
67 |
68 | 69 | 70 | 71 | .*:name 72 | 73 | http://schemas.android.com/apk/res/android 74 | 75 | 76 | 77 |
78 |
79 | 80 | 81 | 82 | name 83 | 84 | ^$ 85 | 86 | 87 | 88 |
89 |
90 | 91 | 92 | 93 | style 94 | 95 | ^$ 96 | 97 | 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | ^$ 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 | 114 | 115 | 116 | .* 117 | 118 | http://schemas.android.com/apk/res/android 119 | 120 | 121 | ANDROID_ATTRIBUTE_ORDER 122 | 123 |
124 |
125 | 126 | 127 | 128 | .* 129 | 130 | .* 131 | 132 | 133 | BY_NAME 134 | 135 |
136 |
137 |
138 |
139 |
140 |
-------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | 6 | defaultConfig { 7 | applicationId "com.zinc.jrecycleview" 8 | minSdkVersion rootProject.ext.minSdkVersion 9 | targetSdkVersion rootProject.ext.targetSdkVersion 10 | versionCode rootProject.ext.versionCode 11 | versionName rootProject.ext.versionName 12 | 13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 14 | } 15 | 16 | signingConfigs { 17 | 18 | release { 19 | storeFile file("../cer/JRecycleView.jks") 20 | storePassword RELEASE_STORE_PASSWORD 21 | keyAlias RELEASE_KEY_ALIAS 22 | keyPassword RELEASE_KEY_PASSWORD 23 | } 24 | 25 | } 26 | 27 | buildTypes { 28 | release { 29 | minifyEnabled false 30 | signingConfig signingConfigs.release 31 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 32 | } 33 | } 34 | compileOptions { 35 | sourceCompatibility = '1.8' 36 | targetCompatibility = '1.8' 37 | } 38 | } 39 | 40 | dependencies { 41 | implementation fileTree(dir: 'libs', include: ['*.jar']) 42 | implementation "androidx.appcompat:appcompat:$androidx" 43 | implementation 'com.google.android.material:material:1.0.0' 44 | 45 | testImplementation 'junit:junit:4.12' 46 | 47 | implementation project(":lib.recycleview") 48 | } 49 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the mAnimSet 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/androidTest/java/com/zinc/jrecycleview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zinc.jrecycleview", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | 7 | import androidx.annotation.Nullable; 8 | import androidx.appcompat.app.AppCompatActivity; 9 | 10 | import com.zinc.jrecycleview.anim.dialog.AnimDialog; 11 | import com.zinc.jrecycleview.diy.DiyArticleListActivity; 12 | import com.zinc.jrecycleview.mix.dialog.MixDialog; 13 | import com.zinc.jrecycleview.refreshAndLoad.RefreshAndLoadActivity; 14 | import com.zinc.jrecycleview.stick.content.StickContentActivity; 15 | import com.zinc.jrecycleview.stick.header.StickHeaderActivity; 16 | import com.zinc.jrecycleview.swipe.SwipeActivity; 17 | 18 | /** 19 | * author : Jiang Pengyong 20 | * time : 2018-04-16 22:20 21 | * email : 56002982@qq.com 22 | * desc : 主视图 23 | * version : 1.0.0 24 | */ 25 | 26 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 27 | 28 | private AnimDialog mAnimDialog; 29 | private MixDialog mMixDialog; 30 | 31 | @Override 32 | protected void onCreate(@Nullable Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_main); 35 | 36 | mAnimDialog = AnimDialog.newInstance(); 37 | mMixDialog = MixDialog.newInstance(); 38 | 39 | findViewById(R.id.tv_mix).setOnClickListener(this); 40 | findViewById(R.id.tv_load_and_refresh).setOnClickListener(this); 41 | findViewById(R.id.tv_diy_refresh).setOnClickListener(this); 42 | findViewById(R.id.tv_anim).setOnClickListener(this); 43 | findViewById(R.id.tv_swipe).setOnClickListener(this); 44 | findViewById(R.id.tv_stick_header).setOnClickListener(this); 45 | findViewById(R.id.tv_stick_content).setOnClickListener(this); 46 | findViewById(R.id.tv_diy).setOnClickListener(this); 47 | 48 | } 49 | 50 | @Override 51 | public void onClick(View v) { 52 | switch (v.getId()) { 53 | case R.id.tv_mix: 54 | mMixDialog.show(getSupportFragmentManager(), "Mix"); 55 | break; 56 | case R.id.tv_load_and_refresh: 57 | Intent intent1 = new Intent(this, RefreshAndLoadActivity.class); 58 | intent1.putExtra(RefreshAndLoadActivity.IS_DIY, false); 59 | startActivity(intent1); 60 | break; 61 | case R.id.tv_diy_refresh: 62 | Intent intent2 = new Intent(this, RefreshAndLoadActivity.class); 63 | intent2.putExtra(RefreshAndLoadActivity.IS_DIY, true); 64 | startActivity(intent2); 65 | break; 66 | case R.id.tv_swipe: 67 | go(SwipeActivity.class); 68 | break; 69 | case R.id.tv_anim: 70 | mAnimDialog.show(getSupportFragmentManager(), "Anim"); 71 | break; 72 | case R.id.tv_stick_header: 73 | go(StickHeaderActivity.class); 74 | break; 75 | case R.id.tv_stick_content: 76 | go(StickContentActivity.class); 77 | break; 78 | case R.id.tv_diy: 79 | go(DiyArticleListActivity.class); 80 | break; 81 | } 82 | } 83 | 84 | private void go(Class to) { 85 | Intent intent = new Intent(this, to); 86 | startActivity(intent); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/MyApp.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview; 2 | 3 | import android.app.Application; 4 | 5 | import com.zinc.jrecycleview.anim.AnimFactory; 6 | import com.zinc.jrecycleview.config.JRecycleViewManager; 7 | 8 | /** 9 | * author : Jiang Pengyong 10 | * time : 2018-04-08 23:07 11 | * email : 56002982@qq.com 12 | * desc : 应用application 13 | * version : 1.0.0 14 | */ 15 | 16 | public class MyApp extends Application { 17 | 18 | @Override 19 | public void onCreate() { 20 | super.onCreate(); 21 | 22 | JRecycleViewManager.getInstance() 23 | .setItemAnimations(AnimFactory.getAnimSet(AnimFactory.SLIDE_RIGHT)) 24 | .setIsDebug(true); 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/anim/AnimActivity.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | import androidx.appcompat.app.AppCompatActivity; 8 | import androidx.recyclerview.widget.LinearLayoutManager; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import com.zinc.jrecycleview.R; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * author : Jiang Pengyong 18 | * time : 2018-04-17 22:23 19 | * email : 56002982@qq.com 20 | * desc : 动画 21 | * version : 1.0.0 22 | */ 23 | 24 | public class AnimActivity extends AppCompatActivity { 25 | 26 | private static final String TYPE = "ANIM_TYPE"; 27 | 28 | private final static int PAGE_SIZE = 100; 29 | private RecyclerView mRecycleView; 30 | 31 | private AnimAdapter mAdapter; 32 | private final List data = new ArrayList<>(); 33 | private int mType; 34 | 35 | public static void startActivity(Context context, int type) { 36 | Intent intent = new Intent(context, AnimActivity.class); 37 | 38 | intent.putExtra(TYPE, type); 39 | 40 | context.startActivity(intent); 41 | } 42 | 43 | @Override 44 | protected void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | setContentView(R.layout.activity_anim); 47 | 48 | mType = getIntent().getIntExtra(TYPE, AnimFactory.SLIDE_TOP); 49 | 50 | mRecycleView = findViewById(R.id.recycle_view); 51 | 52 | getInitData(); 53 | 54 | mAdapter = new AnimAdapter(this, data); 55 | // 加入视图动画 56 | // 设置动画(设置动画会默认开启动画) 57 | mAdapter.setAnimations(AnimFactory.getAnimSet(mType)); 58 | mAdapter.setOpenAnim(true); 59 | 60 | mRecycleView.setLayoutManager(new LinearLayoutManager(this)); 61 | mRecycleView.setAdapter(mAdapter); 62 | 63 | } 64 | 65 | public void getInitData() { 66 | data.clear(); 67 | for (int i = 1; i <= PAGE_SIZE; ++i) { 68 | data.add("zinc Power" + i); 69 | } 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/anim/AnimAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.recyclerview.widget.RecyclerView; 11 | 12 | import com.zinc.jrecycleview.R; 13 | import com.zinc.jrecycleview.adapter.JBaseRecycleAdapter; 14 | 15 | import java.lang.ref.WeakReference; 16 | import java.util.List; 17 | 18 | /** 19 | * author : Jiang Pengyong 20 | * time : 2018-04-08 22:25 21 | * email : 56002982@qq.com 22 | * desc : 动画适配器 23 | * version : 1.0.0 24 | */ 25 | 26 | public class AnimAdapter extends JBaseRecycleAdapter { 27 | 28 | private final List mData; 29 | private final LayoutInflater mLayoutInflater; 30 | 31 | AnimAdapter(Context context, 32 | List data) { 33 | mLayoutInflater = LayoutInflater.from(context); 34 | mData = data; 35 | } 36 | 37 | @NonNull 38 | @Override 39 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, 40 | int viewType) { 41 | return new TestHolder( 42 | mLayoutInflater 43 | .inflate(R.layout.refresh_and_load_view_item, parent, false)); 44 | } 45 | 46 | @Override 47 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { 48 | String content = mData.get(position); 49 | TestHolder testHolder = (TestHolder) holder; 50 | testHolder.mTvContent.setText(content); 51 | } 52 | 53 | @Override 54 | public int getItemCount() { 55 | return mData.size(); 56 | } 57 | 58 | class TestHolder extends RecyclerView.ViewHolder { 59 | 60 | private TextView mTvContent; 61 | 62 | TestHolder(View itemView) { 63 | super(itemView); 64 | mTvContent = itemView.findViewById(R.id.tv_content); 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/anim/ScaleToMissAnimation.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.view.View; 5 | 6 | public class ScaleToMissAnimation extends IBaseAnimation { 7 | 8 | @Override 9 | protected void init(View view) { 10 | addAnimTogether(ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f)); 11 | addAnimTogether(ObjectAnimator.ofFloat(view, "scaleY", 1f, 0f)); 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/anim/dialog/AnimAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim.dialog; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.recyclerview.widget.RecyclerView; 11 | 12 | import com.zinc.jrecycleview.R; 13 | 14 | import java.lang.ref.WeakReference; 15 | import java.util.List; 16 | 17 | /** 18 | * author : Jiang Pengyong 19 | * time : 2019-08-24 22:03 20 | * email : 56002982@qq.com 21 | * desc : 动画选择列表适配器 22 | * version : 1.0.0 23 | */ 24 | public class AnimAdapter extends RecyclerView.Adapter { 25 | 26 | private final WeakReference mContext; 27 | private final LayoutInflater mInflater; 28 | private final List mData; 29 | private final AnimListener mListener; 30 | 31 | public AnimAdapter(Context context, 32 | List data, 33 | AnimListener listener) { 34 | this.mContext = new WeakReference<>(context); 35 | this.mInflater = LayoutInflater.from(context); 36 | this.mData = data; 37 | this.mListener = listener; 38 | } 39 | 40 | @NonNull 41 | @Override 42 | public AnimViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 43 | return new AnimViewHolder( 44 | mInflater.inflate(R.layout.item_anim, parent, false)); 45 | } 46 | 47 | @Override 48 | public void onBindViewHolder(@NonNull AnimViewHolder holder, int position) { 49 | AnimData animData = mData.get(position); 50 | holder.tvContent.setText(animData.getName()); 51 | holder.tvContent.setOnClickListener(v -> { 52 | mListener.onItemClick(animData.getType()); 53 | }); 54 | } 55 | 56 | @Override 57 | public int getItemCount() { 58 | return mData.size(); 59 | } 60 | 61 | static class AnimViewHolder extends RecyclerView.ViewHolder { 62 | private TextView tvContent; 63 | 64 | AnimViewHolder(View itemView) { 65 | super(itemView); 66 | 67 | tvContent = itemView.findViewById(R.id.tv_content); 68 | } 69 | } 70 | 71 | interface AnimListener { 72 | void onItemClick(int type); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/anim/dialog/AnimData.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim.dialog; 2 | 3 | /** 4 | * author : Jiang Pengyong 5 | * time : 2019-08-24 22:07 6 | * email : 56002982@qq.com 7 | * desc : 动画数据 8 | * version : 1.0.0 9 | */ 10 | public class AnimData { 11 | 12 | private int type; 13 | private String name; 14 | 15 | public AnimData(int type, String name) { 16 | this.type = type; 17 | this.name = name; 18 | } 19 | 20 | public int getType() { 21 | return type; 22 | } 23 | 24 | public String getName() { 25 | return name; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/anim/dialog/AnimDialog.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim.dialog; 2 | 3 | import android.os.Bundle; 4 | import android.view.Gravity; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.Window; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.annotation.Nullable; 12 | import androidx.appcompat.app.AppCompatDialogFragment; 13 | import androidx.fragment.app.DialogFragment; 14 | import androidx.recyclerview.widget.LinearLayoutManager; 15 | import androidx.recyclerview.widget.RecyclerView; 16 | 17 | import com.zinc.jrecycleview.R; 18 | import com.zinc.jrecycleview.anim.AnimActivity; 19 | import com.zinc.jrecycleview.anim.AnimFactory; 20 | import com.zinc.jrecycleview.diy.UIUtils; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | /** 26 | * author : Jiang Pengyong 27 | * time : 2018-11-02 21:27 28 | * email : 56002982@qq.com 29 | * desc : 动画选择器 30 | * version : 1.0.0 31 | */ 32 | 33 | public class AnimDialog extends AppCompatDialogFragment implements AnimAdapter.AnimListener { 34 | 35 | private RecyclerView mRecycleView; 36 | private static final List mData = new ArrayList<>(); 37 | 38 | static { 39 | mData.add(new AnimData(AnimFactory.SLIDE_TOP, "SLIDE_TOP")); 40 | mData.add(new AnimData(AnimFactory.SLIDE_RIGHT, "SLIDE_RIGHT")); 41 | mData.add(new AnimData(AnimFactory.SLIDE_BOTTOM, "SLIDE_BOTTOM")); 42 | mData.add(new AnimData(AnimFactory.SLIDE_LEFT, "SLIDE_LEFT")); 43 | mData.add(new AnimData(AnimFactory.SCALE, "SCALE")); 44 | mData.add(new AnimData(AnimFactory.ALPHA, "ALPHA")); 45 | } 46 | 47 | public static AnimDialog newInstance() { 48 | Bundle bundle = new Bundle(); 49 | 50 | AnimDialog fragment = new AnimDialog(); 51 | fragment.setArguments(bundle); 52 | 53 | return fragment; 54 | } 55 | 56 | @Override 57 | public void onCreate(@Nullable Bundle savedInstanceState) { 58 | super.onCreate(savedInstanceState); 59 | setStyle(DialogFragment.STYLE_NORMAL, R.style.BitFrameDialog); 60 | } 61 | 62 | @Override 63 | public View onCreateView(@NonNull LayoutInflater inflater, 64 | ViewGroup container, 65 | Bundle savedInstanceState) { 66 | return inflater.inflate(R.layout.dialog_anim, container, false); 67 | } 68 | 69 | @Override 70 | public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { 71 | super.onViewCreated(view, savedInstanceState); 72 | 73 | initWindows(getDialog().getWindow()); 74 | 75 | mRecycleView = view.findViewById(R.id.recycle_view); 76 | 77 | mRecycleView.setLayoutManager(new LinearLayoutManager(getContext())); 78 | mRecycleView.setAdapter(new AnimAdapter(getContext(), mData, this)); 79 | 80 | } 81 | 82 | private void initWindows(Window window) { 83 | View decorView = window.getDecorView(); 84 | decorView.setPadding(0, decorView.getPaddingTop(), 0, 0); 85 | window.setLayout(UIUtils.dip2px(getContext(), 300), 86 | UIUtils.dip2px(getContext(), 300)); 87 | window.setGravity(Gravity.CENTER); 88 | } 89 | 90 | @Override 91 | public void onItemClick(int type) { 92 | AnimActivity.startActivity(getContext(), type); 93 | dismiss(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/data/SwipeData.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.data; 2 | 3 | /** 4 | * author : Jiang Pengyong 5 | * time : 2018-04-08 21:19 6 | * email : 56002982@qq.com 7 | * desc : 测滑数据 8 | * version : 1.0.0 9 | */ 10 | 11 | public class SwipeData { 12 | 13 | private int type; 14 | private String content; 15 | 16 | private int readNum; 17 | 18 | public SwipeData(int type, String content, int readNum) { 19 | this.type = type; 20 | this.content = content; 21 | this.readNum = readNum; 22 | } 23 | 24 | public int getType() { 25 | return type; 26 | } 27 | 28 | public void setType(int type) { 29 | this.type = type; 30 | } 31 | 32 | public String getContent() { 33 | return content; 34 | } 35 | 36 | public void setContent(String content) { 37 | this.content = content; 38 | } 39 | 40 | public int getReadNum() { 41 | return readNum; 42 | } 43 | 44 | public void setReadNum(int readNum) { 45 | this.readNum = readNum; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/diy/DiyArticleAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.diy; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.recyclerview.widget.RecyclerView; 11 | 12 | import com.zinc.jrecycleview.R; 13 | import com.zinc.jrecycleview.stick.IStick; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * author : Jiang Pengyong 19 | * time : 2019-08-19 12:05 20 | * email : 56002982@qq.com 21 | * desc : 自定义联动适配器 22 | * version : 1.0.0 23 | */ 24 | public class DiyArticleAdapter extends RecyclerView.Adapter { 25 | 26 | static final int BANNER = 1; 27 | static final int SORT = 2; 28 | static final int CONTENT = 3; 29 | 30 | private final List mData; 31 | private final LayoutInflater mInflater; 32 | 33 | DiyArticleAdapter(Context context, List data) { 34 | mData = data; 35 | mInflater = LayoutInflater.from(context); 36 | } 37 | 38 | @NonNull 39 | @Override 40 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 41 | 42 | if (viewType == BANNER) { 43 | return new BannerViewHolder( 44 | mInflater.inflate(R.layout.item_article_banner, parent, false) 45 | ); 46 | } else if (viewType == SORT) { 47 | return new SortViewHolder( 48 | mInflater.inflate(R.layout.item_article_sort, parent, false) 49 | ); 50 | } else if (viewType == CONTENT) { 51 | return new ContentViewHolder( 52 | mInflater.inflate(R.layout.item_article_content, parent, false) 53 | ); 54 | } 55 | 56 | return null; 57 | 58 | } 59 | 60 | @Override 61 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { 62 | 63 | DiyData yctcData = mData.get(position); 64 | if (holder instanceof BannerViewHolder) { 65 | BannerViewHolder bannerViewHolder = (BannerViewHolder) holder; 66 | bannerViewHolder.tvBanner.setText(yctcData.getContent()); 67 | } else if (holder instanceof SortViewHolder) { 68 | SortViewHolder sortViewHolder = (SortViewHolder) holder; 69 | sortViewHolder.tvSort.setText(yctcData.getContent()); 70 | } else if (holder instanceof ContentViewHolder) { 71 | ContentViewHolder contentViewHolder = (ContentViewHolder) holder; 72 | contentViewHolder.tvContent.setText(yctcData.getContent()); 73 | } 74 | 75 | } 76 | 77 | @Override 78 | public int getItemCount() { 79 | return mData.size(); 80 | } 81 | 82 | @Override 83 | public int getItemViewType(int position) { 84 | return mData.get(position).getType(); 85 | } 86 | 87 | public static class BannerViewHolder extends RecyclerView.ViewHolder implements IStick { 88 | 89 | private TextView tvBanner; 90 | 91 | BannerViewHolder(View itemView) { 92 | super(itemView); 93 | tvBanner = itemView.findViewById(R.id.tv_banner); 94 | } 95 | 96 | } 97 | 98 | static class SortViewHolder extends RecyclerView.ViewHolder { 99 | 100 | private TextView tvSort; 101 | 102 | SortViewHolder(View itemView) { 103 | super(itemView); 104 | tvSort = itemView.findViewById(R.id.tv_sort); 105 | } 106 | 107 | } 108 | 109 | static class ContentViewHolder extends RecyclerView.ViewHolder { 110 | 111 | private TextView tvContent; 112 | 113 | ContentViewHolder(View itemView) { 114 | super(itemView); 115 | tvContent = itemView.findViewById(R.id.tv_content); 116 | } 117 | 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/diy/DiyArticleListActivity.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.diy; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.util.Log; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.LinearLayout; 12 | import android.widget.TextView; 13 | 14 | import androidx.annotation.Nullable; 15 | import androidx.appcompat.app.AppCompatActivity; 16 | import androidx.recyclerview.widget.LinearLayoutManager; 17 | import androidx.recyclerview.widget.RecyclerView; 18 | 19 | import com.zinc.jrecycleview.JRecycleView; 20 | import com.zinc.jrecycleview.R; 21 | import com.zinc.jrecycleview.adapter.JRefreshAndLoadMoreAdapter; 22 | import com.zinc.jrecycleview.listener.JRecycleListener; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | /** 28 | * author : Jiang Pengyong 29 | * time : 2019-08-19 11:51 30 | * email : 56002982@qq.com 31 | * desc : 自定义联动视图 32 | * version : 1.0.0 33 | */ 34 | public class DiyArticleListActivity extends AppCompatActivity { 35 | 36 | private static final String TAG = "DiyArticleListActivity"; 37 | 38 | private static final int DURATION = 200; 39 | 40 | private int mSubHeight; 41 | 42 | private static final int PAGE_SIZE = 20; 43 | 44 | private LinearLayout llTopCategory; 45 | private LinearLayout llSubCategory; 46 | private JRecycleView jRecycleView; 47 | private TextView tvTab; 48 | private TextView tvSort; 49 | 50 | private DiyArticleAdapter mAdapter; 51 | private final List mData = new ArrayList<>(); 52 | 53 | private ValueAnimator mAnim; 54 | 55 | private Handler mHandler = new Handler(Looper.getMainLooper()); 56 | 57 | @Override 58 | protected void onCreate(@Nullable Bundle savedInstanceState) { 59 | super.onCreate(savedInstanceState); 60 | setContentView(R.layout.activity_yctc_article_list); 61 | 62 | llTopCategory = findViewById(R.id.ll_top_category); 63 | llSubCategory = findViewById(R.id.ll_sub_category); 64 | jRecycleView = findViewById(R.id.j_recycle_view); 65 | tvTab = findViewById(R.id.tv_tab); 66 | tvSort = findViewById(R.id.tv_sort); 67 | 68 | mSubHeight = UIUtils.dip2px(this, 45); 69 | 70 | initAnim(); 71 | 72 | tvSort.setVisibility(View.GONE); 73 | 74 | jRecycleView.setListener(new JRecycleListener() { 75 | @Override 76 | public boolean onTouch(MotionEvent event, float deltaY) { 77 | 78 | // 这里要使用 llSubCategory.getLayoutParams().height; 79 | // 因为 llSubCategory.getHeight() 的值为可见值,操作过快会有可能和预期不同 80 | int height = llSubCategory.getLayoutParams().height; 81 | 82 | Log.i(TAG, "onTouch: [height:" + height + "; deltaY:" + deltaY + "]"); 83 | 84 | if (height <= 0 && deltaY < 0) { 85 | return false; 86 | } else if (height >= mSubHeight && deltaY > 0) { 87 | return false; 88 | } else { 89 | setSubCateHeight((int) (height + deltaY)); 90 | return true; 91 | } 92 | } 93 | 94 | @Override 95 | public boolean onUp(MotionEvent event) { 96 | 97 | int curHeight = llSubCategory.getLayoutParams().height; 98 | 99 | Log.i(TAG, "activity onUp: " + curHeight); 100 | 101 | if (curHeight >= mSubHeight || curHeight <= 0) { 102 | return false; 103 | } 104 | 105 | int halfHeight = mSubHeight >> 1; 106 | 107 | if (mAnim.isRunning()) { 108 | mAnim.cancel(); 109 | } 110 | 111 | if (curHeight > halfHeight) { 112 | mAnim.setIntValues(curHeight, mSubHeight); 113 | } else { 114 | mAnim.setIntValues(curHeight, 0); 115 | } 116 | mAnim.start(); 117 | 118 | return true; 119 | } 120 | }); 121 | 122 | jRecycleView.addOnScrollListener(new RecyclerView.OnScrollListener() { 123 | @Override 124 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 125 | 126 | View firstView = recyclerView.getLayoutManager().getChildAt(0); 127 | if (firstView == null) { 128 | return; 129 | } 130 | 131 | RecyclerView.ViewHolder childViewHolder = recyclerView.getChildViewHolder(firstView); 132 | 133 | if (childViewHolder == null) { 134 | return; 135 | } 136 | 137 | if (childViewHolder instanceof DiyArticleAdapter.SortViewHolder 138 | || childViewHolder instanceof DiyArticleAdapter.ContentViewHolder) { 139 | tvSort.setVisibility(View.VISIBLE); 140 | } else { 141 | tvSort.setVisibility(View.GONE); 142 | } 143 | } 144 | }); 145 | 146 | initData(); 147 | 148 | DiyArticleAdapter yctcArticleAdapter = new DiyArticleAdapter(this, mData); 149 | JRefreshAndLoadMoreAdapter adapter 150 | = new JRefreshAndLoadMoreAdapter(this, yctcArticleAdapter); 151 | 152 | jRecycleView.setAdapter(adapter); 153 | jRecycleView.setLayoutManager(new LinearLayoutManager(this)); 154 | 155 | adapter.setOnLoadMoreListener(() -> { 156 | mHandler.postDelayed(() -> { 157 | 158 | int size = mData.size(); 159 | 160 | addData(); 161 | adapter.setLoadComplete(); 162 | adapter.setRefreshComplete(); 163 | adapter.notifyItemRangeInserted(size, PAGE_SIZE); 164 | 165 | }, 2000); 166 | }); 167 | 168 | adapter.setOnRefreshListener(() -> { 169 | mHandler.postDelayed(() -> { 170 | 171 | initData(); 172 | adapter.setLoadComplete(); 173 | adapter.setRefreshComplete(); 174 | adapter.notifyDataSetChanged(); 175 | 176 | }, 2000); 177 | }); 178 | 179 | 180 | llSubCategory.post(new Runnable() { 181 | @Override 182 | public void run() { 183 | Log.i(TAG, "run: " + llSubCategory.getY()); 184 | } 185 | }); 186 | } 187 | 188 | private void initAnim() { 189 | mAnim = new ValueAnimator(); 190 | mAnim.setDuration(DURATION); 191 | mAnim.addUpdateListener(animation -> { 192 | int value = (int) animation.getAnimatedValue(); 193 | setSubCateHeight(value); 194 | }); 195 | } 196 | 197 | private void setSubCateHeight(int height) { 198 | Log.i(TAG, "setSubCateHeight: [height: " + height + "]"); 199 | 200 | if (height > mSubHeight) { 201 | height = mSubHeight; 202 | } else if (height < 0) { 203 | height = 0; 204 | } 205 | 206 | ViewGroup.LayoutParams layoutParams = llSubCategory.getLayoutParams(); 207 | layoutParams.height = height; 208 | llSubCategory.setLayoutParams(layoutParams); 209 | } 210 | 211 | private void initData() { 212 | mData.clear(); 213 | mData.add(new DiyData(DiyArticleAdapter.BANNER, 214 | "BannerBannerBannerBannerBanner" + 215 | "BannerBannerBannerBannerBannerBanner" + 216 | "BannerBannerBannerBannerBanner" + 217 | "BannerBannerBannerBannerBanner" + 218 | "BannerBannerBannerBannerBanner" + 219 | "BannerBannerBannerBannerBanner" + 220 | "BannerBannerBannerBannerBanner" + 221 | "BannerBannerBannerBannerBanner" + 222 | "BannerBannerBannerBannerBanner" + 223 | "BannerBannerBannerBannerBanner" + 224 | "BannerBannerBannerBannerBanner")); 225 | mData.add(new DiyData(DiyArticleAdapter.SORT, "Sort")); 226 | for (int i = 1; i <= PAGE_SIZE; ++i) { 227 | mData.add(new DiyData(DiyArticleAdapter.CONTENT, "Content " + i)); 228 | } 229 | } 230 | 231 | private void addData() { 232 | int size = mData.size(); 233 | for (int i = 1; i < PAGE_SIZE; ++i) { 234 | mData.add(new DiyData(DiyArticleAdapter.CONTENT, "Content " + (size + i))); 235 | } 236 | } 237 | 238 | } 239 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/diy/DiyData.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.diy; 2 | 3 | /** 4 | * author : Jiang Pengyong 5 | * time : 2019-08-19 12:13 6 | * desc : 自定义联动数据 7 | * version : 1.0.0 8 | */ 9 | public class DiyData { 10 | 11 | private int type; 12 | private String content; 13 | 14 | DiyData(int type, String content) { 15 | this.type = type; 16 | this.content = content; 17 | } 18 | 19 | public int getType() { 20 | return type; 21 | } 22 | 23 | public String getContent() { 24 | return content; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/diy/UIUtils.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.diy; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | import android.view.WindowManager; 6 | 7 | /** 8 | * author : Jiang Pengyong 9 | * time : 2016-07-15 14:33 10 | * email : 56002982@qq.com 11 | * desc : UI 工具 12 | * version : 1.0.0 13 | */ 14 | 15 | public class UIUtils { 16 | 17 | public static int dip2px(Context context, float dipValue) { 18 | float density = context.getResources().getDisplayMetrics().density; 19 | return (int) (dipValue * density + 0.5f); 20 | } 21 | 22 | public static int px2dip(Context context, float pxValue) { 23 | float density = context.getResources().getDisplayMetrics().density; 24 | return (int) (pxValue / density + 0.5f); 25 | } 26 | 27 | public static int sp2px(Context context, float spValue) { 28 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 29 | return (int) (spValue * fontScale + 0.5f); 30 | } 31 | 32 | public static int getScreenWidth(Context context) { 33 | DisplayMetrics metrics = new DisplayMetrics(); 34 | ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay() 35 | .getMetrics(metrics); 36 | return metrics.widthPixels; 37 | } 38 | 39 | public static int getScreenHeight(Context context) { 40 | DisplayMetrics metrics = new DisplayMetrics(); 41 | ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay() 42 | .getMetrics(metrics); 43 | return metrics.heightPixels; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/mix/Constant.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.mix; 2 | 3 | /** 4 | * author : Jiang Pengyong 5 | * time : 2019-08-24 23:34 6 | * email : 56002982@qq.com 7 | * desc : 可选择的类型 8 | * version : 1.0.0 9 | */ 10 | public interface Constant { 11 | 12 | int REFRESH = 1; 13 | int LOAD_MORE = 2; 14 | int SWIPE = 3; 15 | int ANIM = 4; 16 | int STICK = 5; 17 | 18 | interface DATA_TYPE { 19 | int STICK = 0; 20 | int NORMAL = 1; 21 | int SWIPE = 2; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/mix/MixActivity.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.mix; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.os.Looper; 8 | 9 | import androidx.annotation.Nullable; 10 | import androidx.appcompat.app.AppCompatActivity; 11 | import androidx.recyclerview.widget.LinearLayoutManager; 12 | 13 | import com.zinc.jrecycleview.JRecycleView; 14 | import com.zinc.jrecycleview.R; 15 | import com.zinc.jrecycleview.adapter.JRefreshAndLoadMoreAdapter; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.Random; 20 | 21 | /** 22 | * author : Jiang Pengyong 23 | * time : 2019-08-24 22:49 24 | * email : 56002982@qq.com 25 | * desc : 混合视图 26 | * version : 1.0.0 27 | */ 28 | public class MixActivity extends AppCompatActivity { 29 | 30 | private static final int PAGE_SIZE = 20; 31 | 32 | private static final String REFRESH = "REFRESH"; 33 | private static final String LOAD_MORE = "LOAD_MORE"; 34 | private static final String SWIPE = "SWIPE"; 35 | private static final String ANIM = "ANIM"; 36 | private static final String STICK = "STICK"; 37 | 38 | private boolean refresh; 39 | private boolean loadMore; 40 | private boolean swipe; 41 | private boolean anim; 42 | private boolean stick; 43 | 44 | private JRecycleView recycleView; 45 | 46 | private Random mRandom; 47 | 48 | private final Handler mHandler = new Handler(Looper.getMainLooper()); 49 | 50 | private final List mValidType = new ArrayList<>(); 51 | 52 | private JRefreshAndLoadMoreAdapter mAdapter; 53 | 54 | public static void startActivity(Context context, 55 | boolean isRefresh, 56 | boolean isLoadMore, 57 | boolean isSwipe, 58 | boolean isAnim, 59 | boolean isStick) { 60 | Intent intent = new Intent(context, MixActivity.class); 61 | 62 | intent.putExtra(REFRESH, isRefresh); 63 | intent.putExtra(LOAD_MORE, isLoadMore); 64 | intent.putExtra(SWIPE, isSwipe); 65 | intent.putExtra(ANIM, isAnim); 66 | intent.putExtra(STICK, isStick); 67 | 68 | context.startActivity(intent); 69 | } 70 | 71 | @Override 72 | public void onCreate(@Nullable Bundle savedInstanceState) { 73 | super.onCreate(savedInstanceState); 74 | setContentView(R.layout.activity_mix); 75 | 76 | mRandom = new Random(); 77 | 78 | initIntent(getIntent()); 79 | initType(); 80 | initData(); 81 | 82 | mAdapter = new JRefreshAndLoadMoreAdapter(this, new MixAdapter(this, mData)); 83 | 84 | mAdapter.setIsOpenRefresh(refresh); 85 | mAdapter.setIsOpenLoadMore(loadMore); 86 | mAdapter.setOpenAnim(anim); 87 | 88 | mAdapter.setOnRefreshListener(() -> { 89 | mHandler.postDelayed(() -> { 90 | 91 | initData(); 92 | // 将 "上拉加载更多" 重置 93 | mAdapter.resetLoadMore(); 94 | // 将 "下拉刷新" 95 | mAdapter.setRefreshComplete(); 96 | // 刷新数据 97 | mAdapter.notifyDataSetChanged(); 98 | 99 | }, 2000); 100 | 101 | }); 102 | 103 | mAdapter.setOnLoadMoreListener(() -> { 104 | mHandler.postDelayed(() -> { 105 | 106 | if (mData.size() > 2 * PAGE_SIZE) { 107 | // 错误 108 | mAdapter.setLoadError(); 109 | } else { 110 | int size = mData.size(); 111 | 112 | addData(); 113 | // 加载成功 114 | mAdapter.setLoadComplete(); 115 | // 刷新 116 | mAdapter.notifyItemRangeInserted(mAdapter.getRealPosition(size), PAGE_SIZE); 117 | } 118 | 119 | }, 2000); 120 | }); 121 | 122 | recycleView = findViewById(R.id.recycle_view); 123 | recycleView.setLayoutManager(new LinearLayoutManager(this)); 124 | recycleView.setAdapter(mAdapter); 125 | 126 | } 127 | 128 | private void initType() { 129 | 130 | mValidType.add(new MixData(Constant.DATA_TYPE.NORMAL, "普通类型")); 131 | 132 | if (stick) { 133 | mValidType.add(new MixData(Constant.DATA_TYPE.STICK, "粘性类型")); 134 | } 135 | 136 | if (swipe) { 137 | mValidType.add(new MixData(Constant.DATA_TYPE.SWIPE, "侧滑类型")); 138 | } 139 | 140 | } 141 | 142 | private void initIntent(Intent intent) { 143 | 144 | refresh = intent.getBooleanExtra(REFRESH, false); 145 | loadMore = intent.getBooleanExtra(LOAD_MORE, false); 146 | swipe = intent.getBooleanExtra(SWIPE, false); 147 | anim = intent.getBooleanExtra(ANIM, false); 148 | stick = intent.getBooleanExtra(STICK, false); 149 | 150 | } 151 | 152 | private List mData = new ArrayList<>(); 153 | 154 | private void initData() { 155 | mData.clear(); 156 | 157 | int typeSize = mValidType.size(); 158 | 159 | for (int i = 0; i < PAGE_SIZE; ++i) { 160 | 161 | int type = mRandom.nextInt(typeSize); 162 | 163 | if (type == typeSize) { 164 | type = 0; 165 | } 166 | 167 | MixData validData = mValidType.get(type); 168 | 169 | MixData mixData = new MixData(validData.getType(), validData.getName()); 170 | mData.add(mixData); 171 | } 172 | } 173 | 174 | private void addData() { 175 | int typeSize = mValidType.size(); 176 | 177 | for (int i = 0; i < PAGE_SIZE; ++i) { 178 | 179 | int type = mRandom.nextInt(typeSize); 180 | 181 | if (type == typeSize) { 182 | type = 0; 183 | } 184 | 185 | MixData validData = mValidType.get(type); 186 | 187 | MixData mixData = new MixData(validData.getType(), validData.getName()); 188 | mData.add(mixData); 189 | } 190 | } 191 | 192 | } 193 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/mix/MixAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.mix; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.FrameLayout; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.recyclerview.widget.RecyclerView; 13 | 14 | import com.zinc.jrecycleview.R; 15 | import com.zinc.jrecycleview.config.JRecycleConfig; 16 | import com.zinc.jrecycleview.stick.IStick; 17 | import com.zinc.jrecycleview.swipe.JSwipeViewHolder; 18 | 19 | import java.lang.ref.WeakReference; 20 | import java.util.List; 21 | 22 | /** 23 | * author : Jiang Pengyong 24 | * time : 2018-03-17 22:15 25 | * email : 56002982@qq.com 26 | * desc : 混合适配器 27 | * version : 1.0.0 28 | */ 29 | 30 | public class MixAdapter extends RecyclerView.Adapter { 31 | 32 | private final List mData; 33 | 34 | private final LayoutInflater mLayoutInflater; 35 | 36 | private final WeakReference mContext; 37 | 38 | MixAdapter(Context context, List data) { 39 | mData = data; 40 | mLayoutInflater = LayoutInflater.from(context); 41 | mContext = new WeakReference<>(context); 42 | } 43 | 44 | @NonNull 45 | @Override 46 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, 47 | int viewType) { 48 | if (viewType == Constant.DATA_TYPE.NORMAL) { 49 | return new NormalHolder(mLayoutInflater 50 | .inflate(R.layout.refresh_and_load_view_item, parent, false)); 51 | } else if (viewType == Constant.DATA_TYPE.SWIPE) { 52 | return new SwipeHolder(mLayoutInflater 53 | .inflate(JRecycleConfig.SWIPE_LAYOUT, parent, false)); 54 | } else if (viewType == Constant.DATA_TYPE.STICK) { 55 | return new StickHolder(mLayoutInflater 56 | .inflate(R.layout.stick_item, parent, false)); 57 | } 58 | return null; 59 | } 60 | 61 | @Override 62 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, 63 | int position) { 64 | MixData mixData = mData.get(position); 65 | final int pos = position; 66 | 67 | if (holder instanceof NormalHolder) { 68 | NormalHolder normalHolder = (NormalHolder) holder; 69 | normalHolder.tvContent.setText(mixData.getName()); 70 | normalHolder.tvContent.setOnClickListener(v -> { 71 | Toast.makeText(mContext.get(), mixData.getName() + pos, Toast.LENGTH_SHORT).show(); 72 | }); 73 | } else if (holder instanceof StickHolder) { 74 | StickHolder stickHolder = (StickHolder) holder; 75 | stickHolder.tvStick.setText(mixData.getName()); 76 | stickHolder.itemView.setOnClickListener(v -> { 77 | Toast.makeText(mContext.get(), mixData.getName() + pos, Toast.LENGTH_SHORT).show(); 78 | }); 79 | } else if (holder instanceof SwipeHolder) { 80 | SwipeHolder swipeHolder = (SwipeHolder) holder; 81 | swipeHolder.tvContent.setText(mixData.getName()); 82 | swipeHolder.tvRightMenu.setOnClickListener(v -> { 83 | Toast.makeText(mContext.get(), "右" + pos, Toast.LENGTH_SHORT).show(); 84 | swipeHolder.getSwipeItemLayout().close(); 85 | }); 86 | 87 | swipeHolder.tvContent.setOnClickListener(v -> { 88 | Toast.makeText(mContext.get(), mixData.getName() + pos, Toast.LENGTH_SHORT).show(); 89 | }); 90 | } 91 | } 92 | 93 | @Override 94 | public int getItemCount() { 95 | return mData.size(); 96 | } 97 | 98 | @Override 99 | public int getItemViewType(int position) { 100 | return mData.get(position).getType(); 101 | } 102 | 103 | static class NormalHolder extends RecyclerView.ViewHolder { 104 | 105 | private TextView tvContent; 106 | 107 | NormalHolder(View itemView) { 108 | super(itemView); 109 | tvContent = itemView.findViewById(R.id.tv_content); 110 | } 111 | } 112 | 113 | static class StickHolder extends RecyclerView.ViewHolder implements IStick { 114 | 115 | private TextView tvStick; 116 | 117 | StickHolder(View itemView) { 118 | super(itemView); 119 | 120 | tvStick = itemView.findViewById(R.id.tv_stick); 121 | } 122 | } 123 | 124 | static class SwipeHolder extends JSwipeViewHolder { 125 | 126 | private TextView tvRightMenu; 127 | private TextView tvContent; 128 | 129 | SwipeHolder(View itemView) { 130 | super(itemView); 131 | } 132 | 133 | @Override 134 | public int getContentLayout() { 135 | return R.layout.swipe_content; 136 | } 137 | 138 | @Override 139 | public int getRightMenuLayout() { 140 | return R.layout.swipe_only_right; 141 | } 142 | 143 | @Override 144 | public void initItem(FrameLayout frameLayout) { 145 | 146 | tvRightMenu = frameLayout.findViewById(R.id.tv_right_menu); 147 | tvContent = frameLayout.findViewById(R.id.tv_content); 148 | 149 | } 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/mix/MixData.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.mix; 2 | 3 | /** 4 | * author : Jiang Pengyong 5 | * time : 2019-08-24 23:57 6 | * email : 56002982@qq.com 7 | * desc : 混合适配器 8 | * version : 1.0.0 9 | */ 10 | public class MixData { 11 | 12 | private int type; 13 | private String name; 14 | 15 | MixData(int type, String name) { 16 | this.type = type; 17 | this.name = name; 18 | } 19 | 20 | public int getType() { 21 | return type; 22 | } 23 | 24 | public String getName() { 25 | return name; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/mix/dialog/MixAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.mix.dialog; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ImageView; 8 | import android.widget.TextView; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.recyclerview.widget.RecyclerView; 12 | 13 | import com.zinc.jrecycleview.R; 14 | 15 | import java.lang.ref.WeakReference; 16 | import java.util.List; 17 | 18 | /** 19 | * author : Jiang Pengyong 20 | * time : 2019-08-24 22:03 21 | * email : 56002982@qq.com 22 | * desc : 混合适配器 23 | * version : 1.0.0 24 | */ 25 | public class MixAdapter extends RecyclerView.Adapter { 26 | 27 | private final WeakReference mContext; 28 | private final LayoutInflater mInflater; 29 | private final List mData; 30 | 31 | MixAdapter(Context context, 32 | List data) { 33 | this.mContext = new WeakReference<>(context); 34 | this.mInflater = LayoutInflater.from(context); 35 | this.mData = data; 36 | } 37 | 38 | @NonNull 39 | @Override 40 | public AnimViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 41 | return new AnimViewHolder( 42 | mInflater.inflate(R.layout.item_mix, parent, false)); 43 | } 44 | 45 | @Override 46 | public void onBindViewHolder(@NonNull AnimViewHolder holder, int position) { 47 | MixShowInfoData mixData = mData.get(position); 48 | holder.tvContent.setText(mixData.getName()); 49 | holder.ivCheck.setVisibility(mixData.isSelect() ? View.VISIBLE : View.GONE); 50 | 51 | holder.itemView.setOnClickListener(v -> { 52 | mixData.setSelect(!mixData.isSelect()); 53 | notifyDataSetChanged(); 54 | }); 55 | } 56 | 57 | @Override 58 | public int getItemCount() { 59 | return mData.size(); 60 | } 61 | 62 | static class AnimViewHolder extends RecyclerView.ViewHolder { 63 | private TextView tvContent; 64 | private ImageView ivCheck; 65 | 66 | AnimViewHolder(View itemView) { 67 | super(itemView); 68 | 69 | tvContent = itemView.findViewById(R.id.tv_content); 70 | ivCheck = itemView.findViewById(R.id.iv_check); 71 | 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/mix/dialog/MixDialog.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.mix.dialog; 2 | 3 | import android.os.Bundle; 4 | import android.view.Gravity; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.Window; 9 | import android.widget.TextView; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.annotation.Nullable; 13 | import androidx.appcompat.app.AppCompatDialogFragment; 14 | import androidx.fragment.app.DialogFragment; 15 | import androidx.recyclerview.widget.LinearLayoutManager; 16 | import androidx.recyclerview.widget.RecyclerView; 17 | 18 | import com.zinc.jrecycleview.R; 19 | import com.zinc.jrecycleview.diy.UIUtils; 20 | import com.zinc.jrecycleview.mix.Constant; 21 | import com.zinc.jrecycleview.mix.MixActivity; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | /** 27 | * author : Jiang Pengyong 28 | * time : 2018-11-02 21:27 29 | * email : 56002982@qq.com 30 | * desc : 混合选择列表 31 | * version : 1.0.0 32 | */ 33 | 34 | public class MixDialog extends AppCompatDialogFragment { 35 | 36 | private RecyclerView mRecycleView; 37 | private TextView mTvGo; 38 | private static final List mData = new ArrayList<>(); 39 | 40 | static { 41 | mData.add(new MixShowInfoData(Constant.REFRESH, "下拉刷新(REFRESH)")); 42 | mData.add(new MixShowInfoData(Constant.LOAD_MORE, "上拉加载(LOAD_MORE)")); 43 | mData.add(new MixShowInfoData(Constant.SWIPE, "侧滑(SWIPE)")); 44 | mData.add(new MixShowInfoData(Constant.ANIM, "动画(ANIM)")); 45 | mData.add(new MixShowInfoData(Constant.STICK, "粘性(STICK)")); 46 | } 47 | 48 | public static MixDialog newInstance() { 49 | 50 | Bundle args = new Bundle(); 51 | 52 | MixDialog fragment = new MixDialog(); 53 | fragment.setArguments(args); 54 | return fragment; 55 | } 56 | 57 | @Override 58 | public void onCreate(@Nullable Bundle savedInstanceState) { 59 | super.onCreate(savedInstanceState); 60 | setStyle(DialogFragment.STYLE_NORMAL, R.style.BitFrameDialog); 61 | } 62 | 63 | @Override 64 | public View onCreateView(@NonNull LayoutInflater inflater, 65 | ViewGroup container, 66 | Bundle savedInstanceState) { 67 | return inflater.inflate(R.layout.dialog_mix, container, false); 68 | } 69 | 70 | @Override 71 | public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { 72 | super.onViewCreated(view, savedInstanceState); 73 | 74 | initWindows(getDialog().getWindow()); 75 | 76 | mRecycleView = view.findViewById(R.id.recycle_view); 77 | mTvGo = view.findViewById(R.id.tv_go); 78 | 79 | mRecycleView.setLayoutManager(new LinearLayoutManager(getContext())); 80 | mRecycleView.setAdapter(new MixAdapter(getContext(), mData)); 81 | 82 | mTvGo.setOnClickListener(v -> { 83 | MixActivity.startActivity(getContext(), 84 | mData.get(0).isSelect(), 85 | mData.get(1).isSelect(), 86 | mData.get(2).isSelect(), 87 | mData.get(3).isSelect(), 88 | mData.get(4).isSelect() 89 | ); 90 | }); 91 | 92 | } 93 | 94 | private void initWindows(Window window) { 95 | View decorView = window.getDecorView(); 96 | decorView.setPadding(0, decorView.getPaddingTop(), 0, 0); 97 | window.setLayout(UIUtils.dip2px(getContext(), 300), 98 | UIUtils.dip2px(getContext(), 300)); 99 | window.setGravity(Gravity.CENTER); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/mix/dialog/MixShowInfoData.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.mix.dialog; 2 | 3 | /** 4 | * author : Jiang Pengyong 5 | * time : 2019-08-24 23:33 6 | * email : 56002982@qq.com 7 | * desc : 混合选择列表数据 8 | * version : 1.0.0 9 | */ 10 | public class MixShowInfoData { 11 | 12 | private int type; 13 | private String name; 14 | private boolean isSelect; 15 | 16 | MixShowInfoData(int type, String name) { 17 | this.type = type; 18 | this.name = name; 19 | this.isSelect = false; 20 | } 21 | 22 | public int getType() { 23 | return type; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public boolean isSelect() { 31 | return isSelect; 32 | } 33 | 34 | public void setSelect(boolean select) { 35 | isSelect = select; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/refreshAndLoad/RefreshAndLoadActivity.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.refreshAndLoad; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.widget.Toast; 7 | 8 | import androidx.appcompat.app.AppCompatActivity; 9 | import androidx.recyclerview.widget.LinearLayoutManager; 10 | import androidx.recyclerview.widget.RecyclerView; 11 | 12 | import com.zinc.jrecycleview.JRecycleView; 13 | import com.zinc.jrecycleview.R; 14 | import com.zinc.jrecycleview.adapter.JRefreshAndLoadMoreAdapter; 15 | import com.zinc.jrecycleview.widget.MyRefreshView; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | * author : Jiang Pengyong 22 | * time : 2018-03-17 21:59 23 | * email : 56002982@qq.com 24 | * desc : 下拉刷新、上拉加载 25 | * version : 1.0.0 26 | */ 27 | public class RefreshAndLoadActivity extends AppCompatActivity { 28 | 29 | private static final int PAGE_SIZE = 20; 30 | 31 | public static final String IS_DIY = "isDiy"; 32 | 33 | private JRecycleView mJRecycleView; 34 | 35 | private JRefreshAndLoadMoreAdapter mAdapter; 36 | 37 | private final List mData = new ArrayList<>(); 38 | 39 | private final Handler mHandler = new Handler(Looper.getMainLooper()); 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_refresh_and_load); 45 | 46 | boolean isDiy = getIntent().getBooleanExtra(IS_DIY, false); 47 | 48 | mJRecycleView = findViewById(R.id.j_recycle_view); 49 | 50 | getInitData(); 51 | 52 | // 原始 Adapter 53 | RecyclerView.Adapter adapter = new RefreshAndLoadAdapter(this, mData); 54 | // 使用 JRefreshAndLoadMoreAdapter 进行包装 55 | this.mAdapter = new JRefreshAndLoadMoreAdapter(this, adapter); 56 | 57 | this.mAdapter.setOnLoadMoreListener(() -> { 58 | Toast.makeText(RefreshAndLoadActivity.this, 59 | "触发加载更多", 60 | Toast.LENGTH_SHORT) 61 | .show(); 62 | 63 | mHandler.postDelayed(() -> { 64 | 65 | if (mData.size() > 2 * PAGE_SIZE) { 66 | // 错误 67 | mAdapter.setLoadError(); 68 | } else { 69 | int size = mData.size(); 70 | 71 | addData(); 72 | // 加载成功 73 | mAdapter.setLoadComplete(); 74 | // 刷新 75 | mAdapter.notifyItemRangeInserted(mAdapter.getRealPosition(size), PAGE_SIZE); 76 | } 77 | 78 | }, 2000); 79 | 80 | }); 81 | 82 | this.mAdapter.setOnRefreshListener(() -> { 83 | mHandler.postDelayed(() -> { 84 | 85 | getRefreshData(); 86 | // 将 "上拉加载更多" 重置 87 | mAdapter.resetLoadMore(); 88 | // 将 "下拉刷新" 状态置为刷新完成 89 | mAdapter.setRefreshComplete(); 90 | 91 | }, 2000); 92 | }); 93 | 94 | if (isDiy) { 95 | mAdapter.setRefreshLoadView(new MyRefreshView(getBaseContext())); 96 | } 97 | 98 | mJRecycleView.setLayoutManager(new LinearLayoutManager(this)); 99 | mJRecycleView.setAdapter(mAdapter); 100 | 101 | } 102 | 103 | public void getInitData() { 104 | mData.clear(); 105 | for (int i = 1; i <= PAGE_SIZE; ++i) { 106 | mData.add("zinc Power" + i); 107 | } 108 | } 109 | 110 | public void getRefreshData() { 111 | mData.clear(); 112 | for (int i = 1; i <= 15; ++i) { 113 | mData.add("zinc Power" + i); 114 | } 115 | } 116 | 117 | public void addData() { 118 | int size = mData.size(); 119 | for (int i = 1; i <= PAGE_SIZE; ++i) { 120 | mData.add("zinc Power" + (size + i)); 121 | } 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/refreshAndLoad/RefreshAndLoadAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.refreshAndLoad; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.recyclerview.widget.RecyclerView; 13 | 14 | import com.zinc.jrecycleview.R; 15 | 16 | import java.lang.ref.WeakReference; 17 | import java.util.List; 18 | 19 | /** 20 | * author : Jiang Pengyong 21 | * time : 2018-03-17 22:15 22 | * email : 56002982@qq.com 23 | * desc : 下拉刷新、上拉加载的适配器 24 | * version : 1.0.0 25 | */ 26 | 27 | public class RefreshAndLoadAdapter extends RecyclerView.Adapter { 28 | 29 | private final List mData; 30 | 31 | private final LayoutInflater mLayoutInflater; 32 | 33 | private final WeakReference mContext; 34 | 35 | RefreshAndLoadAdapter(Context context, List data) { 36 | mData = data; 37 | mLayoutInflater = LayoutInflater.from(context); 38 | mContext = new WeakReference<>(context); 39 | } 40 | 41 | @NonNull 42 | @Override 43 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, 44 | int viewType) { 45 | return new TestHolder(mLayoutInflater 46 | .inflate(R.layout.refresh_and_load_view_item, parent, false)); 47 | } 48 | 49 | @Override 50 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, 51 | int position) { 52 | final String content = mData.get(position); 53 | TestHolder testHolder = (TestHolder) holder; 54 | testHolder.mTvContent.setText(content); 55 | testHolder.itemView.setOnClickListener(new View.OnClickListener() { 56 | @Override 57 | public void onClick(View v) { 58 | Log.i("zincPower", "onClick: " + content); 59 | Toast.makeText(mContext.get(), content, Toast.LENGTH_LONG).show(); 60 | } 61 | }); 62 | } 63 | 64 | @Override 65 | public int getItemCount() { 66 | return mData.size(); 67 | } 68 | 69 | class TestHolder extends RecyclerView.ViewHolder { 70 | 71 | private TextView mTvContent; 72 | 73 | TestHolder(View itemView) { 74 | super(itemView); 75 | mTvContent = itemView.findViewById(R.id.tv_content); 76 | } 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/stick/content/StickContentActivity.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.stick.content; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import androidx.recyclerview.widget.LinearLayoutManager; 7 | import androidx.recyclerview.widget.RecyclerView; 8 | 9 | import com.zinc.jrecycleview.JRecycleView; 10 | import com.zinc.jrecycleview.R; 11 | import com.zinc.jrecycleview.adapter.JRefreshAndLoadMoreAdapter; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * author : Jiang Pengyong 18 | * time : 2019-07-26 14:09 19 | * desc : 粘性效果视图 20 | * version : 1.0.0 21 | */ 22 | public class StickContentActivity extends AppCompatActivity { 23 | 24 | private JRecycleView mJRecycleView; 25 | 26 | private JRefreshAndLoadMoreAdapter mAdapter; 27 | private final List mData = new ArrayList<>(); 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_refresh_and_load); 33 | 34 | mJRecycleView = findViewById(R.id.j_recycle_view); 35 | 36 | getInitData(); 37 | 38 | RecyclerView.Adapter adapter = new StickContentAdapter(this, mData); 39 | mAdapter = new JRefreshAndLoadMoreAdapter(this, adapter); 40 | 41 | mAdapter.setIsOpenLoadMore(false); 42 | mAdapter.setIsOpenRefresh(false); 43 | 44 | mJRecycleView.setLayoutManager(new LinearLayoutManager(this)); 45 | mJRecycleView.setAdapter(mAdapter); 46 | 47 | } 48 | 49 | public void getInitData() { 50 | mData.clear(); 51 | for (int i = 1; i <= 20; ++i) { 52 | mData.add("zinc Power" + i); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/stick/content/StickContentAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.stick.content; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.recyclerview.widget.RecyclerView; 13 | 14 | import com.zinc.jrecycleview.R; 15 | import com.zinc.jrecycleview.stick.IStick; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * author : Jiang Pengyong 21 | * time : 2018-03-17 23:45 22 | * email : 56002982@qq.com 23 | * desc : 粘性内容适配器 24 | * version : 1.0.0 25 | */ 26 | 27 | public class StickContentAdapter extends RecyclerView.Adapter { 28 | 29 | private final List mData; 30 | private final LayoutInflater mLayoutInflater; 31 | 32 | private Context context; 33 | 34 | StickContentAdapter(Context context, List data) { 35 | this.mData = data; 36 | mLayoutInflater = LayoutInflater.from(context); 37 | this.context = context; 38 | } 39 | 40 | @NonNull 41 | @Override 42 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, 43 | int viewType) { 44 | if (viewType == 1) { 45 | return new StickHolder(mLayoutInflater 46 | .inflate(R.layout.stick_item, parent, false)); 47 | } else { 48 | return new TestHolder(mLayoutInflater 49 | .inflate(R.layout.refresh_and_load_view_item, parent, false)); 50 | } 51 | } 52 | 53 | @Override 54 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, 55 | int position) { 56 | 57 | final String content = mData.get(position); 58 | 59 | if (holder instanceof TestHolder) { 60 | 61 | TestHolder testHolder = (TestHolder) holder; 62 | testHolder.tvContent.setText(content); 63 | testHolder.itemView.setOnClickListener(new View.OnClickListener() { 64 | @Override 65 | public void onClick(View v) { 66 | Log.i("zincPower", "onClick: " + content); 67 | Toast.makeText(context, content, Toast.LENGTH_LONG).show(); 68 | } 69 | }); 70 | 71 | } else if (holder instanceof StickHolder) { 72 | 73 | StickHolder stickHolder = (StickHolder) holder; 74 | stickHolder.tvStick.setText(content); 75 | 76 | } 77 | } 78 | 79 | @Override 80 | public int getItemCount() { 81 | return mData.size(); 82 | } 83 | 84 | @Override 85 | public int getItemViewType(int position) { 86 | if (position % 2 == 0) { 87 | return 1; 88 | } else { 89 | return 2; 90 | } 91 | } 92 | 93 | class TestHolder extends RecyclerView.ViewHolder { 94 | 95 | private TextView tvContent; 96 | 97 | TestHolder(View itemView) { 98 | super(itemView); 99 | tvContent = itemView.findViewById(R.id.tv_content); 100 | } 101 | } 102 | 103 | class StickHolder extends RecyclerView.ViewHolder implements IStick { 104 | 105 | private TextView tvStick; 106 | 107 | StickHolder(View itemView) { 108 | super(itemView); 109 | tvStick = itemView.findViewById(R.id.tv_stick); 110 | } 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/stick/header/StickHeaderActivity.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.stick.header; 2 | 3 | import android.os.Bundle; 4 | import android.util.Log; 5 | import android.widget.TextView; 6 | 7 | import androidx.appcompat.app.AppCompatActivity; 8 | import androidx.recyclerview.widget.LinearLayoutManager; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import com.zinc.jrecycleview.JRecycleView; 12 | import com.zinc.jrecycleview.R; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * author : Jiang Pengyong 19 | * time : 2019-07-26 14:09 20 | * email : 56002982@qq.com 21 | * desc : 粘性头 22 | * version : 1.0.0 23 | */ 24 | public class StickHeaderActivity extends AppCompatActivity { 25 | 26 | private static final float OFFSET = 600; 27 | private static final int PAGE_SIZE = 20; 28 | 29 | private final List mData = new ArrayList<>(); 30 | 31 | private JRecycleView mJRecycleView; 32 | private TextView mTextView; 33 | 34 | private float mRvOffset = 0; 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | setContentView(R.layout.activity_stick); 40 | 41 | mJRecycleView = findViewById(R.id.j_recycle_view); 42 | mTextView = findViewById(R.id.tv_header); 43 | 44 | mTextView.setAlpha(0); 45 | mTextView.setText("Zinc"); 46 | 47 | getInitData(); 48 | 49 | RecyclerView.Adapter adapter = new StickHeaderAdapter(this, mData); 50 | 51 | mJRecycleView.addOnScrollListener(new RecyclerView.OnScrollListener() { 52 | @Override 53 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 54 | 55 | mRvOffset += dy; 56 | float percent = mRvOffset / OFFSET; 57 | 58 | if (percent >= 1) { 59 | percent = 1; 60 | } 61 | 62 | Log.i("test", "onScrolled: [x: " + dx + ";" + 63 | " y:" + dy + ";" + 64 | " mRvOffset:" + mRvOffset + ";" + 65 | " percent:" + percent + "]"); 66 | 67 | mTextView.setAlpha(percent); 68 | } 69 | }); 70 | 71 | mJRecycleView.setLayoutManager(new LinearLayoutManager(this)); 72 | mJRecycleView.setAdapter(adapter); 73 | 74 | } 75 | 76 | public void getInitData() { 77 | this.mData.clear(); 78 | for (int i = 1; i <= PAGE_SIZE; ++i) { 79 | mData.add("zinc Power" + i); 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/stick/header/StickHeaderAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.stick.header; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.recyclerview.widget.RecyclerView; 13 | 14 | import com.zinc.jrecycleview.R; 15 | import com.zinc.jrecycleview.stick.IStick; 16 | 17 | import java.lang.ref.WeakReference; 18 | import java.util.List; 19 | 20 | /** 21 | * author : Jiang Pengyong 22 | * time : 2018-03-17 21:20 23 | * email : 56002982@qq.com 24 | * desc : 粘性头部适配器 25 | * version : 1.0.0 26 | */ 27 | 28 | public class StickHeaderAdapter extends RecyclerView.Adapter { 29 | 30 | private final List mData; 31 | private final LayoutInflater mLayoutInflater; 32 | 33 | private final WeakReference context; 34 | 35 | public StickHeaderAdapter(Context context, List data) { 36 | this.mData = data; 37 | this.mLayoutInflater = LayoutInflater.from(context); 38 | this.context = new WeakReference<>(context); 39 | } 40 | 41 | @NonNull 42 | @Override 43 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 44 | if (viewType == 1) { 45 | return new StickHolder(mLayoutInflater 46 | .inflate(R.layout.stick_item, parent, false)); 47 | } else { 48 | return new TestHolder(mLayoutInflater 49 | .inflate(R.layout.refresh_and_load_view_item, parent, false)); 50 | } 51 | } 52 | 53 | @Override 54 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { 55 | if (holder instanceof TestHolder) { 56 | 57 | final String content = mData.get(position); 58 | TestHolder testHolder = (TestHolder) holder; 59 | testHolder.mTvContent.setText(content); 60 | testHolder.itemView.setOnClickListener(new View.OnClickListener() { 61 | @Override 62 | public void onClick(View v) { 63 | Log.i("zincPower", "onClick: " + content); 64 | Toast.makeText(context.get(), content, Toast.LENGTH_LONG).show(); 65 | } 66 | }); 67 | 68 | } 69 | } 70 | 71 | @Override 72 | public int getItemCount() { 73 | return mData.size(); 74 | } 75 | 76 | @Override 77 | public int getItemViewType(int position) { 78 | if (position == 0) { 79 | return 1; 80 | } else { 81 | return 2; 82 | } 83 | } 84 | 85 | class TestHolder extends RecyclerView.ViewHolder { 86 | 87 | private TextView mTvContent; 88 | 89 | TestHolder(View itemView) { 90 | super(itemView); 91 | mTvContent = itemView.findViewById(R.id.tv_content); 92 | } 93 | } 94 | 95 | class StickHolder extends RecyclerView.ViewHolder implements IStick { 96 | 97 | StickHolder(View itemView) { 98 | super(itemView); 99 | } 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/swipe/SwipeActivity.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.swipe; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | import androidx.annotation.Nullable; 7 | import androidx.recyclerview.widget.LinearLayoutManager; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | import com.zinc.jrecycleview.R; 11 | import com.zinc.jrecycleview.data.SwipeData; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * author : Jiang Pengyong 18 | * time : 2018-04-08 22:27 19 | * email : 56002982@qq.com 20 | * desc : 测滑视图 21 | * version : 1.0.0 22 | */ 23 | 24 | public class SwipeActivity extends Activity { 25 | 26 | private static final int PAGE_SIZE = 20; 27 | 28 | private RecyclerView mJRecycleView; 29 | private final List mData = new ArrayList<>(); 30 | private SwipeAdapter mAdapter; 31 | 32 | @Override 33 | protected void onCreate(@Nullable Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_swipe); 36 | 37 | mJRecycleView = findViewById(R.id.j_recycle_view); 38 | 39 | getInitData(); 40 | 41 | mAdapter = new SwipeAdapter(this, mData); 42 | mJRecycleView.setLayoutManager(new LinearLayoutManager(this)); 43 | mJRecycleView.setAdapter(this.mAdapter); 44 | 45 | } 46 | 47 | public void getInitData() { 48 | mData.clear(); 49 | for (int i = 1; i <= PAGE_SIZE; ++i) { 50 | if (i % 4 == 1) { 51 | mData.add(new SwipeData(SwipeAdapter.SWIPE_TYPE_ONLY_RIGHT, "只有右菜单" + i, i)); 52 | } else if (i % 4 == 2) { 53 | mData.add(new SwipeData(SwipeAdapter.SWIPE_TYPE_ONLY_LEFT, "只有左菜单" + i, i)); 54 | } else { 55 | mData.add(new SwipeData(SwipeAdapter.SWIPE_TYPE, "两个菜单" + i, i)); 56 | } 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/swipe/SwipeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.swipe; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.FrameLayout; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.recyclerview.widget.RecyclerView; 13 | 14 | import com.zinc.jrecycleview.R; 15 | import com.zinc.jrecycleview.config.JRecycleConfig; 16 | import com.zinc.jrecycleview.data.SwipeData; 17 | 18 | import java.lang.ref.WeakReference; 19 | import java.util.List; 20 | 21 | /** 22 | * author : Jiang Pengyong 23 | * time : 2018-04-08 14:39 24 | * email : 56002982@qq.com 25 | * desc : 测滑适配器 26 | * version : 1.0.0 27 | */ 28 | 29 | public class SwipeAdapter extends RecyclerView.Adapter { 30 | 31 | static final int SWIPE_TYPE = 0x10001; 32 | static final int SWIPE_TYPE_ONLY_RIGHT = 0x10002; 33 | static final int SWIPE_TYPE_ONLY_LEFT = 0x10003; 34 | 35 | private final List mSwipeData; 36 | 37 | private final LayoutInflater mLayoutInflater; 38 | 39 | private final WeakReference mContext; 40 | 41 | SwipeAdapter(Context context, List data) { 42 | mSwipeData = data; 43 | mLayoutInflater = LayoutInflater.from(context); 44 | mContext = new WeakReference<>(context); 45 | } 46 | 47 | @NonNull 48 | @Override 49 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, 50 | int viewType) { 51 | switch (viewType) { 52 | case SWIPE_TYPE: 53 | return new MyContentViewHolder(mLayoutInflater 54 | .inflate(JRecycleConfig.SWIPE_LAYOUT, parent, false)); 55 | case SWIPE_TYPE_ONLY_RIGHT: 56 | return new OnlyRightViewHolder(mLayoutInflater 57 | .inflate(JRecycleConfig.SWIPE_LAYOUT, parent, false)); 58 | case SWIPE_TYPE_ONLY_LEFT: 59 | return new OnlyLeftViewHolder(mLayoutInflater 60 | .inflate(JRecycleConfig.SWIPE_LAYOUT, parent, false)); 61 | default: 62 | return null; 63 | } 64 | } 65 | 66 | @Override 67 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { 68 | 69 | final SwipeData swipeData = this.mSwipeData.get(position); 70 | 71 | if (holder instanceof MyContentViewHolder) { 72 | 73 | final MyContentViewHolder myContentViewHolder = (MyContentViewHolder) holder; 74 | myContentViewHolder.tvRightMenu.setText("test Right"); 75 | myContentViewHolder.tvRightMenu.setOnClickListener(v -> { 76 | Toast.makeText(mContext.get(), "Right menu", Toast.LENGTH_SHORT).show(); 77 | //关闭菜单 78 | myContentViewHolder.getSwipeItemLayout().close(); 79 | }); 80 | 81 | myContentViewHolder.tvRightMenuTwo.setText("test Right 2"); 82 | myContentViewHolder.tvRightMenuTwo.setOnClickListener(v -> { 83 | Toast.makeText(mContext.get(), "Right 2 menu", Toast.LENGTH_SHORT).show(); 84 | //关闭菜单 85 | myContentViewHolder.getSwipeItemLayout().close(); 86 | }); 87 | 88 | myContentViewHolder.tvLeftMenu.setText("test Left"); 89 | myContentViewHolder.tvLeftMenu.setOnClickListener(v -> { 90 | Toast.makeText(mContext.get(), "Left menu", Toast.LENGTH_SHORT).show(); 91 | //关闭菜单 92 | myContentViewHolder.getSwipeItemLayout().close(); 93 | }); 94 | 95 | myContentViewHolder.tvLeftMenuTwo.setText("test Left 2"); 96 | myContentViewHolder.tvLeftMenuTwo.setOnClickListener(v -> { 97 | Toast.makeText(mContext.get(), "Left 2 menu", Toast.LENGTH_SHORT).show(); 98 | //关闭菜单 99 | myContentViewHolder.getSwipeItemLayout().close(); 100 | }); 101 | 102 | myContentViewHolder 103 | .tvContent 104 | .setText(this.mSwipeData.get(position).getContent()); 105 | myContentViewHolder.tvContent.setOnClickListener(v -> 106 | Toast.makeText(mContext.get(), swipeData.getContent(), Toast.LENGTH_SHORT).show()); 107 | 108 | } else if (holder instanceof OnlyLeftViewHolder) { 109 | 110 | final OnlyLeftViewHolder onlyLeftViewHolder = (OnlyLeftViewHolder) holder; 111 | 112 | onlyLeftViewHolder.tvContent.setText(this.mSwipeData.get(position).getContent()); 113 | 114 | onlyLeftViewHolder.tvLeftMenu.setOnClickListener(v -> { 115 | Toast.makeText(mContext.get(), "点击了左菜单", Toast.LENGTH_SHORT).show(); 116 | //关闭菜单 117 | onlyLeftViewHolder.getSwipeItemLayout().close(); 118 | }); 119 | 120 | onlyLeftViewHolder.tvContent.setOnClickListener(v -> 121 | Toast.makeText(mContext.get(), swipeData.getContent(), Toast.LENGTH_SHORT).show()); 122 | 123 | } else if (holder instanceof OnlyRightViewHolder) { 124 | 125 | final OnlyRightViewHolder onlyRightViewHolder = (OnlyRightViewHolder) holder; 126 | 127 | final int fPos = position; 128 | 129 | // 关闭侧滑 130 | // onlyRightViewHolder.getSwipeItemLayout().setSwipeEnable(false); 131 | 132 | onlyRightViewHolder.tvContent.setText(this.mSwipeData.get(position).getContent()); 133 | 134 | onlyRightViewHolder.tvRightMenu.setOnClickListener(v -> { 135 | Toast.makeText(mContext.get(), "点击了右菜单,删除", Toast.LENGTH_SHORT).show(); 136 | //关闭菜单 137 | this.mSwipeData.remove(fPos); 138 | onlyRightViewHolder.getSwipeItemLayout().close(); 139 | notifyItemRemoved(fPos); 140 | }); 141 | 142 | onlyRightViewHolder.tvContent.setOnClickListener(v -> 143 | Toast.makeText(mContext.get(), swipeData.getContent(), Toast.LENGTH_SHORT).show()); 144 | 145 | } 146 | } 147 | 148 | @Override 149 | public int getItemCount() { 150 | return mSwipeData.size(); 151 | } 152 | 153 | @Override 154 | public int getItemViewType(int position) { 155 | return mSwipeData.get(position).getType(); 156 | } 157 | 158 | class MyContentViewHolder extends JSwipeViewHolder { 159 | 160 | private TextView tvLeftMenu; 161 | private TextView tvRightMenu; 162 | private TextView tvContent; 163 | private TextView tvRightMenuTwo; 164 | private TextView tvLeftMenuTwo; 165 | 166 | MyContentViewHolder(View itemView) { 167 | super(itemView); 168 | } 169 | 170 | @Override 171 | public int getLeftMenuLayout() { 172 | return R.layout.swipe_left_menu; 173 | } 174 | 175 | @Override 176 | public int getRightMenuLayout() { 177 | return R.layout.swipe_right_menu; 178 | } 179 | 180 | @Override 181 | public int getContentLayout() { 182 | return R.layout.swipe_content; 183 | } 184 | 185 | @Override 186 | public void initLeftMenuItem(FrameLayout flLeftMenu) { 187 | tvLeftMenu = flLeftMenu.findViewById(R.id.tv_left_menu); 188 | tvLeftMenuTwo = flLeftMenu.findViewById(R.id.tv_left_menu_two); 189 | } 190 | 191 | @Override 192 | public void initRightMenuItem(FrameLayout flRightMenu) { 193 | tvRightMenu = flRightMenu.findViewById(R.id.tv_right_menu); 194 | tvRightMenuTwo = flRightMenu.findViewById(R.id.tv_right_menu_two); 195 | } 196 | 197 | @Override 198 | public void initContentItem(FrameLayout flContent) { 199 | tvContent = flContent.findViewById(R.id.tv_content); 200 | } 201 | 202 | @Override 203 | public void initItem(FrameLayout frameLayout) { 204 | 205 | } 206 | } 207 | 208 | class OnlyLeftViewHolder extends JSwipeViewHolder { 209 | 210 | private TextView tvLeftMenu; 211 | private TextView tvContent; 212 | 213 | OnlyLeftViewHolder(View itemView) { 214 | super(itemView); 215 | } 216 | 217 | @Override 218 | public int getLeftMenuLayout() { 219 | return R.layout.swipe_only_left; 220 | } 221 | 222 | @Override 223 | public int getContentLayout() { 224 | return R.layout.swipe_content; 225 | } 226 | 227 | @Override 228 | public void initItem(FrameLayout frameLayout) { 229 | tvLeftMenu = frameLayout.findViewById(R.id.tv_left_menu); 230 | tvContent = frameLayout.findViewById(R.id.tv_content); 231 | } 232 | } 233 | 234 | class OnlyRightViewHolder extends JSwipeViewHolder { 235 | 236 | private TextView tvRightMenu; 237 | private TextView tvContent; 238 | 239 | OnlyRightViewHolder(View itemView) { 240 | super(itemView); 241 | } 242 | 243 | @Override 244 | public int getRightMenuLayout() { 245 | return R.layout.swipe_only_right; 246 | } 247 | 248 | @Override 249 | public int getContentLayout() { 250 | return R.layout.swipe_content; 251 | } 252 | 253 | @Override 254 | public void initItem(FrameLayout frameLayout) { 255 | tvRightMenu = frameLayout.findViewById(R.id.tv_right_menu); 256 | tvContent = frameLayout.findViewById(R.id.tv_content); 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /app/src/main/java/com/zinc/jrecycleview/widget/MyRefreshView.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.AnimationDrawable; 5 | import android.util.AttributeSet; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.RelativeLayout; 10 | 11 | import androidx.annotation.Nullable; 12 | 13 | import com.zinc.jrecycleview.R; 14 | import com.zinc.jrecycleview.loadview.base.IBaseRefreshLoadView; 15 | import com.zinc.jrecycleview.loadview.bean.MoveInfo; 16 | 17 | /** 18 | * author : Jiang Pengyong 19 | * time : 2018-04-17 16:55 20 | * email : 56002982@qq.com 21 | * desc : 仿美团下拉 22 | * version : 1.0.0 23 | */ 24 | 25 | public class MyRefreshView extends IBaseRefreshLoadView { 26 | 27 | private RelativeLayout mLoadView; 28 | private View mIvMeituan; 29 | 30 | public MyRefreshView(Context context) { 31 | super(context); 32 | } 33 | 34 | public MyRefreshView(Context context, @Nullable AttributeSet attrs) { 35 | super(context, attrs); 36 | } 37 | 38 | public MyRefreshView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 39 | super(context, attrs, defStyleAttr); 40 | } 41 | 42 | @Override 43 | protected View initView(Context context) { 44 | this.mLoadView = (RelativeLayout) LayoutInflater.from(context) 45 | .inflate(R.layout.view_my_refresh, 46 | this, 47 | false); 48 | 49 | this.mIvMeituan = this.mLoadView.findViewById(R.id.iv_meituan); 50 | this.mIvMeituan.setBackgroundResource(R.drawable.meituan_pull_image); 51 | 52 | return mLoadView; 53 | } 54 | 55 | @Override 56 | protected View getLoadView() { 57 | return mLoadView; 58 | } 59 | 60 | @Override 61 | protected void onPullToAction() { 62 | 63 | } 64 | 65 | @Override 66 | protected void onReleaseToAction() { 67 | 68 | } 69 | 70 | @Override 71 | protected void onExecuting() { 72 | this.mIvMeituan.clearAnimation(); 73 | this.mIvMeituan.setBackgroundResource(R.drawable.meituan_refreshing_anim); 74 | AnimationDrawable anim = (AnimationDrawable) this.mIvMeituan.getBackground(); 75 | anim.start(); 76 | } 77 | 78 | @Override 79 | protected void onDone() { 80 | this.mIvMeituan.clearAnimation(); 81 | this.mIvMeituan.setBackgroundResource(R.drawable.meituan_pull_image); 82 | } 83 | 84 | @Override 85 | protected void onMoving(MoveInfo moveInfo) { 86 | this.mIvMeituan.clearAnimation(); 87 | 88 | if (moveInfo.getPercent() < 100) { 89 | ViewGroup.LayoutParams layoutParams = this.mIvMeituan.getLayoutParams(); 90 | int height = moveInfo.getViewHeight() * moveInfo.getPercent() / 100; 91 | layoutParams.height = height; 92 | layoutParams.width = height; 93 | 94 | this.mIvMeituan.setBackgroundResource(R.drawable.meituan_pull_image); 95 | } else { 96 | this.mIvMeituan.clearAnimation(); 97 | this.mIvMeituan.setBackgroundResource(R.drawable.meituan_pull_to_refresh_anim); 98 | AnimationDrawable anim = (AnimationDrawable) this.mIvMeituan.getBackground(); 99 | anim.start(); 100 | } 101 | 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/meituan_pull_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/meituan_pull_image.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/meituan_pull_to_refresh_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/meituan_refreshing_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/pull_end_image_frame_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/pull_end_image_frame_01.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/pull_end_image_frame_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/pull_end_image_frame_02.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/pull_end_image_frame_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/pull_end_image_frame_03.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/pull_end_image_frame_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/pull_end_image_frame_04.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/pull_end_image_frame_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/pull_end_image_frame_05.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/refreshing_image_frame_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/refreshing_image_frame_01.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/refreshing_image_frame_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/refreshing_image_frame_02.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/refreshing_image_frame_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/refreshing_image_frame_03.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/refreshing_image_frame_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/refreshing_image_frame_04.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/refreshing_image_frame_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/refreshing_image_frame_05.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/refreshing_image_frame_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/refreshing_image_frame_06.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/refreshing_image_frame_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/refreshing_image_frame_07.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/refreshing_image_frame_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/app/src/main/res/drawable-xhdpi/refreshing_image_frame_08.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_background_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_blue_round_5dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_dialog_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 15 | 16 | 20 | 21 | 25 | 26 | 30 | 31 | 35 | 36 | 40 | 41 | 45 | 46 | 50 | 51 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_mix.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_refresh_and_load.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_stick.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_swipe.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_yctc_article_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 21 | 22 | 23 | 30 | 31 | 38 | 39 | 40 | 47 | 48 | 53 | 54 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_mix.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_article_banner.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_article_content.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_article_sort.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_mix.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 21 | 22 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/refresh_and_load_view_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/stick_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/swipe_content.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/swipe_left_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/swipe_only_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/swipe_only_right.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/swipe_right_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_my_refresh.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/menu/layout_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #35a8ee 5 | #1296db 6 | #FF4081 7 | 8 | #f54e5b 9 | #2ab00a 10 | #f89b4b 11 | 12 | #fe9191 13 | #e4406f 14 | #ca2374 15 | #9c297f 16 | 17 | #88333333 18 | 19 | #ffe6eb 20 | #defcfc 21 | #cbf1f5 22 | #a6e3e9 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | 80dp 7 | 120dp 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | JRecycleview 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 25 | 26 | 35 | 36 | 44 | 45 | 52 | 53 | 60 | 61 | 68 | 69 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /app/src/test/java/com/zinc/jrecycleview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | // app 版本信息 6 | versionName = '1.1.0' 7 | versionCode = 1100 8 | minSdkVersion = 19 9 | targetSdkVersion = 29 10 | compileSdkVersion = 29 11 | 12 | androidx = "1.1.0" 13 | 14 | junitVersion = '4.12' 15 | } 16 | 17 | repositories { 18 | google() 19 | jcenter() 20 | } 21 | dependencies { 22 | classpath 'com.android.tools.build:gradle:3.5.2' 23 | 24 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'//ADD 25 | // NOTE: Do not place your application dependencies here; they belong 26 | // in the individual module build.gradle files 27 | } 28 | } 29 | 30 | allprojects { 31 | repositories { 32 | google() 33 | jcenter() 34 | } 35 | } 36 | 37 | task clean(type: Delete) { 38 | delete rootProject.buildDir 39 | } 40 | 41 | -------------------------------------------------------------------------------- /cer/JRecycleView.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/cer/JRecycleView.jks -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | RELEASE_KEY_PASSWORD=2018JRecycleView 20 | RELEASE_KEY_ALIAS=JRecycleView 21 | RELEASE_STORE_PASSWORD=2018JRecycleView 22 | 23 | android.useAndroidX=true 24 | android.enableJetifier=true 25 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Dec 04 14:21:07 CST 2019 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-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /img/anim_item.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/img/anim_item.gif -------------------------------------------------------------------------------- /img/diy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/img/diy.gif -------------------------------------------------------------------------------- /img/diy_pull_and_load.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/img/diy_pull_and_load.gif -------------------------------------------------------------------------------- /img/multi_use.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/img/multi_use.gif -------------------------------------------------------------------------------- /img/pull_and_load.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/img/pull_and_load.gif -------------------------------------------------------------------------------- /img/stick_content.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/img/stick_content.gif -------------------------------------------------------------------------------- /img/stick_head.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/img/stick_head.gif -------------------------------------------------------------------------------- /img/swipe.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/img/swipe.gif -------------------------------------------------------------------------------- /img/zincPay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/img/zincPay.jpg -------------------------------------------------------------------------------- /lib.recycleview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /lib.recycleview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven'//ADD 3 | 4 | group = 'com.github.zincPower' 5 | 6 | android { 7 | compileSdkVersion rootProject.ext.compileSdkVersion 8 | 9 | defaultConfig { 10 | minSdkVersion rootProject.ext.minSdkVersion 11 | targetSdkVersion rootProject.ext.targetSdkVersion 12 | versionCode rootProject.ext.versionCode 13 | versionName rootProject.ext.versionName 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | 26 | } 27 | 28 | dependencies { 29 | implementation fileTree(dir: 'libs', include: ['*.jar']) 30 | 31 | implementation "androidx.appcompat:appcompat:$androidx" 32 | implementation "androidx.recyclerview:recyclerview:$androidx" 33 | } 34 | -------------------------------------------------------------------------------- /lib.recycleview/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the mAnimSet 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 | -------------------------------------------------------------------------------- /lib.recycleview/src/androidTest/java/com/zinc/librecycleview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zinc.librecycleview; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zinc.librecycleview.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/adapter/JBaseRecycleAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.adapter; 2 | 3 | import android.animation.AnimatorSet; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.recyclerview.widget.RecyclerView; 7 | 8 | import com.zinc.jrecycleview.anim.IBaseAnimation; 9 | import com.zinc.jrecycleview.config.JRecycleConfig; 10 | import com.zinc.jrecycleview.config.JRecycleViewManager; 11 | 12 | /** 13 | * author : Jiang Pengyong 14 | * time : 2018-04-12 10:28 15 | * email : 56002982@qq.com 16 | * desc : JBaseRecycleAdapter 17 | * version : 1.0.0 18 | */ 19 | public abstract class JBaseRecycleAdapter 20 | extends RecyclerView.Adapter { 21 | 22 | //是否开启动画 23 | private boolean mOpenAnim = false; 24 | //是否第一次使用动画 25 | private boolean mOnlyFirstAnimEnable = true; 26 | 27 | //最后显示的item位置 28 | private int mLastPosition = -1; 29 | 30 | //动画集合 31 | private IBaseAnimation[] mAnimations = JRecycleViewManager.getInstance().getItemAnimations(); 32 | 33 | @Override 34 | public void onViewAttachedToWindow(@NonNull T holder) { 35 | super.onViewAttachedToWindow(holder); 36 | 37 | addAnimForItem(holder); 38 | } 39 | 40 | public void setOpenAnim(boolean openAnim) { 41 | this.mOpenAnim = openAnim; 42 | } 43 | 44 | public void setOnlyFirstAnimEnable(boolean onlyFirstAnimEnable) { 45 | this.mOnlyFirstAnimEnable = onlyFirstAnimEnable; 46 | } 47 | 48 | public void setAnimations(IBaseAnimation[] animations) { 49 | this.mAnimations = animations; 50 | this.mOpenAnim = true; 51 | } 52 | 53 | /** 54 | * 给每个item添加动画 55 | */ 56 | protected void addAnimForItem(T holder) { 57 | 58 | //是否开启动画 59 | if (!this.mOpenAnim) { 60 | return; 61 | } 62 | 63 | //是否有动画 64 | if (this.mAnimations == null || this.mAnimations.length <= 0) { 65 | return; 66 | } 67 | 68 | int itemType = holder.getItemViewType(); 69 | if (itemType == JRecycleConfig.FOOT || itemType == JRecycleConfig.HEAD) { 70 | return; 71 | } 72 | 73 | //是否只有第一次起作用 或是 第一次进入页面 74 | if (!this.mOnlyFirstAnimEnable || holder.getLayoutPosition() > mLastPosition) { 75 | 76 | this.mLastPosition = holder.getLayoutPosition(); 77 | int animLength = this.mAnimations.length; 78 | int curAnimPosition = holder.getLayoutPosition() % animLength; 79 | AnimatorSet animators = this.mAnimations[curAnimPosition].getAnimators(holder.itemView); 80 | animators.start(); 81 | 82 | } 83 | 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/anim/AlphaAnimation.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.view.View; 5 | 6 | /** 7 | * author : Jiang Pengyong 8 | * time : 2018-04-12 12:15 9 | * email : 56002982@qq.com 10 | * desc : 透明度动画 11 | * version : 1.0.0 12 | */ 13 | 14 | public class AlphaAnimation extends IBaseAnimation { 15 | 16 | @Override 17 | protected void init(View view) { 18 | addAnimTogether(ObjectAnimator.ofFloat(view, "alpha", 0f, 1f)); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/anim/AnimFactory.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | /** 4 | * author : Jiang Pengyong 5 | * time : 2018-04-12 12:24 6 | * email : 56002982@qq.com 7 | * desc : 动画工厂 8 | * version : 1.0.0 9 | */ 10 | 11 | public class AnimFactory { 12 | 13 | public static final int SLIDE_TOP = 1; 14 | public static final int SLIDE_RIGHT = 2; 15 | public static final int SLIDE_BOTTOM = 3; 16 | public static final int SLIDE_LEFT = 4; 17 | public static final int SCALE = 5; 18 | public static final int ALPHA = 6; 19 | 20 | public static IBaseAnimation[] getAnimSet(int type) { 21 | IBaseAnimation[] set = null; 22 | 23 | switch (type) { 24 | case SLIDE_TOP: 25 | set = new IBaseAnimation[]{new SlideInTopAnimation()}; 26 | break; 27 | case SLIDE_RIGHT: 28 | set = new IBaseAnimation[]{new SlideInRightAnimation()}; 29 | break; 30 | case SLIDE_BOTTOM: 31 | set = new IBaseAnimation[]{new SlideInBottomAnimation()}; 32 | break; 33 | case SLIDE_LEFT: 34 | set = new IBaseAnimation[]{new SlideInLeftAnimation()}; 35 | break; 36 | case SCALE: 37 | set = new IBaseAnimation[]{new ScaleAnimation()}; 38 | break; 39 | case ALPHA: 40 | set = new IBaseAnimation[]{new AlphaAnimation()}; 41 | break; 42 | } 43 | 44 | return set; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/anim/IBaseAnimation.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorSet; 5 | import android.view.View; 6 | import android.view.animation.LinearInterpolator; 7 | 8 | import com.zinc.jrecycleview.config.JRecycleConfig; 9 | 10 | /** 11 | * author : Jiang Pengyong 12 | * time : 2018-04-12 12:17 13 | * email : 56002982@qq.com 14 | * desc : 动画接口 15 | * version : 1.0.0 16 | */ 17 | 18 | public abstract class IBaseAnimation { 19 | 20 | protected AnimatorSet mAnimSet; 21 | 22 | /** 23 | * 需要加载动画的视图,一般为ViewHolder中的itemView 24 | * {@link androidx.recyclerview.widget.RecyclerView.ViewHolder#itemView} 25 | */ 26 | public AnimatorSet getAnimators(View view) { 27 | 28 | mAnimSet = new AnimatorSet(); 29 | 30 | initAnimatorSet(); 31 | init(view); 32 | 33 | return mAnimSet; 34 | } 35 | 36 | /** 37 | * 初始化动画集合 38 | */ 39 | private void initAnimatorSet() { 40 | mAnimSet.setDuration(JRecycleConfig.ANIM_DURATION); 41 | mAnimSet.setInterpolator(new LinearInterpolator()); 42 | } 43 | 44 | /** 45 | * 增加同步动画 46 | */ 47 | protected void addAnimTogether(Animator animator) { 48 | mAnimSet.playTogether(animator); 49 | } 50 | 51 | /** 52 | * 初始化方法 53 | */ 54 | protected abstract void init(View view); 55 | 56 | } 57 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/anim/ScaleAnimation.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.view.View; 5 | 6 | /** 7 | * author : Jiang Pengyong 8 | * time : 2018-04-12 12:25 9 | * email : 56002982@qq.com 10 | * desc : 缩放动画 11 | * version : 1.0.0 12 | */ 13 | 14 | public class ScaleAnimation extends IBaseAnimation { 15 | 16 | @Override 17 | protected void init(View view) { 18 | addAnimTogether(ObjectAnimator.ofFloat(view, "scaleX", 0.5f, 1f)); 19 | addAnimTogether(ObjectAnimator.ofFloat(view, "scaleY", 0.5f, 1f)); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/anim/SlideInBottomAnimation.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.view.View; 5 | 6 | /** 7 | * author : Jiang Pengyong 8 | * time : 2018-04-12 12:26 9 | * email : 56002982@qq.com 10 | * desc : 从下往上动画 11 | * version : 1.0.0 12 | */ 13 | 14 | public class SlideInBottomAnimation extends IBaseAnimation { 15 | @Override 16 | protected void init(View view) { 17 | addAnimTogether(ObjectAnimator.ofFloat(view, "translationY", 18 | view.getRootView().getHeight() >> 2, 0)); 19 | addAnimTogether(ObjectAnimator.ofFloat(view, "alpha", 0.5f, 1f)); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/anim/SlideInLeftAnimation.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.view.View; 5 | 6 | /** 7 | * author : Jiang Pengyong 8 | * time : 2018-04-12 12:28 9 | * email : 56002982@qq.com 10 | * desc : 从左进入 11 | * version : 1.0.0 12 | */ 13 | 14 | public class SlideInLeftAnimation extends IBaseAnimation { 15 | @Override 16 | protected void init(View view) { 17 | addAnimTogether(ObjectAnimator.ofFloat(view, "translationX", 18 | -view.getRootView().getWidth(), 0)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/anim/SlideInRightAnimation.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.view.View; 5 | 6 | /** 7 | * author : Jiang Pengyong 8 | * time : 2018-04-12 12:28 9 | * email : 56002982@qq.com 10 | * desc : 从右进 11 | * version : 1.0.0 12 | */ 13 | 14 | public class SlideInRightAnimation extends IBaseAnimation { 15 | @Override 16 | protected void init(View view) { 17 | addAnimTogether(ObjectAnimator.ofFloat(view, "translationX", 18 | view.getRootView().getWidth(), 0)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/anim/SlideInTopAnimation.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.anim; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.view.View; 5 | 6 | /** 7 | * author : Jiang Pengyong 8 | * time : 2019-04-12 12:29 9 | * email : 56002982@qq.com 10 | * desc : 11 | * version : 1.0.0 12 | */ 13 | 14 | public class SlideInTopAnimation extends IBaseAnimation { 15 | @Override 16 | protected void init(View view) { 17 | addAnimTogether(ObjectAnimator.ofFloat(view, "translationY", 18 | -view.getRootView().getHeight() >> 2, 0)); 19 | addAnimTogether(ObjectAnimator.ofFloat(view, "alpha", 0.5f, 1f)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/config/JRecycleConfig.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.config; 2 | 3 | import com.zinc.librecycleview.R; 4 | 5 | /** 6 | * author : Jiang Pengyong 7 | * time : 2018-04-12 12:30 8 | * email : 56002982@qq.com 9 | * desc : JRecycle的一些配置 10 | * version : 1.0.0 11 | */ 12 | 13 | public class JRecycleConfig { 14 | 15 | //侧滑的layout 16 | public static int SWIPE_LAYOUT = R.layout.j_swipe_wrapper; 17 | 18 | // 刷新头部 19 | public static final int HEAD = 0xABC101; 20 | // 加载更多 21 | public static final int FOOT = 0xABC103; 22 | // 动画的时长 23 | public static final int ANIM_DURATION = 500; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/config/JRecycleViewManager.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.config; 2 | 3 | import com.zinc.jrecycleview.anim.IBaseAnimation; 4 | import com.zinc.jrecycleview.anim.SlideInBottomAnimation; 5 | import com.zinc.jrecycleview.loadview.base.IBaseLoadMoreView; 6 | import com.zinc.jrecycleview.loadview.base.IBaseRefreshLoadView; 7 | 8 | /** 9 | * author : Jiang Pengyong 10 | * time : 2019-04-17 12:31 11 | * email : 56002982@qq.com 12 | * desc : JRecycleView 的配置管理 13 | * version : 1.0.0 14 | */ 15 | 16 | public class JRecycleViewManager { 17 | 18 | private static final JRecycleViewManager INSTANCE = new JRecycleViewManager(); 19 | 20 | // 下拉刷新视图 21 | private IBaseRefreshLoadView mRefreshLoadView; 22 | // 上拉更多视图 23 | private IBaseLoadMoreView mLoadMoreView; 24 | 25 | // 动画 26 | private IBaseAnimation[] mItemAnimations; 27 | 28 | // 是否处于 debug 29 | private boolean mIsDebug; 30 | 31 | public static JRecycleViewManager getInstance() { 32 | return INSTANCE; 33 | } 34 | 35 | private JRecycleViewManager() { 36 | mItemAnimations = new IBaseAnimation[]{new SlideInBottomAnimation()}; 37 | mIsDebug = false; 38 | } 39 | 40 | public IBaseRefreshLoadView getRefreshLoadView() { 41 | return mRefreshLoadView; 42 | } 43 | 44 | public JRecycleViewManager setRefreshLoadView(IBaseRefreshLoadView refreshLoadView) { 45 | this.mRefreshLoadView = refreshLoadView; 46 | return this; 47 | } 48 | 49 | public IBaseLoadMoreView getLoadMoreView() { 50 | return mLoadMoreView; 51 | } 52 | 53 | public JRecycleViewManager setLoadMoreView(IBaseLoadMoreView loadMoreView) { 54 | this.mLoadMoreView = loadMoreView; 55 | return this; 56 | } 57 | 58 | public IBaseAnimation[] getItemAnimations() { 59 | return mItemAnimations; 60 | } 61 | 62 | public JRecycleViewManager setItemAnimations(IBaseAnimation[] itemAnimations) { 63 | this.mItemAnimations = itemAnimations; 64 | return this; 65 | } 66 | 67 | public boolean isDebug() { 68 | return mIsDebug; 69 | } 70 | 71 | public JRecycleViewManager setIsDebug(boolean isDebug) { 72 | this.mIsDebug = isDebug; 73 | return this; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/listener/JRecycleListener.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.listener; 2 | 3 | import android.view.MotionEvent; 4 | 5 | /** 6 | * author : Jiang Pengyong 7 | * time : 2019-08-19 15:34 8 | * desc : JRecycleListener 9 | * version : 1.0.0 10 | */ 11 | public interface JRecycleListener { 12 | 13 | boolean onTouch(MotionEvent event, float deltaY); 14 | 15 | boolean onUp(MotionEvent event); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/loadview/OrdinaryLoadMoreView.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.loadview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.ImageView; 8 | import android.widget.TextView; 9 | 10 | import androidx.annotation.Nullable; 11 | 12 | import com.zinc.jrecycleview.loadview.base.IBaseLoadMoreView; 13 | import com.zinc.jrecycleview.widget.BallSpinFadeLoader; 14 | import com.zinc.librecycleview.R; 15 | 16 | /** 17 | * author : Jiang Pengyong 18 | * time : 2018-03-19 16:09 19 | * email : 56002982@qq.com 20 | * desc : 普通的加载更多 21 | *

22 | * 自定义流程 23 | * 1、只需要继承 {@link IBaseLoadMoreView},实现相应的方法。 24 | * 2、全局设置,可以通过 25 | * {@link com.zinc.jrecycleview.config.JRecycleViewManager#setLoadMoreView(IBaseLoadMoreView)} 26 | * 3、单个设置,可以通过 27 | * {@link com.zinc.jrecycleview.adapter.JRefreshAndLoadMoreAdapter#setLoadMoreView(IBaseLoadMoreView)} 28 | *

29 | * version : 1.0.0 30 | */ 31 | 32 | public class OrdinaryLoadMoreView extends IBaseLoadMoreView { 33 | 34 | private View mLoadMoreView; 35 | private BallSpinFadeLoader mProgressBar; 36 | private TextView mTvTip; 37 | private ImageView mIvReload; 38 | 39 | public OrdinaryLoadMoreView(Context context) { 40 | this(context, null, 0); 41 | } 42 | 43 | public OrdinaryLoadMoreView(Context context, 44 | @Nullable AttributeSet attrs) { 45 | this(context, attrs, 0); 46 | } 47 | 48 | public OrdinaryLoadMoreView(Context context, 49 | @Nullable AttributeSet attrs, 50 | int defStyleAttr) { 51 | super(context, attrs, defStyleAttr); 52 | } 53 | 54 | @Override 55 | protected View getLoadView() { 56 | return this.mLoadMoreView; 57 | } 58 | 59 | @Override 60 | protected void onNoMore() { 61 | this.mProgressBar.setVisibility(GONE); 62 | this.mTvTip.setText(getContext().getString(R.string.j_recycle_no_more)); 63 | this.mTvTip.setVisibility(VISIBLE); 64 | this.mIvReload.setVisibility(GONE); 65 | } 66 | 67 | @Override 68 | protected void onError() { 69 | this.mProgressBar.setVisibility(GONE); 70 | this.mTvTip.setText(getContext().getString(R.string.j_recycle_reload)); 71 | this.mTvTip.setVisibility(VISIBLE); 72 | this.mIvReload.setVisibility(VISIBLE); 73 | } 74 | 75 | @Override 76 | protected void onPullToAction() { 77 | this.mProgressBar.setVisibility(GONE); 78 | this.mTvTip.setText(getContext().getString(R.string.j_recycle_pull_to_load)); 79 | this.mTvTip.setVisibility(VISIBLE); 80 | this.mIvReload.setVisibility(GONE); 81 | } 82 | 83 | @Override 84 | protected void onReleaseToAction() { 85 | this.mProgressBar.setVisibility(GONE); 86 | this.mTvTip.setText(getContext().getString(R.string.j_recycle_release_to_load)); 87 | this.mTvTip.setVisibility(VISIBLE); 88 | this.mIvReload.setVisibility(GONE); 89 | } 90 | 91 | @Override 92 | protected void onExecuting() { 93 | this.mProgressBar.setVisibility(VISIBLE); 94 | this.mTvTip.setText(getContext().getString(R.string.j_recycle_loading)); 95 | this.mTvTip.setVisibility(VISIBLE); 96 | this.mIvReload.setVisibility(GONE); 97 | } 98 | 99 | @Override 100 | protected void onDone() { 101 | this.mProgressBar.setVisibility(GONE); 102 | this.mTvTip.setText(getContext().getString(R.string.j_recycle_loaded)); 103 | this.mTvTip.setVisibility(VISIBLE); 104 | this.mIvReload.setVisibility(GONE); 105 | } 106 | 107 | @Override 108 | protected View initView(Context context) { 109 | this.mLoadMoreView = LayoutInflater.from(context) 110 | .inflate(R.layout.j_widget_ordinary_load_more_view, 111 | this, 112 | false); 113 | this.mProgressBar = this.mLoadMoreView.findViewById(R.id.ball_loader); 114 | this.mTvTip = this.mLoadMoreView.findViewById(R.id.tv_tip); 115 | this.mIvReload = this.mLoadMoreView.findViewById(R.id.iv_reload); 116 | 117 | return this.mLoadMoreView; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/loadview/OrdinaryRefreshLoadView.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.loadview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.animation.Animation; 8 | import android.view.animation.RotateAnimation; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import androidx.annotation.Nullable; 13 | 14 | import com.zinc.jrecycleview.loadview.base.IBaseRefreshLoadView; 15 | import com.zinc.jrecycleview.loadview.bean.MoveInfo; 16 | import com.zinc.jrecycleview.utils.LogUtils; 17 | import com.zinc.jrecycleview.widget.BallSpinFadeLoader; 18 | import com.zinc.librecycleview.R; 19 | 20 | /** 21 | * author : Jiang Pengyong 22 | * time : 2018-03-17 14:35 23 | * email : 56002982@qq.com 24 | * desc : 最为普通的下拉刷新头部 25 | *

26 | * 自定义流程 27 | * 1、只需要继承 {@link IBaseRefreshLoadView},实现相应的方法。 28 | * 2、全局设置,可以通过 29 | * {@link com.zinc.jrecycleview.config.JRecycleViewManager#setRefreshLoadView(IBaseRefreshLoadView)} 30 | * 3、单个设置,可以通过 31 | * {@link com.zinc.jrecycleview.adapter.JRefreshAndLoadMoreAdapter#setRefreshLoadView(IBaseRefreshLoadView)} 32 | *

33 | * version : 1.0.0 34 | */ 35 | 36 | public class OrdinaryRefreshLoadView extends IBaseRefreshLoadView { 37 | 38 | private View mLoadView; 39 | 40 | // 动画时长 41 | private static final int ANIM_DURATION = 180; 42 | 43 | //视图控件 44 | private TextView mTvRefreshStatus; 45 | private ImageView mIvArrow; 46 | private BallSpinFadeLoader mBallLoader; 47 | 48 | //向上转动画 49 | private RotateAnimation mArrowToUpAnim; 50 | //向下转动画 51 | private RotateAnimation mArrowToDownAnim; 52 | 53 | public OrdinaryRefreshLoadView(Context context) { 54 | this(context, null, 0); 55 | } 56 | 57 | public OrdinaryRefreshLoadView(Context context, 58 | @Nullable AttributeSet attrs) { 59 | this(context, attrs, 0); 60 | } 61 | 62 | public OrdinaryRefreshLoadView(Context context, 63 | @Nullable AttributeSet attrs, 64 | int defStyleAttr) { 65 | super(context, attrs, defStyleAttr); 66 | } 67 | 68 | @Override 69 | protected void onMoving(MoveInfo moveInfo) { 70 | LogUtils.i(TAG, "onMoving: " + moveInfo.toString()); 71 | } 72 | 73 | @Override 74 | protected View getLoadView() { 75 | return mLoadView; 76 | } 77 | 78 | @Override 79 | protected View initView(Context context) { 80 | mLoadView = LayoutInflater 81 | .from(context) 82 | .inflate(R.layout.j_widget_ordinary_load_refresh_view, this, false); 83 | 84 | mTvRefreshStatus = mLoadView.findViewById(R.id.tv_refresh_status); 85 | mIvArrow = mLoadView.findViewById(R.id.iv_arrow); 86 | mBallLoader = mLoadView.findViewById(R.id.ball_loader); 87 | 88 | //向上转,从0->180 89 | mArrowToUpAnim = new RotateAnimation(0, 180, 90 | Animation.RELATIVE_TO_SELF, 0.5f, 91 | Animation.RELATIVE_TO_SELF, 0.5f); 92 | //动画时长 93 | mArrowToUpAnim.setDuration(ANIM_DURATION); 94 | //让动画停留在最后一帧 95 | mArrowToUpAnim.setFillAfter(true); 96 | 97 | //向下转,从180->0 98 | mArrowToDownAnim = new RotateAnimation(180, 0, 99 | Animation.RELATIVE_TO_SELF, 0.5f, 100 | Animation.RELATIVE_TO_SELF, 0.5f); 101 | mArrowToDownAnim.setDuration(ANIM_DURATION); 102 | mArrowToDownAnim.setFillAfter(true); 103 | 104 | return mLoadView; 105 | } 106 | 107 | @Override 108 | protected void onPullToAction() { 109 | mBallLoader.setVisibility(GONE); 110 | mIvArrow.setVisibility(VISIBLE); 111 | mTvRefreshStatus.setText(getContext().getString(R.string.j_recycle_pull_to_refresh)); 112 | 113 | if (mCurState == STATE_RELEASE_TO_ACTION) {//释放刷新->下拉刷新:把箭头往回转 114 | mIvArrow.startAnimation(mArrowToDownAnim); 115 | } else if (mCurState == STATE_EXECUTING) {//刷新ing->下拉刷新 116 | mIvArrow.clearAnimation(); 117 | } 118 | } 119 | 120 | @Override 121 | protected void onReleaseToAction() { 122 | mBallLoader.setVisibility(GONE); 123 | mIvArrow.setVisibility(VISIBLE); 124 | mTvRefreshStatus.setText(getContext().getString(R.string.j_recycle_release_to_refresh)); 125 | //需要先清空动画 126 | mIvArrow.clearAnimation(); 127 | mIvArrow.startAnimation(mArrowToUpAnim); 128 | } 129 | 130 | @Override 131 | protected void onExecuting() { 132 | mBallLoader.setVisibility(VISIBLE); 133 | 134 | //需要先清空箭头状态,后在进行视图隐藏,否则会有问题 135 | mIvArrow.clearAnimation(); 136 | mIvArrow.setVisibility(GONE); 137 | 138 | mTvRefreshStatus.setText(getContext().getString(R.string.j_recycle_refreshing)); 139 | } 140 | 141 | @Override 142 | protected void onDone() { 143 | mIvArrow.clearAnimation(); 144 | mIvArrow.setVisibility(GONE); 145 | mBallLoader.setVisibility(GONE); 146 | mTvRefreshStatus.setText(getContext().getString(R.string.j_recycle_refreshed)); 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/loadview/base/IBaseLoadMoreView.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.loadview.base; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | 7 | import androidx.annotation.Nullable; 8 | 9 | import com.zinc.jrecycleview.adapter.JRefreshAndLoadMoreAdapter; 10 | import com.zinc.jrecycleview.utils.LogUtils; 11 | 12 | /** 13 | * author : Jiang Pengyong 14 | * time : 2018-03-19 12:34 15 | * email : 56002982@qq.com 16 | * desc : 加载更多,抽象类 17 | * version : 1.0.0 18 | */ 19 | 20 | public abstract class IBaseLoadMoreView extends IBaseWrapperView { 21 | 22 | protected JRefreshAndLoadMoreAdapter.OnLoadMoreListener mOnLoadMoreListener; 23 | 24 | public IBaseLoadMoreView(Context context) { 25 | super(context); 26 | } 27 | 28 | public IBaseLoadMoreView(Context context, 29 | @Nullable AttributeSet attrs) { 30 | super(context, attrs); 31 | } 32 | 33 | public IBaseLoadMoreView(Context context, 34 | @Nullable AttributeSet attrs, 35 | int defStyleAttr) { 36 | super(context, attrs, defStyleAttr); 37 | } 38 | 39 | @Override 40 | protected void wrapper(Context context, View view) { 41 | 42 | addView(view); 43 | 44 | measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 45 | this.mHeight = getMeasuredHeight(); 46 | } 47 | 48 | public void setOnLoadMoreListener(JRefreshAndLoadMoreAdapter.OnLoadMoreListener listener) { 49 | this.mOnLoadMoreListener = listener; 50 | } 51 | 52 | public JRefreshAndLoadMoreAdapter.OnLoadMoreListener getOnLoadMoreListener() { 53 | return mOnLoadMoreListener; 54 | } 55 | 56 | /** 57 | * 释放动作,会进入两种状态:1、等待刷新;2、正在刷新; 58 | * 59 | * @param visible 可见高度 60 | * @return 返回是否正在刷新 61 | */ 62 | public boolean releaseAction(int visible) { 63 | //是否正在刷新 64 | boolean isOnRefresh = false; 65 | 66 | LogUtils.i(TAG, "visible: " + visible + "; height: " + mHeight); 67 | 68 | //如果释放的时候,大于刷新视图的高度值且未进入刷新状态,则需要进入刷新状态 69 | if (visible > this.mHeight && this.mCurState < STATE_EXECUTING) { 70 | setState(STATE_EXECUTING); 71 | isOnRefresh = true; 72 | } 73 | 74 | smoothScrollTo(this.mHeight); 75 | 76 | return isOnRefresh; 77 | } 78 | 79 | /** 80 | * 加载完毕 81 | */ 82 | public void loadComplete() { 83 | setState(STATE_DONE); 84 | reset(mHeight); 85 | } 86 | 87 | /** 88 | * 重置 89 | */ 90 | public void reset() { 91 | setState(STATE_PULL_TO_ACTION); 92 | reset(mHeight); 93 | } 94 | 95 | /** 96 | * 加载错误 97 | */ 98 | public void loadError() { 99 | setState(STATE_ERROR); 100 | } 101 | 102 | /** 103 | * 没有更多 104 | */ 105 | public void noMore() { 106 | setState(STATE_NO_MORE); 107 | smoothScrollTo(mHeight); 108 | } 109 | 110 | @Override 111 | protected void onOther(int state) { 112 | switch (state) { 113 | case STATE_NO_MORE: 114 | onNoMore(); 115 | break; 116 | case STATE_ERROR: 117 | onError(); 118 | break; 119 | } 120 | } 121 | 122 | /** 123 | * @param visibleHeight 可视高度 124 | * @param delta 垂直增量 125 | */ 126 | public void onMove(int visibleHeight, float delta) { 127 | //需要符合:1、可见高度大于控件高度;2、拉动距离要大于0 128 | float viewHeight = visibleHeight + delta; 129 | if (viewHeight < mHeight) { 130 | viewHeight = mHeight; 131 | } 132 | setVisibleHeight((int) viewHeight); 133 | 134 | LogUtils.i(TAG, 135 | "visibleHeight: " + visibleHeight + "; " + 136 | "height: " + mHeight + "; " + 137 | "viewHeight: " + viewHeight); 138 | 139 | //当前状态为: 1、上拉刷新; 2、释放刷新 140 | if (this.mCurState <= STATE_RELEASE_TO_ACTION) { 141 | //小于loadView高度 142 | if (visibleHeight <= mHeight) { 143 | if (this.mCurState == STATE_ERROR) { 144 | setState(STATE_ERROR); 145 | } else { 146 | setState(STATE_PULL_TO_ACTION); 147 | } 148 | } else { 149 | setState(STATE_RELEASE_TO_ACTION); 150 | } 151 | } 152 | 153 | } 154 | 155 | /** 156 | * 没有更多状态 157 | */ 158 | protected abstract void onNoMore(); 159 | 160 | /** 161 | * 加载出错 162 | */ 163 | protected abstract void onError(); 164 | 165 | } 166 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/loadview/base/IBaseRefreshLoadView.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.loadview.base; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | 7 | import androidx.annotation.Nullable; 8 | 9 | import com.zinc.jrecycleview.adapter.JRefreshAndLoadMoreAdapter; 10 | import com.zinc.jrecycleview.loadview.bean.MoveInfo; 11 | import com.zinc.jrecycleview.utils.LogUtils; 12 | 13 | /** 14 | * author : Jiang Pengyong 15 | * time : 2018-03-17 15:54 16 | * email : 56002982@qq.com 17 | * desc : 下拉刷新 18 | * version : 1.0.0 19 | */ 20 | 21 | public abstract class IBaseRefreshLoadView extends IBaseWrapperView { 22 | 23 | private MoveInfo mMoveInfo; 24 | 25 | private JRefreshAndLoadMoreAdapter.OnRefreshListener mOnRefreshListener; 26 | 27 | public IBaseRefreshLoadView(Context context) { 28 | this(context, null, 0); 29 | } 30 | 31 | public IBaseRefreshLoadView(Context context, 32 | @Nullable AttributeSet attrs) { 33 | this(context, attrs, 0); 34 | } 35 | 36 | public IBaseRefreshLoadView(Context context, 37 | @Nullable AttributeSet attrs, 38 | int defStyleAttr) { 39 | super(context, attrs, defStyleAttr); 40 | 41 | mMoveInfo = new MoveInfo(); 42 | } 43 | 44 | @Override 45 | protected void wrapper(Context context, View view) { 46 | 47 | addView(view); 48 | 49 | measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 50 | this.mHeight = getMeasuredHeight(); 51 | 52 | setVisibleHeight(0); 53 | } 54 | 55 | public void setOnRefreshListener(JRefreshAndLoadMoreAdapter.OnRefreshListener listener) { 56 | this.mOnRefreshListener = listener; 57 | } 58 | 59 | public JRefreshAndLoadMoreAdapter.OnRefreshListener getOnRefreshListener() { 60 | return this.mOnRefreshListener; 61 | } 62 | 63 | /** 64 | * 释放动作,会进入两种状态:1、等待刷新;2、正在刷新; 65 | * 66 | * @param visibleHeight 可见高度 67 | * @return 是否正在刷新 68 | */ 69 | public boolean releaseAction(int visibleHeight) { 70 | // 是否正在刷新 71 | boolean isOnRefresh = false; 72 | // 可见高度 73 | // int height = visibleHeight; 74 | // 此次释放后,需要进入的目标高度 75 | int destHeight = 0; 76 | 77 | // 当前已经正在刷新,则让视图回到加载视图的高度(正在刷新,不用返回true,否则会再触发) 78 | if (this.mCurState == STATE_EXECUTING) { 79 | destHeight = this.mHeight; 80 | } 81 | 82 | // 如果释放的时候,大于刷新视图的高度值且未进入刷新状态,则需要进入刷新状态 83 | if (visibleHeight > this.mHeight && this.mCurState < STATE_EXECUTING) { 84 | setState(STATE_EXECUTING); 85 | destHeight = this.mHeight; 86 | isOnRefresh = true; 87 | } 88 | 89 | smoothScrollTo(destHeight); 90 | 91 | return isOnRefresh; 92 | } 93 | 94 | /** 95 | * @param delta 垂直增量 96 | */ 97 | public void onMove(int visibleHeight, int delta) { 98 | 99 | LogUtils.i(TAG, "[visibleHeight: " + visibleHeight + "; " + 100 | "delta: " + delta + "]"); 101 | 102 | //需要符合:1、可见高度大于0,即用户已有向下拉动;2、拉动距离要大于0 103 | if (visibleHeight > 0 || delta > 0) { 104 | setVisibleHeight((visibleHeight + delta)); 105 | 106 | //当前状态为1、下拉刷新;2、释放刷新 107 | if (mCurState <= STATE_RELEASE_TO_ACTION) { 108 | 109 | //小于loadView高度 110 | if (visibleHeight <= mHeight) { 111 | setState(STATE_PULL_TO_ACTION); 112 | } else { 113 | setState(STATE_RELEASE_TO_ACTION); 114 | } 115 | 116 | } 117 | 118 | int height; 119 | if (visibleHeight >= mHeight) { 120 | height = mHeight; 121 | } else { 122 | height = visibleHeight; 123 | } 124 | 125 | mMoveInfo.setViewHeight(mHeight); 126 | mMoveInfo.setDragHeight(visibleHeight); 127 | mMoveInfo.setPercent(height * 100 / mHeight); 128 | 129 | onMoving(mMoveInfo); 130 | 131 | } 132 | } 133 | 134 | public void refreshComplete() { 135 | setState(STATE_DONE); 136 | reset(0); 137 | } 138 | 139 | @Override 140 | protected void onOther(int state) { 141 | //目前空实现,需扩展,可子类进行重写 142 | } 143 | 144 | /** 145 | * 下拉过程中的回调,可以更加细微的处理动画 146 | * 147 | * @param moveInfo 148 | */ 149 | protected abstract void onMoving(MoveInfo moveInfo); 150 | 151 | } 152 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/loadview/base/IBaseWrapperView.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.loadview.base; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.content.Context; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | import android.widget.LinearLayout; 8 | 9 | import androidx.annotation.Nullable; 10 | 11 | import com.zinc.jrecycleview.utils.LogUtils; 12 | 13 | /** 14 | * author : Jiang Pengyong 15 | * time : 2018-04-16 14:28 16 | * email : 56002982@qq.com 17 | * desc : 上拉和下拉基类 18 | * version : 1.0.0 19 | */ 20 | 21 | public abstract class IBaseWrapperView extends LinearLayout { 22 | 23 | protected String TAG = this.getClass().getSimpleName(); 24 | 25 | protected final static int INDEX = 1; 26 | 27 | private static final int SCROLL_DURATION = 300; 28 | 29 | // 加载出错 30 | public final static int STATE_ERROR = INDEX; 31 | // 下拉刷新或上拉更多状态: 32 | // 1、还没操作; 33 | // 2、下拉的高度未超过显示的高度; 34 | public final static int STATE_PULL_TO_ACTION = INDEX << 1; 35 | // 释放执行 36 | public final static int STATE_RELEASE_TO_ACTION = INDEX << 2; 37 | // 执行中 38 | public final static int STATE_EXECUTING = INDEX << 3; 39 | // 执行完毕 40 | public final static int STATE_DONE = INDEX << 4; 41 | // 没有更多 42 | public final static int STATE_NO_MORE = INDEX << 5; 43 | 44 | // 当前状态 45 | protected int mCurState; 46 | 47 | // 本视图高度 48 | protected int mHeight; 49 | 50 | public IBaseWrapperView(Context context) { 51 | this(context, null, 0); 52 | } 53 | 54 | public IBaseWrapperView(Context context, 55 | @Nullable AttributeSet attrs) { 56 | this(context, attrs, 0); 57 | } 58 | 59 | public IBaseWrapperView(Context context, 60 | @Nullable AttributeSet attrs, 61 | int defStyleAttr) { 62 | super(context, attrs, defStyleAttr); 63 | 64 | init(context); 65 | } 66 | 67 | private void init(Context context) { 68 | this.mCurState = STATE_PULL_TO_ACTION; 69 | 70 | LayoutParams layoutParams = 71 | new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 72 | layoutParams.setMargins(0, 0, 0, 0); 73 | setLayoutParams(layoutParams); 74 | setPadding(0, 0, 0, 0); 75 | 76 | View view = initView(context); 77 | wrapper(context, view); 78 | } 79 | 80 | protected abstract void wrapper(Context context, View view); 81 | 82 | public int getViewHeight() { 83 | return this.mHeight; 84 | } 85 | 86 | public void setHeight(int height) { 87 | this.mHeight = height; 88 | } 89 | 90 | /** 91 | * 获取当前状态 92 | */ 93 | public int getCurState() { 94 | return mCurState; 95 | } 96 | 97 | /** 98 | * 获取刷新的根视图 99 | */ 100 | protected abstract View getLoadView(); 101 | 102 | /** 103 | * 获取加载视图的高度 104 | */ 105 | public int getVisibleHeight() { 106 | LinearLayout.LayoutParams layoutParams 107 | = (LinearLayout.LayoutParams) this.getLoadView().getLayoutParams(); 108 | return layoutParams.height; 109 | } 110 | 111 | /** 112 | * 设置加载View的高度 113 | * 114 | * @param height 设置可见高度 115 | */ 116 | protected void setVisibleHeight(int height) { 117 | if (height <= 0) { 118 | height = 0; 119 | } 120 | LinearLayout.LayoutParams layoutParams 121 | = (LinearLayout.LayoutParams) getLoadView().getLayoutParams(); 122 | layoutParams.height = height; 123 | getLoadView().setLayoutParams(layoutParams); 124 | } 125 | 126 | /** 127 | * 设置当前状态 128 | * 129 | * @param state 当前状态 130 | */ 131 | public void setState(int state) { 132 | //如果与当前状态相同,不做任何处理 133 | if (state == this.mCurState) { 134 | return; 135 | } 136 | 137 | LogUtils.i(TAG, "state: " + state); 138 | 139 | switch (state) { 140 | //下拉执行 141 | case STATE_PULL_TO_ACTION: 142 | onPullToAction(); 143 | break; 144 | 145 | //释放执行 146 | case STATE_RELEASE_TO_ACTION: 147 | onReleaseToAction(); 148 | break; 149 | 150 | //执行中 151 | case STATE_EXECUTING: 152 | onExecuting(); 153 | break; 154 | 155 | //执行完毕 156 | case STATE_DONE: 157 | onDone(); 158 | break; 159 | default: 160 | onOther(state); 161 | } 162 | 163 | //保存为当前状态 164 | this.mCurState = state; 165 | } 166 | 167 | /** 168 | * 重置状态 169 | * 170 | * @param destHeight 目标高度 171 | */ 172 | protected void reset(int destHeight) { 173 | smoothScrollTo(destHeight); 174 | postDelayed(new Runnable() { 175 | @Override 176 | public void run() { 177 | setState(STATE_PULL_TO_ACTION); 178 | } 179 | }, 200); 180 | } 181 | 182 | /** 183 | * 平滑滚动至某个高度 184 | * 185 | * @param destHeight 目标高度 186 | */ 187 | protected void smoothScrollTo(int destHeight) { 188 | smoothScrollTo(destHeight, SCROLL_DURATION); 189 | } 190 | 191 | /** 192 | * 平滑滚动至某个高度 193 | * 194 | * @param destHeight 目标高度 195 | * @param durTime 时长 196 | */ 197 | protected void smoothScrollTo(int destHeight, int durTime) { 198 | // 设置从可见高度->目标高度 199 | ValueAnimator valueAnimator = ValueAnimator.ofInt(getVisibleHeight(), destHeight); 200 | valueAnimator.setDuration(durTime); 201 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 202 | @Override 203 | public void onAnimationUpdate(ValueAnimator animation) { 204 | setVisibleHeight((Integer) animation.getAnimatedValue()); 205 | } 206 | }); 207 | valueAnimator.start(); 208 | } 209 | 210 | /** 211 | * 等待上拉 或 等待下拉的状态 视图表现 212 | */ 213 | protected abstract void onPullToAction(); 214 | 215 | /** 216 | * 释放执行(释放刷新 或 释放加载更多)视图表现 217 | */ 218 | protected abstract void onReleaseToAction(); 219 | 220 | /** 221 | * 执行中 视图表现 222 | */ 223 | protected abstract void onExecuting(); 224 | 225 | /** 226 | * 执行完视图表现 227 | */ 228 | protected abstract void onDone(); 229 | 230 | /** 231 | * 扩展方法,主要用于后面扩展一写细节的状态, 232 | * 现用于LoadMore增加{@link IBaseLoadMoreView#STATE_NO_MORE}状态 233 | * 234 | * @param state 当前状态 235 | */ 236 | protected abstract void onOther(int state); 237 | 238 | /** 239 | * 初始化视图,用于加载自己的视图 240 | * 241 | * @param context 上下文 242 | * @return 视图 243 | */ 244 | protected abstract View initView(Context context); 245 | 246 | } 247 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/loadview/bean/MoveInfo.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.loadview.bean; 2 | 3 | /** 4 | * author : Jiang Pengyong 5 | * time : 2018-04-17 16:07 6 | * email : 56002982@qq.com 7 | * desc : 移动信息 8 | * version : 1.0.0 9 | */ 10 | 11 | public class MoveInfo { 12 | 13 | // 视图的高度 14 | private int viewHeight; 15 | // 下拉高度 16 | private int dragHeight; 17 | // 百分比(最大100,最小0) 18 | private int percent; 19 | 20 | public MoveInfo() { 21 | } 22 | 23 | public int getViewHeight() { 24 | return viewHeight; 25 | } 26 | 27 | public void setViewHeight(int viewHeight) { 28 | this.viewHeight = viewHeight; 29 | } 30 | 31 | public int getDragHeight() { 32 | return dragHeight; 33 | } 34 | 35 | public void setDragHeight(int dragHeight) { 36 | this.dragHeight = dragHeight; 37 | } 38 | 39 | public int getPercent() { 40 | return percent; 41 | } 42 | 43 | public void setPercent(int percent) { 44 | this.percent = percent; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "MoveInfo{" + 50 | "viewHeight=" + viewHeight + 51 | ", dragHeight=" + dragHeight + 52 | ", percent=" + percent + 53 | '}'; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/stick/IStick.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.stick; 2 | 3 | /** 4 | * author : Jiang Pengyong 5 | * time : 2019-07-26 17:09 6 | * desc : 粘性接口 7 | * version : 1.0.0 8 | */ 9 | public interface IStick { 10 | } 11 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/swipe/JSwipeConstant.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.swipe; 2 | 3 | /** 4 | * author : Jiang Pengyong 5 | * time : 2019-08-18 15:11 6 | * email : 56002982@qq.com 7 | * desc : 侧滑常量 8 | * version : 1.0.0 9 | */ 10 | 11 | public interface JSwipeConstant { 12 | 13 | int LEFT = 1; 14 | int RIGHT = 1 << 1; 15 | int CONTENT = 1 << 2; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/swipe/JSwipeViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.swipe; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.widget.FrameLayout; 6 | 7 | import androidx.recyclerview.widget.RecyclerView; 8 | 9 | import com.zinc.librecycleview.R; 10 | 11 | /** 12 | * author : Jiang Pengyong 13 | * time : 2018-04-08 14:37 14 | * email : 56002982@qq.com 15 | * desc : 侧滑的ViewHolder 16 | * version : 1.0.0 17 | */ 18 | 19 | public abstract class JSwipeViewHolder extends RecyclerView.ViewHolder { 20 | 21 | private static final int NONE = -1; 22 | 23 | private FrameLayout flLeftMenu; 24 | private FrameLayout flContent; 25 | private FrameLayout flRightMenu; 26 | 27 | private JSwipeItemLayout swipeItemLayout; 28 | 29 | public JSwipeViewHolder(View itemView) { 30 | super(itemView); 31 | 32 | swipeItemLayout = itemView.findViewById(R.id.swipe_item_layout); 33 | flLeftMenu = itemView.findViewById(R.id.fl_left_menu); 34 | flContent = itemView.findViewById(R.id.fl_content); 35 | flRightMenu = itemView.findViewById(R.id.fl_right_menu); 36 | 37 | flLeftMenu.removeAllViews(); 38 | flRightMenu.removeAllViews(); 39 | flContent.removeAllViews(); 40 | 41 | if (getLeftMenuLayout() != NONE) { 42 | LayoutInflater 43 | .from(itemView.getContext()) 44 | .inflate(getLeftMenuLayout(), flLeftMenu, true); 45 | 46 | initLeftMenuItem(flLeftMenu); 47 | swipeItemLayout 48 | .getMenus() 49 | .put(JSwipeConstant.LEFT, flLeftMenu); 50 | } 51 | 52 | if (getRightMenuLayout() != NONE) { 53 | LayoutInflater 54 | .from(itemView.getContext()) 55 | .inflate(getRightMenuLayout(), flRightMenu, true); 56 | 57 | initRightMenuItem(flRightMenu); 58 | swipeItemLayout 59 | .getMenus() 60 | .put(JSwipeConstant.RIGHT, flRightMenu); 61 | } 62 | 63 | LayoutInflater.from(itemView.getContext()) 64 | .inflate(getContentLayout(), flContent, true); 65 | initContentItem(flContent); 66 | 67 | initItem(swipeItemLayout); 68 | 69 | } 70 | 71 | public JSwipeItemLayout getSwipeItemLayout() { 72 | return swipeItemLayout; 73 | } 74 | 75 | /** 76 | * 获取左菜单布局 77 | * 78 | * @return 左菜单的 xml 79 | */ 80 | public int getLeftMenuLayout() { 81 | return NONE; 82 | } 83 | 84 | /** 85 | * 获取右菜单布局 86 | * 87 | * @return 右菜单的 xml 88 | */ 89 | public int getRightMenuLayout() { 90 | return NONE; 91 | } 92 | 93 | /** 94 | * 获取内容布局 95 | * 96 | * @return 内容的 xml 97 | */ 98 | public abstract int getContentLayout(); 99 | 100 | /** 101 | * 初始化左菜单项 102 | * 103 | * @param flLeftMenu 左菜单视图 104 | */ 105 | public void initLeftMenuItem(FrameLayout flLeftMenu) { 106 | 107 | } 108 | 109 | /** 110 | * 初始化右菜单项 111 | * 112 | * @param flRightMenu 右菜单视图 113 | */ 114 | public void initRightMenuItem(FrameLayout flRightMenu) { 115 | 116 | } 117 | 118 | /** 119 | * 初始化内容项 120 | * 121 | * @param flContent 内容视图 122 | */ 123 | public void initContentItem(FrameLayout flContent) { 124 | } 125 | 126 | /** 127 | * 初始化视图 128 | * 129 | * @param frameLayout 包含[左菜单视图,内容视图,右菜单视图] 130 | */ 131 | public abstract void initItem(FrameLayout frameLayout); 132 | 133 | } 134 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/utils/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.utils; 2 | 3 | import android.util.Log; 4 | 5 | import com.zinc.jrecycleview.config.JRecycleViewManager; 6 | 7 | /** 8 | * author : Jiang Pengyong 9 | * time : 2019-08-16 14:09 10 | * desc : 日志打印 11 | * version : 1.0.0 12 | */ 13 | public class LogUtils { 14 | 15 | private static final String TAG = "JRecycleView"; 16 | 17 | public static void i(String tag, String msg) { 18 | if (JRecycleViewManager.getInstance().isDebug()) { 19 | Log.i(tag, msg); 20 | } 21 | } 22 | 23 | public static void d(String tag, String msg) { 24 | if (JRecycleViewManager.getInstance().isDebug()) { 25 | Log.d(tag, msg); 26 | } 27 | } 28 | 29 | public static void w(String tag, String msg) { 30 | if (JRecycleViewManager.getInstance().isDebug()) { 31 | Log.w(tag, msg); 32 | } 33 | } 34 | 35 | public static void v(String tag, String msg) { 36 | if (JRecycleViewManager.getInstance().isDebug()) { 37 | Log.v(tag, msg); 38 | } 39 | } 40 | 41 | public static void e(String tag, String msg) { 42 | if (JRecycleViewManager.getInstance().isDebug()) { 43 | Log.i(tag, msg); 44 | } 45 | } 46 | 47 | public static void i(String msg) { 48 | Log.i(TAG, msg); 49 | } 50 | 51 | public static void d(String msg) { 52 | Log.d(TAG, msg); 53 | } 54 | 55 | public static void w(String msg) { 56 | Log.w(TAG, msg); 57 | } 58 | 59 | public static void v(String msg) { 60 | Log.v(TAG, msg); 61 | } 62 | 63 | public static void e(String msg) { 64 | Log.i(TAG, msg); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/utils/MathUtil.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.utils; 2 | 3 | import android.graphics.PointF; 4 | 5 | /** 6 | * author : Jiang Pengyong 7 | * time : 2019-08-16 10:26 8 | * email : 56002982@qq.com 9 | * desc : 10 | * version : 1.0.0 11 | */ 12 | public class MathUtil { 13 | 14 | /** 15 | * 获得两点之间的直线距离 16 | * 17 | * @param p1 PointF 18 | * @param p2 PointF 19 | * @return 两点之间的直线距离 20 | */ 21 | public static float getTwoPointDistance(PointF p1, PointF p2) { 22 | return (float) Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)); 23 | } 24 | 25 | /** 26 | * 根据两个点(x1,y1)(x2,y2)的坐标算出斜率 27 | * 28 | * @param x1 x1 29 | * @param x2 x2 30 | * @param y1 y1 31 | * @param y2 y2 32 | * @return 斜率 33 | */ 34 | public static Float getLineSlope(float x1, float x2, float y1, float y2) { 35 | if (x2 - x1 == 0) return null; 36 | return (y2 - y1) / (x2 - x1); 37 | } 38 | 39 | /** 40 | * 根据传入的两点得到斜率 41 | * 42 | * @param p1 PointF 43 | * @param p2 PointF 44 | * @return 返回斜率 45 | */ 46 | public static Float getLineSlope(PointF p1, PointF p2) { 47 | if (p2.x - p1.x == 0) return null; 48 | return (p2.y - p1.y) / (p2.x - p1.x); 49 | } 50 | 51 | /** 52 | * Get middle point between p1 and p2. 53 | * 获得两点连线的中点 54 | * 55 | * @param p1 PointF 56 | * @param p2 PointF 57 | * @return 中点 58 | */ 59 | public static PointF getMiddlePoint(PointF p1, PointF p2) { 60 | return new PointF((p1.x + p2.x) / 2.0f, (p1.y + p2.y) / 2.0f); 61 | } 62 | 63 | 64 | /** 65 | * Get the point of intersection between circle and line. 66 | * 获取 通过指定圆心,斜率为lineK的直线与圆的交点。 67 | * 68 | * @param pMiddle The circle center point. 69 | * @param radius The circle radius. 70 | * @param lineK The slope of line which cross the pMiddle. 71 | * @return 72 | */ 73 | public static PointF[] getIntersectionPoints(PointF pMiddle, float radius, Float lineK) { 74 | PointF[] points = new PointF[2]; 75 | 76 | float radian, xOffset = 0, yOffset = 0; 77 | if (lineK != null) { 78 | radian = (float) Math.atan(lineK); 79 | xOffset = (float) (Math.sin(radian) * radius); 80 | yOffset = (float) (Math.cos(radian) * radius); 81 | } else { 82 | xOffset = radius; 83 | yOffset = 0; 84 | } 85 | points[0] = new PointF(pMiddle.x + xOffset, pMiddle.y - yOffset); 86 | points[1] = new PointF(pMiddle.x - xOffset, pMiddle.y + yOffset); 87 | 88 | return points; 89 | } 90 | 91 | 92 | } 93 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/utils/PointEvaluator.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.utils; 2 | 3 | import android.animation.TypeEvaluator; 4 | import android.graphics.PointF; 5 | 6 | /** 7 | * author : Jiang Pengyong 8 | * time : 2019-08-16 10:25 9 | * email : 56002982@qq.com 10 | * desc : 点的估值器 11 | * version : 0.1.0 12 | */ 13 | public class PointEvaluator implements TypeEvaluator { 14 | @Override 15 | public PointF evaluate(float fraction, 16 | PointF startValue, 17 | PointF endValue) { 18 | float x = startValue.x + fraction * (endValue.x - startValue.x); 19 | float y = startValue.y + fraction * (endValue.y - startValue.y); 20 | return new PointF(x, y); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/java/com/zinc/jrecycleview/widget/BallSpinFadeLoader.java: -------------------------------------------------------------------------------- 1 | package com.zinc.jrecycleview.widget; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import androidx.core.content.ContextCompat; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import com.zinc.librecycleview.R; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * author : Jiang Pengyong 18 | * time : 2018-03-17 15:35 19 | * email : 56002982@qq.com 20 | * desc : loading 21 | * version : 1.0.0 22 | */ 23 | 24 | public class BallSpinFadeLoader extends View { 25 | 26 | private Paint mPaint; 27 | 28 | private float mCenterX; 29 | private float mCenterY; 30 | private float mRadius; 31 | 32 | private volatile boolean mAnimatorEnable; 33 | 34 | float[] scaleFloats = new float[]{SCALE, 35 | SCALE, 36 | SCALE, 37 | SCALE, 38 | SCALE, 39 | SCALE, 40 | SCALE, 41 | SCALE}; 42 | 43 | int[] alphas = new int[]{ALPHA, 44 | ALPHA, 45 | ALPHA, 46 | ALPHA, 47 | ALPHA, 48 | ALPHA, 49 | ALPHA, 50 | ALPHA}; 51 | 52 | 53 | public static final float SCALE = 1.0f; 54 | public static final int ALPHA = 255; 55 | 56 | private final List scaleAnimList = new ArrayList<>(); 57 | private final List alphaAnimList = new ArrayList<>(); 58 | 59 | public BallSpinFadeLoader(Context context) { 60 | this(context, null); 61 | } 62 | 63 | public BallSpinFadeLoader(Context context, 64 | AttributeSet attrs) { 65 | this(context, attrs, 0); 66 | } 67 | 68 | public BallSpinFadeLoader(Context context, 69 | AttributeSet attrs, 70 | int defStyleAttr) { 71 | super(context, attrs, defStyleAttr); 72 | init(context); 73 | } 74 | 75 | private void init(Context context) { 76 | mPaint = new Paint(); 77 | mPaint.setAntiAlias(true); 78 | mPaint.setStyle(Paint.Style.FILL); 79 | mPaint.setStrokeWidth(dip2px(1)); 80 | mPaint.setColor(ContextCompat.getColor(context, R.color.j_recycle_balling_color)); 81 | 82 | int[] delays = {0, 120, 240, 360, 480, 600, 720, 780, 840}; 83 | for (int i = 0; i < 8; i++) { 84 | 85 | ValueAnimator scaleAnim = ValueAnimator.ofFloat(1, 0.4f, 1); 86 | scaleAnim.setDuration(1000); 87 | scaleAnim.setRepeatMode(ValueAnimator.RESTART); 88 | scaleAnim.setRepeatCount(ValueAnimator.INFINITE); 89 | scaleAnim.setStartDelay(delays[i]); 90 | scaleAnimList.add(scaleAnim); 91 | 92 | ValueAnimator alphaAnim = ValueAnimator.ofInt(255, 77, 255); 93 | alphaAnim.setDuration(1000); 94 | alphaAnim.setRepeatMode(ValueAnimator.RESTART); 95 | alphaAnim.setRepeatCount(ValueAnimator.INFINITE); 96 | alphaAnim.setStartDelay(delays[i]); 97 | alphaAnimList.add(alphaAnim); 98 | } 99 | 100 | } 101 | 102 | @Override 103 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 104 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 105 | int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 106 | int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 107 | 108 | int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 109 | int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 110 | 111 | //处理 wrap_content问题 112 | int defaultDimension = dip2px(30); 113 | 114 | if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) { 115 | setMeasuredDimension(defaultDimension, defaultDimension); 116 | } else if (widthSpecMode == MeasureSpec.AT_MOST) { 117 | setMeasuredDimension(defaultDimension, heightSpecSize); 118 | } else if (heightSpecMode == MeasureSpec.AT_MOST) { 119 | setMeasuredDimension(widthSpecSize, defaultDimension); 120 | } 121 | 122 | } 123 | 124 | @Override 125 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 126 | super.onSizeChanged(w, h, oldw, oldh); 127 | mRadius = w / 10; 128 | mCenterX = w >> 1; 129 | mCenterY = h >> 1; 130 | } 131 | 132 | 133 | public int dip2px(float dpValue) { 134 | final float scale = getContext().getResources().getDisplayMetrics().density; 135 | return (int) (dpValue * scale + 0.5f); 136 | } 137 | 138 | @Override 139 | protected void onDraw(Canvas canvas) { 140 | super.onDraw(canvas); 141 | 142 | for (int i = 0; i < alphas.length; i++) { 143 | canvas.save(); 144 | canvas.translate(mCenterX + ((getWidth() >> 1) - mRadius) * (float) Math.cos(Math.toRadians(i * 45)), 145 | mCenterY + ((getWidth() >> 1) - mRadius) * (float) Math.sin(Math.toRadians(i * 45))); 146 | canvas.scale(scaleFloats[i], scaleFloats[i]); 147 | mPaint.setAlpha(alphas[i]); 148 | canvas.drawCircle(0, 0, mRadius, mPaint); 149 | canvas.restore(); 150 | } 151 | } 152 | 153 | public void startAnimator() { 154 | 155 | for (int i = 0; i < scaleAnimList.size(); i++) { 156 | ValueAnimator valueAnimator = scaleAnimList.get(i); 157 | 158 | final int index = i; 159 | 160 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 161 | @Override 162 | public void onAnimationUpdate(ValueAnimator animation) { 163 | scaleFloats[index] = (float) animation.getAnimatedValue(); 164 | postInvalidate(); 165 | } 166 | }); 167 | valueAnimator.start(); 168 | } 169 | 170 | for (int i = 0; i < alphaAnimList.size(); i++) { 171 | ValueAnimator valueAnimator = alphaAnimList.get(i); 172 | 173 | final int index = i; 174 | 175 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 176 | @Override 177 | public void onAnimationUpdate(ValueAnimator animation) { 178 | alphas[index] = (int) animation.getAnimatedValue(); 179 | postInvalidate(); 180 | } 181 | }); 182 | 183 | valueAnimator.start(); 184 | } 185 | 186 | mAnimatorEnable = true; 187 | 188 | } 189 | 190 | public boolean isLoading() { 191 | return mAnimatorEnable; 192 | } 193 | 194 | public void stopAnimator() { 195 | if (isLoading()) { 196 | for (ValueAnimator valueAnimator : scaleAnimList) { 197 | valueAnimator.removeAllUpdateListeners(); 198 | valueAnimator.cancel(); 199 | } 200 | 201 | for (ValueAnimator valueAnimator : alphaAnimList) { 202 | valueAnimator.removeAllUpdateListeners(); 203 | valueAnimator.cancel(); 204 | } 205 | } 206 | 207 | mAnimatorEnable = false; 208 | } 209 | 210 | @Override 211 | protected void onAttachedToWindow() { 212 | super.onAttachedToWindow(); 213 | startAnimator(); 214 | } 215 | 216 | @Override 217 | protected void onDetachedFromWindow() { 218 | super.onDetachedFromWindow(); 219 | stopAnimator(); 220 | } 221 | } -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/drawable-xhdpi/red_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/lib.recycleview/src/main/res/drawable-xhdpi/red_bg.9.png -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/drawable/j_recycle_icon_refresh_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/lib.recycleview/src/main/res/drawable/j_recycle_icon_refresh_arrow.png -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/drawable/j_recycle_icon_reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/lib.recycleview/src/main/res/drawable/j_recycle_icon_reload.png -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/layout/j_swipe_wrapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 13 | 14 | 15 | 20 | 21 | 22 | 26 | 27 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/layout/j_widget_ordinary_load_more_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 20 | 21 | 28 | 29 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/layout/j_widget_ordinary_load_refresh_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 23 | 24 | 30 | 31 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/mipmap-xhdpi/explode1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/lib.recycleview/src/main/res/mipmap-xhdpi/explode1.png -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/mipmap-xhdpi/explode2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/lib.recycleview/src/main/res/mipmap-xhdpi/explode2.png -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/mipmap-xhdpi/explode3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/lib.recycleview/src/main/res/mipmap-xhdpi/explode3.png -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/mipmap-xhdpi/explode4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/lib.recycleview/src/main/res/mipmap-xhdpi/explode4.png -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/mipmap-xhdpi/explode5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zincPower/JRecycleView/d8409e915d29423a0f6311d81d3a1f942b004d31/lib.recycleview/src/main/res/mipmap-xhdpi/explode5.png -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #bfbfbf 5 | #bfbfbf 6 | 7 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12sp 5 | 12sp 6 | 7 | -------------------------------------------------------------------------------- /lib.recycleview/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | lib.recycleview 3 | 4 | 正在加载中… 5 | ----没有更多了---- 6 | 上拉重新加载 7 | 上拉加载 8 | 释放立即加载 9 | 上拉加载 10 | 11 | 下拉刷新 12 | 释放立即刷新 13 | 正在刷新… 14 | 刷新完成 15 | 16 | 17 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':lib.recycleview' 2 | --------------------------------------------------------------------------------