├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── wellijohn
│ │ └── org
│ │ └── scrollviewwithstickview
│ │ ├── AndroidWidgetActivity.java
│ │ ├── LinearLayoutManagerUnScrollable.java
│ │ ├── Main2Activity.java
│ │ ├── MainActivity.java
│ │ ├── adapter
│ │ ├── RVRightListAdapter.java
│ │ ├── ReListAdapter.java
│ │ └── TabFragmentAdapter.java
│ │ ├── constant
│ │ └── Constant.java
│ │ ├── fragment
│ │ ├── ChildRecyclerViewFragment.java
│ │ ├── ChildScrollViewFragment.java
│ │ ├── LazyFragment.java
│ │ ├── NoScrollWebView.java
│ │ └── RecyclerViewFragment.java
│ │ └── listener
│ │ └── OnRVItemClickListener.java
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable-xxhdpi
│ └── food.jpg
│ ├── drawable
│ ├── btn_border_gray_999_bg.xml
│ ├── btn_green_big_nomal_bg.xml
│ ├── btn_yellow_full_small_corner_bg.xml
│ └── ic_launcher_background.xml
│ ├── layout
│ ├── activity_android_widget.xml
│ ├── activity_main.xml
│ ├── activity_main2.xml
│ ├── demo_child_scroll.xml
│ ├── just_recyclerview.xml
│ ├── recyclerview.xml
│ ├── rv_item.xml
│ ├── rv_rightitem.xml
│ └── title.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── arrays.xml
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── imgs
├── QR_code_258 .png
├── scrollsnap.gif
├── snapshot2.gif
└── 仿饿了么列表页.gif
├── settings.gradle
└── stickscrollview
├── .gitignore
├── build.gradle
├── jcenter.gradle
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
├── java
└── wellijohn
│ └── org
│ └── scrollviewwithstickheader
│ ├── ChildRecyclerView.java
│ ├── ChildScrollView.java
│ ├── ChildWebView.java
│ ├── Constant.java
│ ├── ScrollViewWithStickHeader.java
│ ├── layoutmanager
│ ├── NoSlideGridLayoutManager.java
│ └── NoSlideLinearLayoutManager.java
│ └── utils
│ ├── UIUtil.java
│ └── ViewUtil.java
└── res
└── values
├── attrs.xml
└── strings.xml
/.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/codeStyles/Project.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 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.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 |
33 |
34 |
35 |
36 |
37 | 1.8
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **前言,一天在点外卖的时候,注意到饿了么列表页的滑动效果不错,但是觉得其中的手势滑动还是挺复杂的,正好又碰到了在熟悉Touch事件的理解当中,所以就抽空对着饿了么的列表页面尝试写写这个效果,同时增加了双列表的联动效果**
2 | ** 在实现上述效果之后,用了下appbarlayout,觉得也能实现上述滑动的效果,不需要更改什么代码,体验上更好,具体可以看AndroidWidgetActivity,在这里面就是CollapsingToolbarLayout和appbarlayout的使用,完成上述的效果,可以简单看下实现的效果图,如果你们觉得满足需求了就不需要继续往下看了,如果想了解下手势点击原理的话,欢迎往下看提点意见:**
3 |
4 | ## APK下载地址
5 | 
6 | ## 1.先贴一个实现的效果图
7 | 
8 |
9 |
10 | ## 2.引入
11 | ```
12 | allprojects {
13 | repositories {
14 | jcenter()
15 | maven { url "https://jitpack.io" }
16 | }
17 | }
18 |
19 | dependencies {
20 | com.github.WelliJohn:StickScrollView:1.1.7
21 | }
22 | ```
23 |
24 | ## 3.界面的布局说明
25 | ```
26 |
30 |
31 |
38 | //这里是header部分,可以随便自定义
39 |
40 |
41 |
46 |
47 |
54 |
55 |
59 |
60 |
61 |
62 | ```
63 | 比如我们看到的仿饿了么的列表页界面,我们就需要在ViewPager设置Fragment,fragment中是左右两个列表,看下fragment的xml设置:
64 | ```
65 |
66 |
71 |
72 |
78 |
79 |
85 |
86 | ```
87 |
88 | ## 4.java代码必要设置
89 | ```
90 | mStickScrollView.setContentView(mLLStickList);//这个是必须的,mLLStickList就是你想到这个布局再滑动就是下面列表滑动的部分了。
91 | mStickScrollView.setSuspensionView(mViewBottom);//这个是底部的悬浮布局,如果没有可以不设置
92 | ```
93 |
94 | ## 5.注意事项
95 | * ScrollViewWithStickHeader内部目前支持放置ViewPager,ScrollView,RecyclerView,WebView
96 | * ScrollView,RecyclerView,WebView需要对应使用ChildScrollView,ChildRecyclerView,ChildWebView
97 | * 我们在使用的时候,需要调用mStickScrollView.setContentView(mContentView);mLLStickList就是我们需要StickHeader+列表的部分,如果你没有StickHeader的话,那么直接设置列表进来也可以,总之,你想滑动到哪个位置接下来滑动就是单纯下面的部分滑动,那你就把下面的View整体设置为mContentView。刚刚那个的ContentView是id为ll_stick_list的View。
98 | * 另外在这里ScrollViewWithStickHeader增加autoscroll属性,默认是关闭的,如果autoscroll:true的话,在我们手指放开的时候,contentView会判断是否自动滑动到顶部还是隐藏不见。
99 | * 暂不支持weight的使用,因为weight会进行二次绘制,所以如果要实现底部bottom的话,请用RelativeiLayout
100 | * 如果是用RecyclerView的话,LinearLayoutManager需要继承NoSlideLinearLayoutManager,GridLayoutManager需要继承NoSlideGridLayoutManager,new NoSlideLinearLayoutManager(context)。
101 |
102 | 
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "wellijohn.org.scrollviewwithstickview"
7 | minSdkVersion 14
8 | targetSdkVersion 28
9 | versionCode 5
10 | versionName "1.4"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 |
20 | lintOptions {
21 | abortOnError false
22 | }
23 |
24 | }
25 |
26 | dependencies {
27 | implementation fileTree(include: ['*.jar'], dir: 'libs')
28 | implementation 'com.android.support:appcompat-v7:27.1.1'
29 | implementation 'com.android.support.constraint:constraint-layout:1.1.2'
30 | implementation 'com.android.support:recyclerview-v7:27.1.1'
31 | implementation project(':stickscrollview')
32 | // implementation 'com.github.WelliJohn:StickScrollView:1.1.7'
33 | // compile 'wellijohn.org.tvanim:animtv:1.0.0'
34 | implementation 'com.android.support:design:27.1.1'
35 |
36 | // implementation 'com.github.WelliJohn:StickScrollView:0.0.1'
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/AndroidWidgetActivity.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.design.widget.AppBarLayout;
6 | import android.support.design.widget.CollapsingToolbarLayout;
7 | import android.support.design.widget.TabLayout;
8 | import android.support.v4.view.ViewPager;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.support.v7.widget.Toolbar;
11 | import android.widget.ImageView;
12 |
13 | import wellijohn.org.scrollviewwithstickview.adapter.TabFragmentAdapter;
14 |
15 | /**
16 | * @author: JiangWeiwei
17 | * @time: 2018/8/2-10:05
18 | * @email: jiangweiwei@qccr.com
19 | * @desc:
20 | */
21 | public class AndroidWidgetActivity extends AppCompatActivity {
22 | private AppBarLayout mAppBar;
23 | private CollapsingToolbarLayout mToolbarLayout;
24 | private ImageView mImageview;
25 | private Toolbar mToolbar;
26 | private TabLayout mTablayout;
27 | private ViewPager mVp;
28 | private TabFragmentAdapter mTabFragmentAdapter;
29 |
30 | @Override
31 | protected void onCreate(@Nullable Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | setContentView(R.layout.activity_android_widget);
34 | initView();
35 | initUI();
36 | }
37 |
38 | private void initUI() {
39 | mTabFragmentAdapter = new TabFragmentAdapter(getSupportFragmentManager());
40 | mVp.setAdapter(mTabFragmentAdapter);
41 | mVp.addOnPageChangeListener(
42 | new TabLayout.TabLayoutOnPageChangeListener(mTablayout));
43 | mVp.setOffscreenPageLimit(3);
44 | mTablayout.setupWithViewPager(mVp);
45 | }
46 |
47 | private void initView() {
48 | mAppBar = findViewById(R.id.app_bar);
49 | mToolbarLayout = findViewById(R.id.toolbar_layout);
50 | mImageview = findViewById(R.id.imageview);
51 | mToolbar = findViewById(R.id.toolbar);
52 | mTablayout = findViewById(R.id.tablayout);
53 | mVp = findViewById(R.id.viewpage);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/LinearLayoutManagerUnScrollable.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.LinearLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 |
11 | public class LinearLayoutManagerUnScrollable extends LinearLayoutManager {
12 | private int[] mMeasuredDimension = new int[2];
13 |
14 | public LinearLayoutManagerUnScrollable(Context context) {
15 | super(context);
16 | setAutoMeasureEnabled(false);
17 | }
18 |
19 | public LinearLayoutManagerUnScrollable(Context context, int orientation, boolean reverseLayout) {
20 | super(context, orientation, reverseLayout);
21 | setAutoMeasureEnabled(false);
22 | }
23 |
24 | public LinearLayoutManagerUnScrollable(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
25 | super(context, attrs, defStyleAttr, defStyleRes);
26 | setAutoMeasureEnabled(false);
27 | }
28 |
29 | @Override
30 | public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
31 | final int widthMode = View.MeasureSpec.getMode(widthSpec);
32 | final int heightMode = View.MeasureSpec.getMode(heightSpec);
33 | final int widthSize = View.MeasureSpec.getSize(widthSpec);
34 | final int heightSize = View.MeasureSpec.getSize(heightSpec);
35 |
36 | int width = 0;
37 | int height = 0;
38 | for (int i = 0; i < getItemCount(); i++) {
39 | measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
40 | View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), mMeasuredDimension);
41 | if (getOrientation() == HORIZONTAL) {
42 | width = width + mMeasuredDimension[0];
43 | if (i == 0) {
44 | height = mMeasuredDimension[1];
45 | }
46 | } else {
47 | height = height + mMeasuredDimension[1];
48 | if (i == 0) {
49 | width = mMeasuredDimension[0];
50 | }
51 | }
52 | }
53 |
54 | switch (widthMode) {
55 | case View.MeasureSpec.EXACTLY:
56 | width = widthSize;
57 | break;
58 | case View.MeasureSpec.AT_MOST:
59 | case View.MeasureSpec.UNSPECIFIED:
60 | }
61 |
62 | switch (heightMode) {
63 | case View.MeasureSpec.EXACTLY:
64 | height = heightSize;
65 | break;
66 | case View.MeasureSpec.AT_MOST:
67 | case View.MeasureSpec.UNSPECIFIED:
68 | }
69 |
70 | setMeasuredDimension(width, height);
71 | }
72 |
73 | private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
74 | int heightSpec, int[] measuredDimension) {
75 | try {
76 | View view = recycler.getViewForPosition(position);//Warning 动态添加时报IndexOutOfBoundsException
77 |
78 | if (view != null) {
79 | RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
80 |
81 | int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
82 | getPaddingLeft() + getPaddingRight(), p.width);
83 |
84 | int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
85 | getPaddingTop() + getPaddingBottom(), p.height);
86 |
87 | view.measure(childWidthSpec, childHeightSpec);
88 | measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
89 | measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
90 | recycler.recycleView(view);
91 | }
92 | } catch (Exception e) {
93 | e.printStackTrace();
94 | } finally {
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/Main2Activity.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 |
6 | public class Main2Activity extends AppCompatActivity {
7 |
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | setContentView(R.layout.activity_main2);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/MainActivity.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.design.widget.TabLayout;
6 | import android.support.v4.view.ViewPager;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.view.View;
10 | import android.webkit.WebSettings;
11 | import android.webkit.WebView;
12 | import android.widget.Button;
13 | import android.widget.LinearLayout;
14 | import android.widget.ScrollView;
15 | import android.widget.TextView;
16 |
17 | import wellijohn.org.scrollviewwithstickheader.ChildRecyclerView;
18 | import wellijohn.org.scrollviewwithstickheader.ChildScrollView;
19 | import wellijohn.org.scrollviewwithstickheader.ScrollViewWithStickHeader;
20 | import wellijohn.org.scrollviewwithstickview.adapter.ReListAdapter;
21 | import wellijohn.org.scrollviewwithstickview.adapter.TabFragmentAdapter;
22 |
23 | public class MainActivity extends AppCompatActivity {
24 |
25 | private TextView mTvStickHeader;
26 | private ScrollView mScrollviewChild;
27 | private RecyclerView mRv;
28 | private ReListAdapter mReListAdapter;
29 |
30 | private static final String TAG = "MainActivity";
31 | private TabLayout mOrderManagerTabs;
32 | private ChildScrollView mCsv;
33 | private ViewPager mVp;
34 | private TabFragmentAdapter mTabFragmentAdapter;
35 | private WebView mWebview;
36 | private LinearLayout mLLStickList;
37 | private Button mButton;
38 | private ScrollViewWithStickHeader mStickScrollView;
39 | private LinearLayout mLl;
40 | private ChildRecyclerView mCrv;
41 | private View mViewBottom;
42 |
43 | @Override
44 | protected void onCreate(Bundle savedInstanceState) {
45 | super.onCreate(savedInstanceState);
46 | setContentView(R.layout.activity_main);
47 | initView();
48 | initUI();
49 | mStickScrollView.setContentView(mLLStickList);
50 | mStickScrollView.setSuspensionView(mViewBottom);
51 |
52 | startActivity(new Intent(this,AndroidWidgetActivity.class));
53 | }
54 |
55 | private void initUI() {
56 |
57 | mTabFragmentAdapter = new TabFragmentAdapter(getSupportFragmentManager());
58 | mVp.setAdapter(mTabFragmentAdapter);
59 | mVp.addOnPageChangeListener(
60 | new TabLayout.TabLayoutOnPageChangeListener(mOrderManagerTabs));
61 | mVp.setOffscreenPageLimit(3);
62 | mOrderManagerTabs.setupWithViewPager(mVp);
63 | WebSettings webSettings = mWebview.getSettings();
64 | //设置WebView属性,能够执行Javascript脚本
65 | webSettings.setJavaScriptEnabled(true);
66 | mWebview.loadUrl("https://segmentfault.com/u/wellijhon_58622d2f61c2d");
67 |
68 | // Log.d(TAG, "initUI: " + (mLl.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS));
69 | }
70 |
71 | private void initView() {
72 | // mTvStickHeader = (TextView) findViewById(R.id.tv_stick_header);
73 | mOrderManagerTabs = (TabLayout) findViewById(R.id.order_manager_tabs);
74 | // mCsv = (ChildScrollView) findViewById(R.id.csv);
75 | mVp = (ViewPager) findViewById(R.id.vp);
76 | mLLStickList = (LinearLayout) findViewById(R.id.ll_stick_list);
77 |
78 | mWebview = (WebView) findViewById(R.id.webview);
79 | mButton = (Button) findViewById(R.id.button);
80 | mStickScrollView = (ScrollViewWithStickHeader) findViewById(R.id.stick_scroll_view);
81 | mLl = (LinearLayout) findViewById(R.id.ll);
82 | mViewBottom = (View) findViewById(R.id.tv_bottom);
83 | // mCrv = (ChildRecyclerView) findViewById(R.id.crv);
84 |
85 |
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/adapter/RVRightListAdapter.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview.adapter;
2 |
3 | import android.support.v7.widget.RecyclerView;
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 | import android.widget.Toast;
10 |
11 | import wellijohn.org.scrollviewwithstickview.R;
12 | import wellijohn.org.scrollviewwithstickview.constant.Constant;
13 |
14 | /**
15 | * @author: JiangWeiwei
16 | * @time: 2017/11/3-18:12
17 | * @email:
18 | * @desc:
19 | */
20 | public class RVRightListAdapter extends RecyclerView.Adapter {
21 |
22 |
23 |
24 |
25 |
26 | @Override
27 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
28 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_rightitem, parent, false);
29 | return new ViewHolder(view);
30 | }
31 |
32 | @Override
33 | public void onBindViewHolder(ViewHolder holder, int position) {
34 | holder.tv.setText(Constant.foods[position]);
35 | holder.iv.setImageResource(R.drawable.food);
36 | holder.itemView.setOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View v) {
39 | Toast.makeText(v.getContext(),"点击了",Toast.LENGTH_LONG).show();
40 | }
41 | });
42 | }
43 |
44 | @Override
45 | public int getItemCount() {
46 | return Constant.foods.length;
47 | }
48 |
49 | final class ViewHolder extends RecyclerView.ViewHolder {
50 |
51 | TextView tv;
52 | ImageView iv;
53 |
54 |
55 | public ViewHolder(View itemView) {
56 | super(itemView);
57 | tv = (TextView) itemView.findViewById(R.id.tv);
58 | iv = (ImageView) itemView.findViewById(R.id.iv);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/adapter/ReListAdapter.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview.adapter;
2 |
3 | import android.graphics.Color;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.TextView;
9 |
10 | import wellijohn.org.scrollviewwithstickview.R;
11 | import wellijohn.org.scrollviewwithstickview.listener.OnRVItemClickListener;
12 |
13 | /**
14 | * @author: JiangWeiwei
15 | * @time: 2017/11/3-18:12
16 | * @email:
17 | * @desc:
18 | */
19 | public class ReListAdapter extends RecyclerView.Adapter {
20 |
21 |
22 | private String[] foods = {"米饭", "招牌菜", "家常风味", "精美甜品", "饮料", "田园时蔬", "美食",
23 | "米饭", "招牌菜", "家常风味", "精美甜品", "饮料", "田园时蔬", "美食"};
24 |
25 | private OnRVItemClickListener onRVItemClickListener;
26 |
27 | private int selectIndex;
28 |
29 | @Override
30 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
31 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_item, parent, false);
32 | return new ViewHolder(view);
33 | }
34 |
35 | @Override
36 | public void onBindViewHolder(final ViewHolder holder, final int position) {
37 | holder.tv.setText(foods[position]);
38 | if (position == selectIndex) {
39 | holder.itemView.setBackgroundColor(Color.parseColor("#FFFFFF"));
40 | } else {
41 | holder.itemView.setBackgroundColor(Color.parseColor("#EEEEEE"));
42 | }
43 |
44 | holder.itemView.setOnClickListener(new View.OnClickListener() {
45 | @Override
46 | public void onClick(View v) {
47 | if (onRVItemClickListener != null)
48 | onRVItemClickListener.onClick(foods[holder.getAdapterPosition()],
49 | holder.getAdapterPosition());
50 | selectIndex = position;
51 | notifyDataSetChanged();
52 | }
53 | });
54 |
55 | }
56 |
57 | public void setOnRVItemClickListener(OnRVItemClickListener onRVItemClickListener) {
58 | this.onRVItemClickListener = onRVItemClickListener;
59 | }
60 |
61 | @Override
62 | public int getItemCount() {
63 | return foods.length;
64 | }
65 |
66 | public void setSelectIndex(int newLeftPos) {
67 | selectIndex = newLeftPos;
68 | notifyDataSetChanged();
69 | }
70 |
71 | final class ViewHolder extends RecyclerView.ViewHolder {
72 |
73 | TextView tv;
74 |
75 |
76 | public ViewHolder(View itemView) {
77 | super(itemView);
78 | tv = (TextView) itemView.findViewById(R.id.tv);
79 |
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/adapter/TabFragmentAdapter.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview.adapter;
2 |
3 | import android.support.annotation.Nullable;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v4.app.FragmentManager;
6 | import android.support.v4.app.FragmentPagerAdapter;
7 |
8 | import wellijohn.org.scrollviewwithstickview.fragment.RecyclerViewFragment;
9 |
10 | /**
11 | * @author: JiangWeiwei
12 | * @time: 2017/11/9-11:33
13 | * @email:
14 | * @desc:
15 | */
16 | public class TabFragmentAdapter extends FragmentPagerAdapter {
17 |
18 | public TabFragmentAdapter(FragmentManager fm) {
19 | super(fm);
20 | }
21 |
22 | @Override
23 | public Fragment getItem(int position) {
24 | // return ChildRecyclerViewFragment.newInstance(position);
25 | return RecyclerViewFragment.newInstance(position);
26 | }
27 |
28 | @Override
29 | public int getCount() {
30 | return 3;
31 | }
32 |
33 | @Nullable
34 | @Override
35 | public CharSequence getPageTitle(int position) {
36 | if (position == 0) {
37 | return "点餐";
38 | }
39 | if (position == 1) {
40 | return "评价";
41 | }
42 | if (position == 2) {
43 | return "商家";
44 | }
45 | return "tab" + position;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/constant/Constant.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview.constant;
2 |
3 | /**
4 | * @author: JiangWeiwei
5 | * @time: 2018/3/22-9:24
6 | * @email: jiangweiwei@qccr.com
7 | * @desc:
8 | */
9 | public class Constant {
10 |
11 | public static final String KEY_TAG = "KEY_TAG";
12 | public static final String[] foods = {"糖醋里脊1", "酸辣土豆丝2", "豆腐3", "上汤菠菜4", "红烧肉5"
13 | , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
14 | , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
15 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
16 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
17 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
18 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
19 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
20 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
21 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
22 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
23 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
24 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
25 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
26 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
27 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
28 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
29 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
30 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
31 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
32 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
33 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
34 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
35 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
36 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
37 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
38 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
39 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
40 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
41 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
42 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
43 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
44 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
45 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
46 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
47 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
48 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
49 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
50 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
51 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
52 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
53 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
54 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
55 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
56 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
57 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
58 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
59 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
60 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
61 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
62 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
63 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
64 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
65 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
66 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
67 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
68 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
69 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
70 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
71 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
72 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
73 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
74 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
75 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
76 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
77 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
78 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
79 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
80 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
81 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
82 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
83 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
84 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
85 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
86 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
87 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
88 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
89 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
90 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
91 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
92 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
93 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
94 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
95 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
96 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
97 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
98 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
99 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
100 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
101 | // , "茶树菇13", "干菜刀豆14", "开背虾15", "清炖牛肉16", "红烧鱼块17", "红烧肉18", "茶树菇19"
102 | // , "茶树菇6", "干菜刀豆7", "开背虾8", "清炖牛肉9", "红烧鱼块10", "红烧肉11", "茶树菇12"
103 | };
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/fragment/ChildRecyclerViewFragment.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview.fragment;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.Fragment;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.webkit.WebSettings;
14 |
15 | import wellijohn.org.scrollviewwithstickheader.ChildWebView;
16 | import wellijohn.org.scrollviewwithstickheader.layoutmanager.NoSlideLinearLayoutManager;
17 | import wellijohn.org.scrollviewwithstickview.MainActivity;
18 | import wellijohn.org.scrollviewwithstickview.R;
19 | import wellijohn.org.scrollviewwithstickview.adapter.RVRightListAdapter;
20 | import wellijohn.org.scrollviewwithstickview.adapter.ReListAdapter;
21 | import wellijohn.org.scrollviewwithstickview.listener.OnRVItemClickListener;
22 |
23 | /**
24 | * @author: JiangWeiwei
25 | * @time: 2017/11/9-11:34
26 | * @email:
27 | * @desc:
28 | */
29 | public class ChildRecyclerViewFragment extends LazyFragment {
30 | private static final String KEY_FRAGMENT_INT = "KEY_FRAGMENT_INT";
31 | private RecyclerView mChildRecyclerview;
32 | private RecyclerView mChildRecyclerviewRight;
33 | private ReListAdapter mReListAdapter;
34 | private NoSlideLinearLayoutManager mLlRight;
35 | private boolean move;
36 | private boolean mIsLeftTouch = true;
37 | private int mOldLeftIndex;
38 | private RecyclerViewListener mRecyclerViewListener;
39 | private MainActivity mParentActivity;
40 | private ChildWebView webview;
41 |
42 | @Override
43 | public void onAttach(Context context) {
44 | super.onAttach(context);
45 | if (context != null && context instanceof MainActivity) {
46 | mParentActivity = (MainActivity) context;
47 | }
48 | }
49 |
50 | @Nullable
51 | @Override
52 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
53 | View view = LayoutInflater.from(container.getContext()).inflate(R.layout.recyclerview, container, false);
54 | initView(view);
55 | return view;
56 | }
57 |
58 | @Override
59 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
60 | super.onViewCreated(view, savedInstanceState);
61 | // mChildRecyclerviewRight.post(new Runnable() {
62 | // @Override
63 | // public void run() {
64 | // ViewGroup.LayoutParams layoutParams = mChildRecyclerviewRight.getLayoutParams();
65 | // layoutParams.height = 1400;
66 | // mChildRecyclerviewRight.setLayoutParams(layoutParams);
67 | // }
68 | // });
69 |
70 | WebSettings settings = webview.getSettings();
71 | settings.setJavaScriptEnabled(true);
72 | webview.loadUrl("https://www.baidu.com/?tn=22073068_oem_dg");
73 | }
74 |
75 |
76 | private void initView(View view) {
77 | mChildRecyclerview = (RecyclerView) view.findViewById(R.id.child_recyclerview);
78 | mChildRecyclerviewRight = (RecyclerView) view.findViewById(R.id.child_recyclerview_right);
79 | webview = (ChildWebView) view.findViewById(R.id.webview);
80 | }
81 |
82 | public static Fragment newInstance(int position) {
83 | ChildRecyclerViewFragment fragment = new ChildRecyclerViewFragment();
84 | Bundle bundle = new Bundle();
85 | bundle.putInt(KEY_FRAGMENT_INT, position);
86 | fragment.setArguments(bundle);
87 | return fragment;
88 | }
89 |
90 |
91 | class RecyclerViewListener extends RecyclerView.OnScrollListener {
92 |
93 | private int mIndex;
94 |
95 |
96 | @Override
97 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
98 | super.onScrolled(recyclerView, dx, dy);
99 | if (!mIsLeftTouch) {
100 | leftLocation();
101 | }
102 | mIsLeftTouch = false;
103 | }
104 |
105 |
106 | public void setIndex(int index) {
107 | this.mIndex = index;
108 | }
109 |
110 |
111 | private void leftLocation() {
112 | int firstItem = mLlRight.findFirstVisibleItemPosition();
113 | int newRightPos = firstItem / 2;
114 | if (newRightPos != mOldLeftIndex) {
115 | mReListAdapter.setSelectIndex(newRightPos);
116 | mOldLeftIndex = newRightPos;
117 | }
118 | }
119 |
120 | }
121 |
122 | @Override
123 | void lazyFetchData() {
124 | initUI();
125 | }
126 |
127 | private void initUI() {
128 | mRecyclerViewListener = new RecyclerViewListener();
129 |
130 | mLlRight = new NoSlideLinearLayoutManager(getActivity());
131 |
132 | mReListAdapter = new ReListAdapter();
133 | LinearLayoutManager ll = new NoSlideLinearLayoutManager(getActivity());
134 | mChildRecyclerview.setLayoutManager(ll);
135 | mChildRecyclerview.setAdapter(mReListAdapter);
136 | mReListAdapter.setOnRVItemClickListener(new OnRVItemClickListener() {
137 | @Override
138 | public void onClick(String s, int index) {
139 | mIsLeftTouch = true;
140 | if (mOldLeftIndex != index) {
141 | int scrollIndex = index * 2;
142 | mRecyclerViewListener.setIndex(scrollIndex);
143 | mLlRight.scrollToPositionWithOffset(scrollIndex, 0);
144 | mOldLeftIndex = index;
145 | }
146 | }
147 | });
148 |
149 |
150 | mChildRecyclerviewRight.setLayoutManager(mLlRight);
151 | mChildRecyclerviewRight.setAdapter(new RVRightListAdapter());
152 | mChildRecyclerviewRight.addOnScrollListener(mRecyclerViewListener);
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/fragment/ChildScrollViewFragment.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview.fragment;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.Fragment;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.TextView;
12 | import android.widget.Toast;
13 |
14 | import wellijohn.org.scrollviewwithstickview.MainActivity;
15 | import wellijohn.org.scrollviewwithstickview.R;
16 | import wellijohn.org.scrollviewwithstickview.adapter.ReListAdapter;
17 |
18 | /**
19 | * @author: JiangWeiwei
20 | * @time: 2017/11/9-11:34
21 | * @email:
22 | * @desc:
23 | */
24 | public class ChildScrollViewFragment extends Fragment {
25 | private static final String KEY_FRAGMENT_INT = "KEY_FRAGMENT_INT";
26 | private ReListAdapter mReListAdapter;
27 | private boolean move;
28 | private boolean mIsLeftTouch = true;
29 | private int mOldLeftIndex;
30 | private MainActivity mParentActivity;
31 | private TextView mTvTitle;
32 |
33 | @Override
34 | public void onAttach(Context context) {
35 | super.onAttach(context);
36 | if (context != null && context instanceof MainActivity) {
37 | mParentActivity = (MainActivity) context;
38 | }
39 | }
40 |
41 | @Nullable
42 | @Override
43 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
44 | View view = LayoutInflater.from(container.getContext()).inflate(R.layout.demo_child_scroll, container, false);
45 | initView(view);
46 | mTvTitle.setOnClickListener(new View.OnClickListener() {
47 | @Override
48 | public void onClick(View v) {
49 | Toast.makeText(v.getContext(),"存在点击事件",Toast.LENGTH_LONG).show();
50 | }
51 | });
52 | return view;
53 | }
54 |
55 | @Override
56 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
57 | super.onViewCreated(view, savedInstanceState);
58 | }
59 |
60 |
61 | private void initView(View view) {
62 | mTvTitle = (TextView) view.findViewById(R.id.tv_title);
63 | }
64 |
65 | public static Fragment newInstance(int position) {
66 | ChildScrollViewFragment fragment = new ChildScrollViewFragment();
67 | Bundle bundle = new Bundle();
68 | bundle.putInt(KEY_FRAGMENT_INT, position);
69 | fragment.setArguments(bundle);
70 | return fragment;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/fragment/LazyFragment.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.view.View;
7 |
8 | /**
9 | * @author: JiangWeiwei
10 | * @time: 2018/3/15-12:24
11 | * @email: jiangweiwei@qccr.com
12 | * @desc:
13 | */
14 | public abstract class LazyFragment extends Fragment {
15 | boolean isViewPrepared; // 标识fragment视图已经初始化完毕
16 | boolean hasFetchData; // 标识已经触发过懒加载数据
17 |
18 |
19 | @Override
20 | public void setUserVisibleHint(boolean isVisibleToUser) {
21 | super.setUserVisibleHint(isVisibleToUser);
22 | if (isVisibleToUser) {//当当前为显示页面时
23 | lazyFetchDataIfPrepared();
24 | }
25 | }
26 |
27 | @Override
28 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
29 | super.onViewCreated(view, savedInstanceState);
30 | isViewPrepared = true;
31 | }
32 |
33 | @Override
34 | public void onActivityCreated(@Nullable Bundle savedInstanceState) {
35 | super.onActivityCreated(savedInstanceState);
36 | lazyFetchDataIfPrepared();
37 | }
38 |
39 | void lazyFetchDataIfPrepared() {
40 | // 用户可见fragment && 没有加载过数据 && 视图已经准备完毕
41 | if (getUserVisibleHint() && !hasFetchData && isViewPrepared) {
42 | hasFetchData = true; //已加载过数据
43 | lazyFetchData();
44 | }
45 | }
46 |
47 | abstract void lazyFetchData();
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/fragment/NoScrollWebView.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview.fragment;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.util.AttributeSet;
6 | import android.view.ViewGroup;
7 | import android.webkit.WebView;
8 |
9 | /**
10 | * @author: JiangWeiwei
11 | * @time: 2017/12/1-17:30
12 | * @email:
13 | * @desc:
14 | */
15 | public class NoScrollWebView extends WebView {
16 |
17 | @SuppressLint("NewApi")
18 | public NoScrollWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
19 | super(context, attrs, defStyleAttr, defStyleRes);
20 | }
21 |
22 | public NoScrollWebView(Context context, AttributeSet attrs, int defStyleAttr) {
23 | super(context, attrs, defStyleAttr);
24 |
25 | post(new Runnable() {
26 | @Override
27 | public void run() {
28 | // Log.d(TAG, "WebView的高度run: " + NoScrollWebView.this.getMeasuredHeight());
29 | ViewGroup.LayoutParams lp =NoScrollWebView.this.getLayoutParams();
30 | lp.height =3000;
31 | NoScrollWebView.this.setLayoutParams(lp);
32 | }
33 | });
34 | // setWebViewClient(new WebViewClient() {
35 | // @Override
36 | // public void onPageFinished(WebView view, String url) {
37 | // super.onPageFinished(view, url);
38 | // Log.d(TAG, "WebView的高度run: " + view.getContentHeight());
39 | // ViewGroup.LayoutParams lp =view.getLayoutParams();
40 | // lp.height = view.getContentHeight();
41 | // view.setLayoutParams(lp);
42 | // }
43 | // });
44 | }
45 |
46 | public NoScrollWebView(Context context, AttributeSet attrs) {
47 | this(context, attrs, 0);
48 | }
49 |
50 | public NoScrollWebView(Context context) {
51 | this(context, null);
52 | }
53 |
54 | @Override
55 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
56 | int mExpandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
57 | super.onMeasure(widthMeasureSpec, mExpandSpec);
58 | }
59 |
60 |
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/fragment/RecyclerViewFragment.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.NonNull;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 |
13 | import wellijohn.org.scrollviewwithstickview.R;
14 | import wellijohn.org.scrollviewwithstickview.adapter.RVRightListAdapter;
15 |
16 | /**
17 | * @author: JiangWeiwei
18 | * @time: 2018/8/2-10:36
19 | * @email: jiangweiwei@qccr.com
20 | * @desc:
21 | */
22 | public class RecyclerViewFragment extends LazyFragment {
23 | private static final String KEY_FRAGMENT_INT = "KEY_FRAGMENT_INT";
24 |
25 | private RecyclerView mRv;
26 | private RecyclerView mRvRight;
27 |
28 | @Nullable
29 | @Override
30 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
31 | View view = LayoutInflater.from(container.getContext()).inflate(R.layout.just_recyclerview, container, false);
32 | initView(view);
33 | return view;
34 | }
35 |
36 | @Override
37 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
38 | super.onViewCreated(view, savedInstanceState);
39 | mRv.setLayoutManager(new LinearLayoutManager(getActivity()));
40 | mRv.setAdapter(new RVRightListAdapter());
41 |
42 | mRvRight.setLayoutManager(new LinearLayoutManager(getActivity()));
43 | mRvRight.setAdapter(new RVRightListAdapter());
44 | }
45 |
46 | @Override
47 | void lazyFetchData() {
48 | // mRv.setLayoutManager(new LinearLayoutManager(getActivity()));
49 | // mRv.setAdapter(new RVRightListAdapter());
50 | }
51 |
52 |
53 | private void initView(View view) {
54 | mRv = view.findViewById(R.id.rv);
55 | mRvRight = view.findViewById(R.id.rv_right);
56 | }
57 |
58 | public static Fragment newInstance(int position) {
59 | RecyclerViewFragment fragment = new RecyclerViewFragment();
60 | Bundle bundle = new Bundle();
61 | bundle.putInt(KEY_FRAGMENT_INT, position);
62 | fragment.setArguments(bundle);
63 | return fragment;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/wellijohn/org/scrollviewwithstickview/listener/OnRVItemClickListener.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickview.listener;
2 |
3 | /**
4 | * @author: JiangWeiwei
5 | * @time: 2018/3/20-10:04
6 | * @email: jiangweiwei@qccr.com
7 | * @desc:
8 | */
9 | public interface OnRVItemClickListener {
10 | void onClick(T t, int index);
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/food.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/drawable-xxhdpi/food.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_border_gray_999_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_green_big_nomal_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_yellow_full_small_corner_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_android_widget.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
24 |
25 |
36 |
37 |
42 |
43 |
44 |
52 |
53 |
62 |
63 |
64 |
65 |
70 |
71 |
72 |
73 |
74 |
75 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
23 |
24 |
25 |
30 |
31 |
36 |
37 |
41 |
42 |
48 |
49 |
58 |
59 |
60 |
66 |
67 |
72 |
73 |
78 |
79 |
80 |
86 |
87 |
94 |
95 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
111 |
112 |
113 |
120 |
121 |
122 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
145 |
150 |
151 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main2.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/demo_child_scroll.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
18 |
19 |
20 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/just_recyclerview.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recyclerview.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
17 |
18 |
23 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
38 |
39 |
45 |
46 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_rightitem.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
16 |
17 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/title.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
16 |
17 |
22 |
23 |
27 |
28 |
34 |
35 |
44 |
45 |
46 |
52 |
53 |
58 |
59 |
64 |
65 |
66 |
72 |
73 |
80 |
81 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.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 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #33CC66
7 | #fab428
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 固定头部库
3 | 已经到中间位置了
4 | 开始位置
5 | 结束位置
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
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 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.2.1'
11 |
12 | //自动化maven打包插件
13 | //自动上传至Bintray平台插件
14 | classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3"
15 | // NOTE: Do not place your application dependencies here; they belong
16 | // in the individual module build.gradle files
17 |
18 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0' // Add this line
19 |
20 |
21 | }
22 | }
23 |
24 | allprojects {
25 | repositories {
26 | google()
27 | jcenter()
28 | maven { url 'https://jitpack.io' }
29 | }
30 | }
31 |
32 | task clean(type: Delete) {
33 | delete rootProject.buildDir
34 | }
35 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Nov 03 16:34:00 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-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 |
--------------------------------------------------------------------------------
/imgs/QR_code_258 .png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/imgs/QR_code_258 .png
--------------------------------------------------------------------------------
/imgs/scrollsnap.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/imgs/scrollsnap.gif
--------------------------------------------------------------------------------
/imgs/snapshot2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/imgs/snapshot2.gif
--------------------------------------------------------------------------------
/imgs/仿饿了么列表页.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WelliJohn/StickScrollView/8754f660aa4ad2ba5a4b8615dc1b3f34cb21c3bc/imgs/仿饿了么列表页.gif
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':stickscrollview'
2 |
--------------------------------------------------------------------------------
/stickscrollview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/stickscrollview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | group='com.github.WelliJohn'
5 | android {
6 | compileSdkVersion 27
7 |
8 | defaultConfig {
9 | minSdkVersion 14
10 | targetSdkVersion 25
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 | //apply from:'./jcenter.gradle'
27 |
28 | dependencies {
29 | implementation fileTree(include: ['*.jar'], dir: 'libs')
30 | implementation 'com.android.support:appcompat-v7:25.4.0'
31 | implementation 'com.android.support:recyclerview-v7:25.4.0'
32 | }
33 |
--------------------------------------------------------------------------------
/stickscrollview/jcenter.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.github.dcendents.android-maven'
2 | apply plugin: 'com.jfrog.bintray'
3 |
4 | tasks.withType(Javadoc) {
5 | options.addStringOption('Xdoclint:none', '-quiet')
6 | }
7 |
8 |
9 | version = "0.0.1"
10 |
11 |
12 | def siteUrl = 'https://github.com/WelliJohn/StickScrollView' // 项目的主页
13 | def gitUrl = 'https://github.com/WelliJohn/StickScrollView.git' // Git仓库的url
14 | group = "wellijohn.org" // 一般填你唯一的包名
15 | install {
16 | repositories.mavenInstaller {
17 | pom {
18 | project {
19 | packaging 'aar'
20 | //项目描述
21 | name 'ScrollViewWithStickview'
22 | url siteUrl
23 | // 开源协议
24 | licenses {
25 | license {
26 | name 'The Apache Software License, Version 2.0'
27 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
28 | }
29 | }
30 | developers {
31 | //填写的基本信息
32 | developer {
33 | id 'WelliJohn'
34 | name 'WelliJohn'
35 | email 'wellijohn1991@gmail.com'
36 | }
37 | }
38 | scm {
39 | connection gitUrl
40 | developerConnection gitUrl
41 | url siteUrl
42 | }
43 | }
44 | }
45 | }
46 | }
47 |
48 |
49 | // 注释掉不上传源码
50 | task sourcesJar(type: Jar) {
51 | from android.sourceSets.main.java.srcDirs
52 | classifier = 'sources'
53 | }
54 | task javadoc(type: Javadoc) {
55 | options.encoding = "utf-8"
56 | source = android.sourceSets.main.java.srcDirs
57 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
58 | }
59 | task javadocJar(type: Jar, dependsOn: javadoc) {
60 | classifier = 'javadoc'
61 | from javadoc.destinationDir
62 | }
63 | artifacts {
64 | archives javadocJar
65 | archives sourcesJar
66 | }
67 | Properties properties = new Properties()
68 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
69 | bintray {
70 | user = properties.getProperty("bintray.user")
71 | key = properties.getProperty("bintray.apikey")
72 | configurations = ['archives']
73 | pkg {
74 | repo = "ScrollViewWithStickview"
75 | name = "ScrollViewWithStickview" //发布到JCenter上的项目名字
76 | websiteUrl = siteUrl
77 | vcsUrl = gitUrl
78 | licenses = ["Apache-2.0"]
79 | publish = true
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/stickscrollview/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/java/wellijohn/org/scrollviewwithstickheader/ChildRecyclerView.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickheader;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.AttributeSet;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 |
10 | import wellijohn.org.scrollviewwithstickheader.layoutmanager.NoSlideLinearLayoutManager;
11 | import wellijohn.org.scrollviewwithstickheader.utils.ViewUtil;
12 |
13 | /**
14 | * @author: JiangWeiwei
15 | * @time: 2017/11/3-18:28
16 | * @email:
17 | * @desc:
18 | */
19 | public class ChildRecyclerView extends RecyclerView {
20 | private static final String TAG = "MyRecyclerView";
21 |
22 | private ScrollViewWithStickHeader mScrollViewWithStickHeader;
23 |
24 | public ChildRecyclerView(Context context) {
25 | this(context, null, 0);
26 | }
27 |
28 | public ChildRecyclerView(Context context, @Nullable AttributeSet attrs) {
29 | this(context, attrs, 0);
30 | }
31 |
32 | public ChildRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
33 | super(context, attrs, defStyle);
34 | setFocusableInTouchMode(false);
35 | post(new Runnable() {
36 | @Override
37 | public void run() {
38 | View tempView = ChildRecyclerView.this;
39 | while (!(tempView.getParent() instanceof ScrollViewWithStickHeader)) {
40 | tempView = (View) tempView.getParent();
41 | }
42 | mScrollViewWithStickHeader = (ScrollViewWithStickHeader) tempView.getParent();
43 | }
44 | });
45 | }
46 |
47 |
48 | float downY = 0;
49 |
50 | @Override
51 | public boolean dispatchTouchEvent(MotionEvent ev) {
52 | int action = ev.getAction();
53 | boolean isRVScroll =
54 | mScrollViewWithStickHeader.isBottom() || (!mScrollViewWithStickHeader.isBottom() &&
55 | !ViewUtil.isScrolledToTop(this));
56 | if (action == MotionEvent.ACTION_DOWN) {
57 | downY = ev.getY();
58 | LayoutManager layoutManager = getLayoutManager();
59 | if (layoutManager instanceof NoSlideLinearLayoutManager) {
60 | ((NoSlideLinearLayoutManager) layoutManager).setCanVerScroll(isRVScroll);
61 | }
62 | }
63 | return super.dispatchTouchEvent(ev);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/java/wellijohn/org/scrollviewwithstickheader/ChildScrollView.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickheader;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.Nullable;
5 | import android.util.AttributeSet;
6 | import android.util.Log;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 | import android.view.ViewConfiguration;
10 | import android.widget.ScrollView;
11 |
12 | /**
13 | * @author: JiangWeiwei
14 | * @time: 2017/11/3-18:28
15 | * @email:
16 | * @desc:
17 | */
18 | public class ChildScrollView extends ScrollView {
19 |
20 | private static final String TAG = "MyRecyclerView";
21 |
22 | private float mLastY = 0;
23 |
24 | private boolean isScrolledToTop = true;
25 | private boolean isScrolledToBottom = false;
26 |
27 | private ScrollViewWithStickHeader mScrollViewWithStickHeader;
28 |
29 | private int minSlop;
30 | private int minPageSlop;
31 |
32 | private float mLastX;
33 |
34 | private boolean mIsDraging;
35 |
36 | public ChildScrollView(Context context) {
37 | this(context, null, 0);
38 | }
39 |
40 | public ChildScrollView(Context context, @Nullable AttributeSet attrs) {
41 | this(context, attrs, 0);
42 | }
43 |
44 | public ChildScrollView(Context context, @Nullable AttributeSet attrs, int defStyle) {
45 | super(context, attrs, defStyle);
46 | setFocusableInTouchMode(false);
47 | post(new Runnable() {
48 | @Override
49 | public void run() {
50 | View tempView = ChildScrollView.this;
51 | while (!(tempView.getParent() instanceof ScrollViewWithStickHeader)) {
52 | tempView = (View) tempView.getParent();
53 | }
54 | mScrollViewWithStickHeader = (ScrollViewWithStickHeader) tempView.getParent();
55 | }
56 | });
57 | minSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
58 | minPageSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
59 | }
60 |
61 | @Override
62 | protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
63 | super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
64 | if (scrollY == 0) {
65 | isScrolledToTop = clampedY;
66 | isScrolledToBottom = false;
67 | } else {
68 | isScrolledToTop = false;
69 | isScrolledToBottom = clampedY;
70 | }
71 | }
72 |
73 | @Override
74 | protected void onScrollChanged(int l, int t, int oldl, int oldt) {
75 | super.onScrollChanged(l, t, oldl, oldt);
76 | if (getScrollY() == 0) {
77 | isScrolledToTop = true;
78 | isScrolledToBottom = false;
79 | } else if (getScrollY() + getHeight() - getPaddingTop() - getPaddingBottom() == getChildAt(0).getHeight()) {
80 | isScrolledToBottom = true;
81 | isScrolledToTop = false;
82 | } else {
83 | isScrolledToTop = false;
84 | isScrolledToBottom = false;
85 | }
86 | }
87 |
88 | float downY;
89 |
90 |
91 | @Override
92 | public boolean dispatchTouchEvent(MotionEvent event) {
93 | if (mScrollViewWithStickHeader == null) {
94 | return super.onTouchEvent(event);
95 | }
96 | int action = event.getAction();
97 |
98 | if (action == MotionEvent.ACTION_DOWN) {
99 | Log.d(Constant.KEY_TAG, "dispatchTouchEvent: ACTION_DOWN");
100 | mLastX = event.getX();
101 | mLastY = event.getY();
102 | //首先判断外层ScrollView是否滑动到底部
103 | if (mScrollViewWithStickHeader.isBottom()) {
104 | getParent().requestDisallowInterceptTouchEvent(true);
105 | return super.dispatchTouchEvent(event);
106 | } /*else {
107 | //拦截事件 本身不处理
108 | getParent().requestDisallowInterceptTouchEvent(false);
109 | return false;
110 | }*/
111 | return super.dispatchTouchEvent(event);
112 | }
113 | if (action == MotionEvent.ACTION_MOVE) {
114 | Log.d(Constant.KEY_TAG, "dispatchTouchEvent: ACTION_MOVE");
115 | float nowY = event.getY();
116 | if (!mScrollViewWithStickHeader.isBottom() && !isScrolledToTop && nowY - mLastY > 0) {
117 | if (Math.abs(event.getX() - mLastX) < minPageSlop) {
118 | getParent().requestDisallowInterceptTouchEvent(true);
119 | return super.dispatchTouchEvent(event);
120 | } else {
121 | getParent().requestDisallowInterceptTouchEvent(true);
122 | return false;
123 | }
124 | } else if (mScrollViewWithStickHeader.isBottom() && !isScrolledToBottom && nowY - mLastY < 0) {
125 | if (Math.abs(event.getX() - mLastX) < minPageSlop) {
126 | getParent().requestDisallowInterceptTouchEvent(true);
127 | return super.dispatchTouchEvent(event);
128 | } else {
129 | getParent().requestDisallowInterceptTouchEvent(true);
130 | return false;
131 | }
132 | } else if (mScrollViewWithStickHeader.isBottom() && !isScrolledToTop && nowY - mLastY > 0) {
133 | if (Math.abs(event.getX() - mLastX) < minPageSlop) {
134 | getParent().requestDisallowInterceptTouchEvent(true);
135 | return super.dispatchTouchEvent(event);
136 | } else {
137 | getParent().requestDisallowInterceptTouchEvent(true);
138 | return false;
139 | }
140 | } else {
141 | getParent().requestDisallowInterceptTouchEvent(false);
142 | }
143 | }
144 |
145 | if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
146 | Log.d(Constant.KEY_TAG, "dispatchTouchEvent: ACTION_UP/ACTION_CANCEL");
147 | getParent().requestDisallowInterceptTouchEvent(false);
148 | }
149 | return super.dispatchTouchEvent(event);
150 | }
151 |
152 | @Override
153 | public boolean onInterceptTouchEvent(MotionEvent ev) {
154 | int action = ev.getAction();
155 | if ((action == MotionEvent.ACTION_MOVE) && (mIsDraging)) {
156 | return true;
157 | }
158 |
159 | if (super.onInterceptTouchEvent(ev)) {
160 | return true;
161 | }
162 | switch (action & MotionEvent.ACTION_MASK) {
163 | case MotionEvent.ACTION_DOWN:
164 | mIsDraging = false;
165 | downY = ev.getY();
166 | break;
167 | case MotionEvent.ACTION_MOVE:
168 | float moveY = ev.getY();
169 | if (Math.abs(moveY - downY) > minSlop) {
170 | requestDisallowInterceptTouchEvent(true);
171 | mIsDraging = true;
172 | }
173 | break;
174 | case MotionEvent.ACTION_UP:
175 | case MotionEvent.ACTION_CANCEL:
176 | mIsDraging = false;
177 | break;
178 |
179 | }
180 | return mIsDraging;
181 | }
182 |
183 | @Override
184 | public boolean onTouchEvent(MotionEvent event) {
185 | // Log.d(Constant.KEY_TAG, "onTouchEvent: ");
186 | // if (mScrollViewWithStickHeader == null) return super.onTouchEvent(event);
187 | // int action = event.getAction();
188 | //
189 | // if (action == MotionEvent.ACTION_DOWN) {
190 | // mLastX = event.getX();
191 | // mLastY = event.getY();
192 | // //首先判断外层ScrollView是否滑动到底部
193 | // if (mScrollViewWithStickHeader.isBottom()) {
194 | // getParent().requestDisallowInterceptTouchEvent(true);
195 | // return super.onTouchEvent(event);
196 | // } else {
197 | // //拦截事件 本身不处理
198 | // getParent().requestDisallowInterceptTouchEvent(false);
199 | // return false;
200 | // }
201 | // }
202 | // if (action == MotionEvent.ACTION_MOVE) {
203 | // float nowY = event.getY();
204 | // if (!mScrollViewWithStickHeader.isBottom() && !isScrolledToTop && nowY - mLastY > 0) {
205 | // if (Math.abs(event.getX() - mLastX) < minPageSlop) {
206 | // getParent().requestDisallowInterceptTouchEvent(true);
207 | // return super.onTouchEvent(event);
208 | // } else {
209 | // getParent().requestDisallowInterceptTouchEvent(true);
210 | // return false;
211 | // }
212 | // } else if (mScrollViewWithStickHeader.isBottom() && !isScrolledToBottom && nowY - mLastY < 0) {
213 | // if (Math.abs(event.getX() - mLastX) < minPageSlop) {
214 | // getParent().requestDisallowInterceptTouchEvent(true);
215 | // return super.onTouchEvent(event);
216 | // } else {
217 | // getParent().requestDisallowInterceptTouchEvent(true);
218 | // return false;
219 | // }
220 | // } else if (mScrollViewWithStickHeader.isBottom() && !isScrolledToTop && nowY - mLastY > 0) {
221 | // if (Math.abs(event.getX() - mLastX) < minPageSlop) {
222 | // getParent().requestDisallowInterceptTouchEvent(true);
223 | // return super.onTouchEvent(event);
224 | // } else {
225 | // getParent().requestDisallowInterceptTouchEvent(true);
226 | // return false;
227 | // }
228 | // } else {
229 | // getParent().requestDisallowInterceptTouchEvent(false);
230 | // }
231 | // }
232 | //
233 | // if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
234 | // getParent().requestDisallowInterceptTouchEvent(false);
235 | // }
236 |
237 | return super.onTouchEvent(event);
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/java/wellijohn/org/scrollviewwithstickheader/ChildWebView.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickheader;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.Nullable;
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 | import android.view.View;
8 | import android.view.ViewConfiguration;
9 | import android.webkit.WebView;
10 |
11 | /**
12 | * @author: JiangWeiwei
13 | * @time: 2017/11/3-18:28
14 | * @email:
15 | * @desc:
16 | */
17 | public class ChildWebView extends WebView {
18 |
19 | private static final String TAG = "MyRecyclerView";
20 |
21 | private float mLastY = 0;
22 |
23 | private boolean isScrolledToTop = true;
24 | private boolean isScrolledToBottom = false;
25 |
26 | private ScrollViewWithStickHeader mScrollViewWithStickHeader;
27 |
28 | private static int minPageSlop;
29 |
30 | private float mLastX;
31 |
32 | public ChildWebView(Context context) {
33 | this(context, null, 0);
34 | }
35 |
36 | public ChildWebView(Context context, @Nullable AttributeSet attrs) {
37 | this(context, attrs, 0);
38 | }
39 |
40 | public ChildWebView(Context context, @Nullable AttributeSet attrs, int defStyle) {
41 | super(context, attrs, defStyle);
42 | setFocusableInTouchMode(false);
43 | post(new Runnable() {
44 | @Override
45 | public void run() {
46 | View tempView = ChildWebView.this;
47 | while (!(tempView.getParent() instanceof ScrollViewWithStickHeader)) {
48 | tempView = (View) tempView.getParent();
49 | }
50 | mScrollViewWithStickHeader = (ScrollViewWithStickHeader) tempView.getParent();
51 | }
52 | });
53 | minPageSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
54 | }
55 |
56 | @Override
57 | protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
58 | super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
59 | if (scrollY == 0) {
60 | isScrolledToTop = clampedY;
61 | isScrolledToBottom = false;
62 | } else {
63 | isScrolledToTop = false;
64 | isScrolledToBottom = clampedY;
65 | }
66 | }
67 | //
68 | // @Override
69 | // protected void onScrollChanged(int l, int t, int oldl, int oldt) {
70 | // super.onScrollChanged(l, t, oldl, oldt);
71 | // if (getScrollY() == 0) {
72 | // isScrolledToTop = true;
73 | // isScrolledToBottom = false;
74 | // } else if (getScrollY() + getHeight() - getPaddingTop() - getPaddingBottom() == getChildAt(0).getHeight()) {
75 | // isScrolledToBottom = true;
76 | // isScrolledToTop = false;
77 | // } else {
78 | // isScrolledToTop = false;
79 | // isScrolledToBottom = false;
80 | // }
81 | // }
82 |
83 |
84 | @Override
85 | public boolean onTouchEvent(MotionEvent event) {
86 | if (mScrollViewWithStickHeader == null) return super.onTouchEvent(event);
87 | int action = event.getAction();
88 |
89 | if (action == MotionEvent.ACTION_DOWN) {
90 | mLastX = event.getX();
91 | mLastY = event.getY();
92 | //首先判断外层ScrollView是否滑动到底部
93 | if (mScrollViewWithStickHeader.isBottom()) {
94 | getParent().requestDisallowInterceptTouchEvent(true);
95 | return super.onTouchEvent(event);
96 | } else {
97 | //拦截事件 本身不处理
98 | getParent().requestDisallowInterceptTouchEvent(false);
99 | return false;
100 | }
101 | }
102 | if (action == MotionEvent.ACTION_MOVE) {
103 | float nowY = event.getY();
104 | if (!mScrollViewWithStickHeader.isBottom() && !isScrolledToTop && nowY - mLastY > 0) {
105 | if (Math.abs(event.getX() - mLastX) < minPageSlop) {
106 | getParent().requestDisallowInterceptTouchEvent(false);
107 | return super.onTouchEvent(event);
108 | } else {
109 | getParent().requestDisallowInterceptTouchEvent(false);
110 | return false;
111 | }
112 | } else if (mScrollViewWithStickHeader.isBottom() && !isScrolledToBottom && nowY - mLastY < 0) {
113 | if (Math.abs(event.getX() - mLastX) < minPageSlop) {
114 | getParent().requestDisallowInterceptTouchEvent(true);
115 | return super.onTouchEvent(event);
116 | } else {
117 | getParent().requestDisallowInterceptTouchEvent(true);
118 | return false;
119 | }
120 | } else if (mScrollViewWithStickHeader.isBottom() && !isScrolledToTop && nowY - mLastY > 0) {
121 | if (Math.abs(event.getX() - mLastX) < minPageSlop) {
122 | getParent().requestDisallowInterceptTouchEvent(true);
123 | return super.onTouchEvent(event);
124 | } else {
125 | getParent().requestDisallowInterceptTouchEvent(true);
126 | return false;
127 | }
128 | } else {
129 | getParent().requestDisallowInterceptTouchEvent(false);
130 | }
131 | }
132 |
133 | if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
134 | getParent().requestDisallowInterceptTouchEvent(false);
135 | }
136 |
137 | return super.onTouchEvent(event);
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/java/wellijohn/org/scrollviewwithstickheader/Constant.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickheader;
2 |
3 | /**
4 | * @author: JiangWeiwei
5 | * @time: 2018/6/5-10:13
6 | * @email: jiangweiwei@qccr.com
7 | * @desc:
8 | */
9 | class Constant {
10 | public static final String KEY_TAG = "KEY_TAG";
11 | }
12 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/java/wellijohn/org/scrollviewwithstickheader/ScrollViewWithStickHeader.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickheader;
2 |
3 | import android.animation.ObjectAnimator;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Rect;
7 | import android.support.v4.view.ViewPager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.util.AttributeSet;
10 | import android.view.MotionEvent;
11 | import android.view.View;
12 | import android.view.ViewConfiguration;
13 | import android.view.ViewGroup;
14 | import android.webkit.WebView;
15 | import android.widget.ScrollView;
16 |
17 | import java.util.ArrayList;
18 | import java.util.Arrays;
19 |
20 | import wellijohn.org.scrollviewwithstickheader.utils.UIUtil;
21 | import wellijohn.org.scrollviewwithstickheader.utils.ViewUtil;
22 |
23 | /**
24 | * @author: JiangWeiwei
25 | * @time: 2017/11/3-16:57
26 | * @email:
27 | * @desc:
28 | */
29 | public class ScrollViewWithStickHeader extends ScrollView {
30 |
31 | private int minPageSlop;
32 | private int minSlop;
33 | private boolean isChildToBottom;
34 |
35 | private View mAutoFillView;
36 |
37 | private Runnable scrollerTask;
38 |
39 |
40 | private static final String TAG = "StickViewScrollView";
41 |
42 | private boolean mIsAutoScrollChild;
43 |
44 | private boolean mIsNeedAutoScroll;
45 |
46 | private int initialPosition;
47 | private int newCheck = 50;
48 | private boolean mIsVisible;
49 |
50 | private Rect rect = new Rect();
51 | private ArrayList mSuspensionViews = new ArrayList<>();
52 |
53 | private ArrayList mListViews = new ArrayList<>();
54 | private ArrayList mScrollViews = new ArrayList<>();
55 |
56 |
57 | public ScrollViewWithStickHeader(Context context) {
58 | this(context, null);
59 | }
60 |
61 | public ScrollViewWithStickHeader(Context context, AttributeSet attrs) {
62 | this(context, attrs, 0);
63 | }
64 |
65 | public ScrollViewWithStickHeader(final Context context, AttributeSet attrs, int defStyleAttr) {
66 | super(context, attrs, defStyleAttr);
67 | minPageSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
68 | minSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
69 | TypedArray ta = context.getResources().obtainAttributes(attrs, R.styleable.ScrollViewWithStickHeader);
70 | mIsNeedAutoScroll = ta.getBoolean(R.styleable.ScrollViewWithStickHeader_autoscroll, false);
71 | ta.recycle();
72 |
73 | scrollerTask = new Runnable() {
74 |
75 | public void run() {
76 | if (mAutoFillView == null) return;
77 | int newPosition = getScrollY();
78 | if (initialPosition - newPosition == 0) {//has stopped
79 | if (!mIsVisible) return;
80 |
81 | if (mIsAutoScrollChild) {
82 | ObjectAnimator.ofInt(ScrollViewWithStickHeader.this, "scrollY",
83 | getChildAt(0).getHeight() - mAutoFillView.getHeight()).setDuration(100).start();
84 | } else {
85 | ObjectAnimator.ofInt(ScrollViewWithStickHeader.this, "scrollY",
86 | (getChildAt(0).getHeight() - mAutoFillView.getHeight() * 2)).setDuration(100).setDuration(200).start();
87 |
88 | }
89 | } else {
90 | initialPosition = getScrollY();
91 | ScrollViewWithStickHeader.this.postDelayed(scrollerTask, newCheck);
92 | }
93 | }
94 | };
95 |
96 |
97 | post(new Runnable() {
98 | @Override
99 | public void run() {
100 | checkNotNull();
101 | ViewGroup.LayoutParams lp = mAutoFillView.getLayoutParams();
102 | int[] stickViewScrollViewCoor = new int[2];
103 | ScrollViewWithStickHeader.this.getLocationOnScreen(stickViewScrollViewCoor);
104 |
105 | int contentHeight = UIUtil.getScreenHeight(getContext()) - stickViewScrollViewCoor[1];
106 | lp.height = contentHeight;
107 | mAutoFillView.setLayoutParams(lp);
108 |
109 | int[] viewPageCoor = new int[2];
110 | int[] autoFillCoor = new int[2];
111 | View tempViewPager = getView();
112 |
113 | tempViewPager.getLocationOnScreen(viewPageCoor);
114 | mAutoFillView.getLocationOnScreen(autoFillCoor);
115 | int tempStickHeight = viewPageCoor[1] - autoFillCoor[1];
116 |
117 | int vpHeight = contentHeight - tempStickHeight - getSuspensionHeight();
118 | ViewGroup.LayoutParams vpLp = tempViewPager.getLayoutParams();
119 | vpLp.height = vpHeight;
120 | tempViewPager.setLayoutParams(vpLp);
121 |
122 | ViewUtil.findChildViews(mListViews, ScrollViewWithStickHeader.this, RecyclerView.class);
123 | ViewUtil.findChildViews(mScrollViews, ScrollViewWithStickHeader.this, ChildScrollView.class);
124 |
125 | }
126 | });
127 | }
128 |
129 |
130 | private void checkNotNull() {
131 | if (mAutoFillView == null)
132 | throw new IllegalStateException("StickView can not be null,Please check you have set");
133 | }
134 |
135 | private View getView() {
136 | View tempViewPager = ViewUtil.findChildView(ScrollViewWithStickHeader.this, ViewPager.class);
137 |
138 | if (tempViewPager == null) {
139 | tempViewPager = ViewUtil.findChildView(ScrollViewWithStickHeader.this, RecyclerView.class);
140 | }
141 |
142 | if (tempViewPager == null) {
143 | tempViewPager = ViewUtil.findChildView(ScrollViewWithStickHeader.this, ScrollView.class);
144 | }
145 |
146 | if (tempViewPager == null) {
147 | tempViewPager = ViewUtil.findChildView(ScrollViewWithStickHeader.this, WebView.class);
148 | }
149 |
150 | if (tempViewPager == null)
151 | throw new IllegalStateException("ScrollViewWithStickHeader must" +
152 | "use with ViewPager||ChildScrollView||RecyclerView||ChildWebView");
153 | return tempViewPager;
154 | }
155 |
156 |
157 | private void startScrollerTask() {
158 | initialPosition = getScrollY();
159 | ScrollViewWithStickHeader.this.postDelayed(scrollerTask, newCheck);
160 | }
161 |
162 |
163 | public boolean isBottom() {
164 | return isChildToBottom;
165 | }
166 |
167 |
168 | @Override
169 | protected void onScrollChanged(int l, int t, int oldl, int oldt) {
170 | super.onScrollChanged(l, t, oldl, oldt);
171 | if (mAutoFillView == null) return;
172 | isChildToBottom = t + getHeight() >= getChildAt(0).getMeasuredHeight();
173 | mIsVisible = mAutoFillView.getGlobalVisibleRect(rect);
174 | if (mIsVisible) {
175 | mIsAutoScrollChild = rect.height() > (mAutoFillView.getHeight() / 3);
176 | }
177 | }
178 |
179 |
180 | @Override
181 | public boolean onTouchEvent(MotionEvent ev) {
182 | int action = ev.getAction();
183 | switch (action) {
184 | case MotionEvent.ACTION_UP:
185 | if (mIsNeedAutoScroll)
186 | startScrollerTask();
187 | break;
188 | }
189 | return super.onTouchEvent(ev);
190 |
191 | }
192 |
193 |
194 | float downY = 0;
195 | float downX = 0;
196 |
197 | @Override
198 | public boolean onInterceptTouchEvent(MotionEvent ev) {
199 | RecyclerView childRecyclerView = getRV(ev);
200 | ChildScrollView childScrollView = getSV(ev);
201 | int action = ev.getAction();
202 | switch (action) {
203 | case MotionEvent.ACTION_DOWN:
204 | downY = ev.getY();
205 | downX = ev.getX();
206 | break;
207 | }
208 | if (childRecyclerView != null) {
209 | switch (action) {
210 | case MotionEvent.ACTION_MOVE:
211 | if (isBottom()) {
212 | return !(ev.getY() - downY < 0) && ViewUtil.isScrolledToTop(childRecyclerView);
213 | }
214 | break;
215 | }
216 | }
217 | // if (childScrollView != null) {
218 | // switch (action) {
219 | // case MotionEvent.ACTION_MOVE:
220 | // if (isBottom()) {
221 | // return !(ev.getY() - downY < 0) && ViewUtil.isScrolledToTop(childScrollView);
222 | // }
223 | // }
224 | // }
225 |
226 | return super.onInterceptTouchEvent(ev);
227 | }
228 |
229 | private RecyclerView getRV(MotionEvent ev) {
230 | for (RecyclerView childRecyclerView : mListViews) {
231 | if (UIUtil.inRangeOfView(childRecyclerView, ev)) return childRecyclerView;
232 | }
233 | return null;
234 | }
235 |
236 | private ChildScrollView getSV(MotionEvent ev) {
237 | for (ChildScrollView childScrollView : mScrollViews) {
238 | if (UIUtil.inRangeOfView(childScrollView, ev)) return childScrollView;
239 | }
240 | return null;
241 | }
242 |
243 |
244 | public int getSuspensionHeight() {
245 | int height = 0;
246 | for (View view : mSuspensionViews) {
247 | height += view.getHeight();
248 | }
249 | return height;
250 | }
251 |
252 | public void setContentView(View paramAutoFillView) {
253 | this.mAutoFillView = paramAutoFillView;
254 | }
255 |
256 | public void setSuspensionView(View... paramView) {
257 | mSuspensionViews.addAll(Arrays.asList(paramView));
258 | }
259 |
260 | }
261 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/java/wellijohn/org/scrollviewwithstickheader/layoutmanager/NoSlideGridLayoutManager.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickheader.layoutmanager;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.GridLayoutManager;
5 | import android.util.AttributeSet;
6 |
7 | /**
8 | * @author: JiangWeiwei
9 | * @time: 2018/4/2-11:05
10 | * @email: jiangweiwei@qccr.com
11 | * @desc:
12 | */
13 | public class NoSlideGridLayoutManager extends GridLayoutManager {
14 | private boolean isCanVerScroll;
15 |
16 | public NoSlideGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
17 | super(context, attrs, defStyleAttr, defStyleRes);
18 | }
19 |
20 | public NoSlideGridLayoutManager(Context context, int spanCount) {
21 | super(context, spanCount);
22 | }
23 |
24 | public NoSlideGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
25 | super(context, spanCount, orientation, reverseLayout);
26 | }
27 |
28 | public void setCanVerScroll(boolean canVerScroll) {
29 | isCanVerScroll = canVerScroll;
30 | }
31 |
32 | @Override
33 | public boolean canScrollVertically() {
34 | return isCanVerScroll && super.canScrollVertically();
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/java/wellijohn/org/scrollviewwithstickheader/layoutmanager/NoSlideLinearLayoutManager.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickheader.layoutmanager;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.LinearLayoutManager;
5 |
6 | /**
7 | * @author: JiangWeiwei
8 | * @time: 2018/4/2-10:56
9 | * @email: jiangweiwei@qccr.com
10 | * @desc:
11 | */
12 | public class NoSlideLinearLayoutManager extends LinearLayoutManager {
13 |
14 | private boolean isCanVerScroll = true;
15 |
16 | public NoSlideLinearLayoutManager(Context context) {
17 | super(context);
18 | }
19 |
20 |
21 | public void setCanVerScroll(boolean canVerScroll) {
22 | isCanVerScroll = canVerScroll;
23 | }
24 |
25 | @Override
26 | public boolean canScrollVertically() {
27 | return isCanVerScroll && super.canScrollVertically();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/java/wellijohn/org/scrollviewwithstickheader/utils/UIUtil.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickheader.utils;
2 |
3 | import android.content.Context;
4 | import android.util.DisplayMetrics;
5 | import android.view.MotionEvent;
6 | import android.view.View;
7 | import android.view.WindowManager;
8 |
9 | /**
10 | * @author: JiangWeiwei
11 | * @time: 2017/11/7-11:51
12 | * @email:
13 | * @desc:
14 | */
15 | public class UIUtil {
16 | public static int getScreenHeight(Context context) {
17 | DisplayMetrics dm = new DisplayMetrics();
18 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
19 | wm.getDefaultDisplay().getMetrics(dm);
20 | return dm.heightPixels;
21 | }
22 |
23 |
24 | public static int getStatusBarHeight(Context context) {
25 | int result = 0;
26 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
27 | if (resourceId > 0) {
28 | result = context.getResources().getDimensionPixelSize(resourceId);
29 | }
30 | return result;
31 | }
32 |
33 | /**
34 | * 点击的位置是否在view中
35 | *
36 | * @param view
37 | * @param ev
38 | * @return
39 | */
40 | public static boolean inRangeOfView(View view, MotionEvent ev) {
41 | int[] location = new int[2];
42 | view.getLocationOnScreen(location);
43 | int x = location[0];
44 | int y = location[1];
45 | if (ev.getX() < x || ev.getRawX() > (x + view.getWidth()) || ev.getRawY() < y
46 | || ev.getRawY() > (y + view.getHeight())) {
47 | return false;
48 | }
49 | return true;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/java/wellijohn/org/scrollviewwithstickheader/utils/ViewUtil.java:
--------------------------------------------------------------------------------
1 | package wellijohn.org.scrollviewwithstickheader.utils;
2 |
3 | import android.support.v7.widget.LinearLayoutManager;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ScrollView;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * @author: JiangWeiwei
13 | * @time: 2018/5/19-10:21
14 | * @email: jiangweiwei@qccr.com
15 | * @desc:
16 | */
17 | public class ViewUtil {
18 | public static T findChildView(View paramView, Class t) {
19 | View childView;
20 | if (paramView instanceof ViewGroup) {
21 | ViewGroup tempVg = (ViewGroup) paramView;
22 | int count = tempVg.getChildCount();
23 | for (int index = 0; index < count; index++) {
24 | View tempView = tempVg.getChildAt(index);
25 | if (t.isInstance(tempView)) {
26 | childView = tempView;
27 | return (T) childView;
28 | } else if (tempView instanceof ViewGroup) {
29 | View view = findChildView(tempView, t);
30 | if (view != null) {
31 | return (T) view;
32 | }
33 | }
34 | }
35 | }
36 | return null;
37 | }
38 |
39 |
40 | public static List findChildViews(List views, View paramView, Class t) {
41 | if (paramView instanceof ViewGroup) {
42 | ViewGroup tempVg = (ViewGroup) paramView;
43 | int count = tempVg.getChildCount();
44 | for (int index = 0; index < count; index++) {
45 | View tempView = tempVg.getChildAt(index);
46 | if (t.isInstance(tempView)) {
47 | views.add((T) tempView);
48 | } else if (tempView instanceof ViewGroup) {
49 | findChildViews(views, tempView, t);
50 | }
51 | }
52 | }
53 | return views;
54 | }
55 |
56 | public static boolean isScrolledToTop(RecyclerView rv) {
57 | return rv.getLayoutManager() instanceof LinearLayoutManager &&
58 | ((LinearLayoutManager) (rv.getLayoutManager())).findFirstCompletelyVisibleItemPosition() == 0;
59 |
60 | }
61 |
62 | public static boolean isScrolledToTop(ScrollView scrollView) {
63 | return scrollView.getScrollY() == 0;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/stickscrollview/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | StickScrollView
3 |
4 |
--------------------------------------------------------------------------------