├── .gitignore
├── LICENSE
├── README-ZH.md
├── README.md
├── apk
└── app-debug.apk
├── app
├── .gitignore
├── android.jks
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── ckr
│ │ └── pagesnaphelper
│ │ ├── MainActivity.java
│ │ ├── adapter
│ │ ├── MainAdapter.java
│ │ └── MyFragmentPagerAdapter.java
│ │ ├── model
│ │ └── Item.java
│ │ ├── view
│ │ ├── BaseFragment.java
│ │ ├── MainFragment.java
│ │ └── PageFragment.java
│ │ └── widget
│ │ └── MyViewPager.java
│ └── res
│ ├── drawable
│ ├── bg_color1.xml
│ ├── bg_color2.xml
│ ├── bg_color3.xml
│ ├── bg_color4.xml
│ ├── bg_color5.xml
│ ├── bg_color6.xml
│ ├── bg_delete.xml
│ ├── bg_tablayout.xml
│ ├── bg_textview.xml
│ ├── shape_point_selected.xml
│ └── shape_point_unselected.xml
│ ├── layout-land
│ ├── item_horizontal_grid.xml
│ └── item_horizontal_grid2.xml
│ ├── layout
│ ├── activity_main.xml
│ ├── fragment_horizontal_grid.xml
│ ├── fragment_horizontal_grid2.xml
│ ├── fragment_horizontal_linear.xml
│ ├── fragment_main.xml
│ ├── fragment_vertical_grid.xml
│ ├── fragment_vertical_linear.xml
│ ├── item_horizontal_grid.xml
│ ├── item_horizontal_grid2.xml
│ ├── item_horizontal_linear.xml
│ ├── item_vertical_grid.xml
│ └── item_vertical_linear.xml
│ ├── menu
│ └── menu_main.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_delete.png
│ ├── ic_launcher.png
│ ├── ic_launcher_round.png
│ ├── ic_picture.png
│ └── ic_picture1.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── values-en
│ └── strings.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── config.gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── pageview
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ ├── android
│ │ └── support
│ │ │ └── v7
│ │ │ └── widget
│ │ │ └── PageRecyclerView.java
│ └── com
│ │ └── ckr
│ │ └── pageview
│ │ ├── adapter
│ │ ├── BasePageAdapter.java
│ │ ├── OnAutoSizeListener.java
│ │ ├── OnIndicatorListener.java
│ │ └── OnPageDataListener.java
│ │ ├── manager
│ │ └── LifecycleManager.java
│ │ ├── transform
│ │ ├── AccordionTransformer.java
│ │ ├── BaseTransformer.java
│ │ ├── CubeOutTransformer.java
│ │ ├── DefaultTransformer.java
│ │ ├── DepthPageTransformer.java
│ │ ├── FlipTransformer.java
│ │ ├── ScaleInOutTransformer.java
│ │ ├── StackTransformer.java
│ │ ├── TabletTransformer.java
│ │ ├── Transformer.java
│ │ ├── ZoomInTransformer.java
│ │ └── ZoomOutSlideTransformer.java
│ │ ├── utils
│ │ └── PageLog.java
│ │ └── view
│ │ ├── PageHandler.java
│ │ └── PageView.java
│ └── res
│ ├── drawable
│ ├── shape_point_selected.xml
│ └── shape_point_unselected.xml
│ ├── layout
│ ├── horizontal_page_view.xml
│ └── vertical_page_view.xml
│ └── values
│ ├── attrs_page_view.xml
│ ├── indicator.xml
│ └── strings.xml
├── screenRecorder
├── Screenshot_1.gif
├── Screenshot_2.gif
├── Screenshot_3.gif
├── Screenshot_4.gif
├── Screenshot_5.gif
└── qq.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README-ZH.md:
--------------------------------------------------------------------------------
1 | # PageRecyclerView
2 | PageRecyclerView实现翻页功能及无限轮播。另外,使用了[banner](https://github.com/youth5201314/banner)的作者的翻页动画。
3 |
4 | ## 效果演示
5 | | 无限轮播 | 水平网格分页 | 添加数据 |
6 | | ------------ | ------------------------- | ----------- |
7 | |  |  |  |
8 |
9 | | 移除数据 | 竖直线性分页 |
10 | | ------------ | ------------------------- |
11 | |  |  |
12 |
13 | ## Demo
14 | [下载 APK](apk/app-debug.apk)
15 |
16 | ## 依赖
17 | ### 添加依赖:
18 | ```
19 | dependencies {
20 | implementation 'ckrjfrog.Page:PageView:1.2.12'//gradle plugin 3.0(包含)以上使用
21 | //compile 'ckrjfrog.Page:PageView:1.2.12'//gradle plugin 3.0一下使用
22 | }
23 | ```
24 |
25 | ## 功能及使用
26 | ### 1.布局引用
27 | ```
28 |
54 | ```
55 | ### 2.属性说明
56 | | 属性 | 描述 | 类型 | 默认值 |
57 | | ----------------------------- | -------------------------------------- | ---------- | ------------- |
58 | | loop | 是否启动无限轮播(当每页只有一个item时有效) | boolean | false |
59 | | loop_interval | 轮询时间间隔 | int | 3000 |
60 | | autoplay | 自动轮播 | boolean | false |
61 | | autosize | item宽或高自适应(只在网格布局有效) | boolean | false |
62 | | hide_indicator | 是否隐藏指示器 | boolean | false |
63 | | indicator_container_background| 指示器父容器的背景 | drawable | null |
64 | | indicator_contianer_heigt | 指示器父容器的高度 | int | 90 |
65 | | indicator_contianer_width | 指示器父容器的高度 | int | 90 |
66 | | indicator_group_alignment | 指示器组的对齐方式 | int | 0x11(center) |
67 | | indicator_group_marginLeft | 指示器组的marginLeft | int | 0 |
68 | | indicator_group_marginTop | 指示器组的marginTop | int | 0 |
69 | | indicator_group_marginRight | 指示器组的marginRight | int | 0 |
70 | | indicator_group_marginBottom | 指示器组的marginBottom | int | 0 |
71 | | indicator_margin | 指示器间的间距 | int | 15 |
72 | | clipToPadding | recyclerView的clipTopadding设置 | boolean | false |
73 | | pagePadding | recyclerView的左右padding设置 | int | 15 |
74 | | layout_flag | 标记线性布局或网格布局 | int | 0(线性) |
75 | | orientation | 布局方向 | int | 0(horizontal) |
76 | | overlap_layout | 指示器容器是否遮住PageRecyclerView | boolean | false |
77 | | page_column | 每页的列数 | int | 1 |
78 | | page_row | 每页的行数 | int | 1 |
79 | | selected_indicator_color | 当前页的指示器颜色 | int | Color.RED |
80 | | selected_indicator_diameter | 当前页的指示器直径 | int | 15 |
81 | | selected_indicator_drawable | 当前页的指示器drawable(优先级高于颜色) | drawable | null |
82 | | unselected_indicator_color | 非当前页的指示器颜色 | int | Color.BLACK |
83 | | unselected_indicator_diameter | 非当前页的指示器直径 | int | 15 |
84 | | selected_indicator_drawable | 非当前页的指示器drawable(优先级高于颜色) | drawable | null |
85 | | page_background | 当前页的背景 | drawable | null |
86 | | enable_touch_scroll | 是否允许触摸滚动 | boolean | true |
87 | | max_scroll_duration | 每页滚动最大时间 | int | 600 |
88 | | min_scroll_duration | 每页滚动最小时间 | int | 0 |
89 | | sub_loop_interval | 轮播时,下标自动调整时下一页的轮播时间间隔 | int | 100 |
90 |
91 | ### 3.代码使用
92 | ```
93 | mainAdapter = new MainAdapter(getContext(), itemLayoutId);//该MainAdapter需继承BasePageAdapter
94 | pageView.setAdapter(mainAdapter);//设置adapter
95 | pageView.updateAll(items);//更新数据
96 | ```
97 | ## 感谢
98 | [banner](https://github.com/youth5201314/banner)
99 |
100 | ## 我的开源项目
101 | [CollapsingRefresh](https://github.com/ckrgithub/CollapsingRefresh):AppBarLayout+ViewPager+RecyclerView的刷新功能
102 |
103 | [FlexItemDecoration](https://github.com/ckrgithub/FlexItemDecoration):recyclerView分割线的绘制
104 |
105 | ## 版本更新
106 | * **1.2.0-release**
107 | * 添加:autopaly属性
108 | * 添加:翻页动画
109 |
110 | * **1.1.1-release**
111 | * 修复:快速滑动,指示器没有及时更新的问题
112 | * 修复:当引用android O 的recyclerview时,setCurrentItem(1,false)不起效问题
113 | * 添加:clipToPadding和pagePadding的配置
114 |
115 | * **1.1.0-release**
116 | * 添加:指示器容器的对齐方式、margin设置、背景设置和overlap布局样式
117 | * 其他:优化代码
118 |
119 | * **1.0.9-release**
120 | * 修复:轮播时,数据源发生变化引起指示点错乱的问题
121 | ## QQ群
122 | QQ群号:862950533
123 | 二维码:
124 | 
125 |
126 | License
127 | -------
128 |
129 | Copyright 2018 ckrgithub
130 |
131 | Licensed under the Apache License, Version 2.0 (the "License");
132 | you may not use this file except in compliance with the License.
133 | You may obtain a copy of the License at
134 |
135 | http://www.apache.org/licenses/LICENSE-2.0
136 |
137 | Unless required by applicable law or agreed to in writing, software
138 | distributed under the License is distributed on an "AS IS" BASIS,
139 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
140 | See the License for the specific language governing permissions and
141 | limitations under the License.
142 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PageRecyclerView
2 | PageRecyclerView achieves page turning function and unlimited carousel [中文文档](README-ZH.md)。
3 |
4 | ## Effect
5 | | carousel | horizontal-grid-paging | add-data |
6 | | ------------ | ------------------------- | ----------- |
7 | |  |  | 
8 |
9 | | remove-data | vertical-linear-paging |
10 | | ------------ | ------------------------- |
11 | |  |  |
12 |
13 | ## Demo
14 | [Download APK](apk/app-debug.apk)
15 |
16 | ## Dependencies
17 | ### add dependencies:
18 | ```
19 | dependencies {
20 | implementation 'ckrjfrog.Page:PageView:1.2.12'//gradle plugin 3.0(inclusive) above used
21 | //compile 'ckrjfrog.Page:PageView:1.2.12'//gradle plugin 3.0 below used
22 | }
23 | ```
24 |
25 | ## Function And Use
26 | ### 1.layout reference
27 | ```
28 |
54 | ```
55 | ### 2.attributes description
56 | | attributes | description | type | defaults |
57 | | ------------------ | ----------------------------- | ----------------- | ---------------- |
58 | | loop | start a carousel(valid when there is only one item per page) | boolean | false |
59 | | loop_interval | loop interval | int | 3000 |
60 | | autoplay | automatically scroll to the next page | boolean | false |
61 | | autosize | automatically adjust the width or height of item(valid in the grid layout) | boolean | false |
62 | | hide_indicator | hide indicator | boolean | false |
63 | | indicator_container_background| the background of indicator parent container | drawable | null |
64 | | indicator_container_height | indicator parent container height(valid in the vertical orientation) | int | 90 |
65 | | indicator_contianer_width | indicator parent container width(valid in the horizontal orientation) | int | 90 |
66 | | indicator_group_alignment | the alignment of indicator group(eg: left,top,center) | int | 0x11(center) |
67 | | indicator_group_marginLeft | the marginLeft of indicator group | int | 0 |
68 | | indicator_group_marginTop | the marginTop of indicator group | int | 0 |
69 | | indicator_group_marginRight | the marginRight of indicator group | int | 0 |
70 | | indicator_group_marginBottom | the marginBottom of indicator group | int | 0 |
71 | | indicator_margin | indicator spacing | boolean | false |
72 | | clipToPadding | the clipTopadding of recyclerView | int | 15 |
73 | | pagePadding | recyclerView.setPadding(pagePadding,0,pagePading,0) | int | 15 |
74 | | layout_flag | mark linear layout or grid layout | int | 0(linear layout) |
75 | | orientation | layout orientation | int | 0(horizontal) |
76 | | overlap_layout | Whether the indicator overlaps the page | boolean | false |
77 | | page_column | the number of columns per page | int | 1 |
78 | | page_row | the number of rows per page | int | 1 |
79 | | selected_indicator_color | indicator color for the current page | int | Color.RED |
80 | | selected_indicator_diameter | indicator diameter for the current page | int | 15 |
81 | | selected_indicator_drawable | indicator drawable for the current page(priority is higher than color) | drawable | null |
82 | | unselected_indicator_color | indicator color for the non-current page | int | Color.BLACK |
83 | | unselected_indicator_diameter | indicator diameter for the non-current page | int | 15 |
84 | | selected_indicator_drawable | indicator drawable for the non-current page(priority is higher than color) | drawable | null |
85 | | page_background | the background of the current page | drawable | null |
86 | | enable_touch_scroll | Whether to allow touch scrolling | boolean | true |
87 | | max_scroll_duration | Maximum scrolling time of the page | int | 600 |
88 | | min_scroll_duration | Minimum scrolling time of the page | int | 0 |
89 | | sub_loop_interval | When the index is adjusted, loop interval | int | 100 |
90 |
91 | ### 3.code to use
92 | ```
93 | mainAdapter = new MainAdapter(getContext(), itemLayoutId);//MainAdapter extend BasePageAdapter
94 | pageView.setAdapter(mainAdapter);
95 | pageView.updateAll(items);
96 | ```
97 | ## Thanks
98 | [banner](https://github.com/youth5201314/banner)
99 |
100 | ## My Other Project
101 | [CollapsingRefresh](https://github.com/ckrgithub/CollapsingRefresh)
102 |
103 | [FlexItemDecoration](https://github.com/ckrgithub/FlexItemDecoration)
104 |
105 | ## Version Tracking
106 | * **1.2.0-release**
107 | * add: the settings of autoplay
108 | * add: the animation of scrolling to the page
109 |
110 | * **1.1.1-release**
111 | * repair: When fast sliding,the indicators don't update in time
112 | * repair: the method of setCurrentItem(1,false) doesn't work
113 | * add: clipToPadding and pagePadding Settings
114 |
115 | * **1.1.0-release**
116 | * add: the indicator container alignment, margin Settings, background Settings, and overlap layout styles
117 | * other: optimize the code
118 |
119 | * **1.0.9-release**
120 | * repair: When the carousel is broadcast, the data source changes to cause confusion in the indicator point.
121 |
122 | ## Community
123 | Contact Me: 862950533
124 | Or scan the QR code below:
125 | 
126 |
127 | License
128 | -------
129 |
130 | Copyright 2018 ckrgithub
131 |
132 | Licensed under the Apache License, Version 2.0 (the "License");
133 | you may not use this file except in compliance with the License.
134 | You may obtain a copy of the License at
135 |
136 | http://www.apache.org/licenses/LICENSE-2.0
137 |
138 | Unless required by applicable law or agreed to in writing, software
139 | distributed under the License is distributed on an "AS IS" BASIS,
140 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
141 | See the License for the specific language governing permissions and
142 | limitations under the License.
143 |
--------------------------------------------------------------------------------
/apk/app-debug.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/apk/app-debug.apk
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/android.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/android.jks
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'android-apt'
3 |
4 | android {
5 | compileSdkVersion rootProject.ext.androidConfig.compileSdkVersion
6 | buildToolsVersion rootProject.ext.androidConfig.buildToolsVersion
7 | defaultConfig {
8 | applicationId rootProject.ext.appConfig.applicationId
9 | minSdkVersion rootProject.ext.androidConfig.minSdkVersion
10 | targetSdkVersion rootProject.ext.androidConfig.targetSdkVersion
11 | versionCode rootProject.ext.appConfig.versionCode
12 | versionName rootProject.ext.appConfig.versionName
13 | }
14 |
15 | signingConfigs {
16 | release {
17 | keyAlias 'key0'
18 | keyPassword '123456'
19 | storeFile file('./android.jks')
20 | storePassword '123456'
21 | }
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
28 | signingConfig signingConfigs.release
29 | }
30 | }
31 | lintOptions {
32 | abortOnError false
33 | }
34 | }
35 |
36 | dependencies {
37 | compile fileTree(include: ['*.jar'], dir: 'libs')
38 | compile "com.android.support:appcompat-v7:$rootProject.supportVersion"
39 | compile "com.android.support:recyclerview-v7:$rootProject.supportVersion"
40 | compile "com.android.support:design:$rootProject.supportVersion"
41 | compile 'com.jakewharton:butterknife:8.8.1'
42 | apt 'com.jakewharton:butterknife-compiler:8.8.1'
43 | // compile project(':pageview')
44 | compile 'ckrjfrog.Page:PageView:1.2.13'
45 | }
46 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\Android\sdk1/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ckr/pagesnaphelper/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pagesnaphelper;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.FragmentManager;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.Menu;
7 | import android.view.MenuItem;
8 |
9 | import com.ckr.pagesnaphelper.view.MainFragment;
10 | import com.ckr.pageview.transform.Transformer;
11 | import com.ckr.pageview.utils.PageLog;
12 |
13 | import java.util.HashMap;
14 | import java.util.Map;
15 |
16 | import butterknife.ButterKnife;
17 | import butterknife.Unbinder;
18 |
19 | public class MainActivity extends AppCompatActivity {
20 | private Unbinder unbinder;
21 | private static final int[] MENU_ITEM_ID = {R.id.item, R.id.accordion, R.id.cubeOut
22 | , R.id.depthPage, R.id.flip, R.id.scaleInOut, R.id.stack, R.id.tablet
23 | , R.id.zoomIn, R.id.zoomOutSlide};
24 | private Menu menu;
25 | private MainFragment mainFragment;
26 | private int lastIndex;
27 | public Map map;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.activity_main);
33 | PageLog.debug();
34 | unbinder = ButterKnife.bind(this);
35 | FragmentManager fragmentManager = getSupportFragmentManager();
36 | if (savedInstanceState == null) {
37 | mainFragment = MainFragment.newInstance();
38 | fragmentManager.beginTransaction()
39 | .add(R.id.container, mainFragment, MainFragment.class.getName())
40 | .commit();
41 | } else {
42 | fragmentManager.beginTransaction().show(mainFragment = (MainFragment) fragmentManager.findFragmentByTag(MainFragment.class.getName()))
43 | .commit();
44 | }
45 | map = new HashMap<>(MENU_ITEM_ID.length);
46 | for (int i = 0; i < MENU_ITEM_ID.length; i++) {
47 | map.put(MENU_ITEM_ID[i], i);
48 | }
49 | }
50 |
51 | @Override
52 | protected void onDestroy() {
53 | super.onDestroy();
54 | unbinder.unbind();
55 | }
56 |
57 | @Override
58 | public boolean onCreateOptionsMenu(Menu menu) {
59 | this.menu = menu;
60 | getMenuInflater().inflate(R.menu.menu_main, this.menu);
61 | return true;
62 | }
63 |
64 | @Override
65 | public boolean onOptionsItemSelected(MenuItem item) {
66 | if (item.isChecked()) {
67 | return true;
68 | }
69 | switch (item.getItemId()) {
70 | case R.id.item:
71 | case R.id.accordion:
72 | case R.id.cubeOut:
73 | case R.id.depthPage:
74 | case R.id.flip:
75 | case R.id.scaleInOut:
76 | case R.id.stack:
77 | case R.id.tablet:
78 | case R.id.zoomIn:
79 | case R.id.zoomOutSlide:
80 | disableChecked(lastIndex);
81 | boolean checked = !item.isChecked();
82 | item.setChecked(checked);
83 | int index = map.get(item.getItemId());
84 | lastIndex = index;
85 | mainFragment.refreshFragment(Transformer.values()[index].getTransformer());
86 | return true;
87 | default:
88 | return super.onOptionsItemSelected(item);
89 | }
90 | }
91 |
92 | private void disableChecked(int pos) {
93 | MenuItem menuItem = menu.findItem(MENU_ITEM_ID[pos]);
94 | if (menuItem.isChecked()) {
95 | menuItem.setChecked(false);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ckr/pagesnaphelper/adapter/MainAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pagesnaphelper.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.LayoutRes;
5 | import android.support.v4.content.ContextCompat;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.View;
8 | import android.widget.ImageButton;
9 | import android.widget.ImageView;
10 | import android.widget.RelativeLayout;
11 | import android.widget.TextView;
12 | import android.widget.Toast;
13 |
14 | import com.ckr.pagesnaphelper.R;
15 | import com.ckr.pagesnaphelper.model.Item;
16 | import com.ckr.pageview.adapter.BasePageAdapter;
17 |
18 |
19 | /**
20 | * Created by PC大佬 on 2018/1/14.
21 | */
22 |
23 | public class MainAdapter extends BasePageAdapter- {
24 | private static final String TAG = "MainAdapter";
25 | public static final int MIN_VALUE = 6;
26 | private boolean isShowDeleteIcon;
27 | private int mLayoutId;
28 |
29 | public MainAdapter(Context context, @LayoutRes int itemLayoutId) {
30 | super(context);
31 | mLayoutId = itemLayoutId;
32 | }
33 |
34 | @Override
35 | public int getItemCount() {
36 | int itemCount = super.getItemCount();
37 | if (mIsLooping) {
38 | return itemCount == 0 ? 0 : Math.max(itemCount * 2, MIN_VALUE);
39 | }
40 | return itemCount;
41 | }
42 |
43 | @Override
44 | protected int getLayoutId(int viewType) {
45 | return mLayoutId;
46 | }
47 |
48 | @Override
49 | protected MainHolder getViewHolder(View itemView, int viewType) {
50 | return new MainHolder(itemView);
51 | }
52 |
53 | @Override
54 | protected void convert(MainHolder holder, final int position, Item originItem, final int adjustedPosition, Item item) {
55 | if (mLayoutFlag == GRID) {
56 | int page = adjustedPosition % (mRow * mColumn * 6);
57 | if (page < mRow * mColumn) {
58 | holder.itemView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.color1));
59 | } else if (page < mRow * mColumn * 2) {
60 | holder.itemView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.color2));
61 | } else if (page < mRow * mColumn * 3) {
62 | holder.itemView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.color3));
63 | } else if (page < mRow * mColumn * 4) {
64 | holder.itemView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.color4));
65 | } else if (page < mRow * mColumn * 5) {
66 | holder.itemView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.color5));
67 | } else {
68 | holder.itemView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.color6));
69 | }
70 | } else {
71 | int page = adjustedPosition % 6;
72 | if (page < 1) {
73 | holder.imageView.setImageResource(R.drawable.bg_color1);
74 | } else if (page < 2) {
75 | holder.imageView.setImageResource(R.drawable.bg_color2);
76 | } else if (page < 3) {
77 | holder.imageView.setImageResource(R.drawable.bg_color3);
78 | } else if (page < 4) {
79 | holder.imageView.setImageResource(R.drawable.bg_color4);
80 | } else if (page < 5) {
81 | holder.imageView.setImageResource(R.drawable.bg_color5);
82 | } else if (page < 6) {
83 | holder.imageView.setImageResource(R.drawable.bg_color6);
84 | }
85 | }
86 | if (item == null) {
87 | holder.relativeLayout.setVisibility(View.INVISIBLE);
88 | holder.itemView.setOnLongClickListener(null);
89 | holder.itemView.setOnClickListener(null);
90 | holder.imageButton.setOnClickListener(null);
91 | } else {
92 | holder.relativeLayout.setVisibility(View.VISIBLE);
93 | holder.textView.setText(item.getName());
94 |
95 | holder.itemView.setOnLongClickListener(new OnItemLongClickListener(adjustedPosition));
96 | holder.itemView.setOnClickListener(new OnItemClickListener(adjustedPosition));
97 | holder.imageButton.setOnClickListener(new OnItemClickListener(adjustedPosition));
98 | holder.imageButton.setVisibility(isShowDeleteIcon ? View.VISIBLE : View.GONE);
99 | }
100 | }
101 |
102 | class MainHolder extends RecyclerView.ViewHolder {
103 | private TextView textView;
104 | private RelativeLayout relativeLayout;
105 | private ImageButton imageButton;
106 | private ImageView imageView;
107 |
108 | public MainHolder(View itemView) {
109 | super(itemView);
110 | textView = (TextView) itemView.findViewById(R.id.textView);
111 | relativeLayout = (RelativeLayout) itemView.findViewById(R.id.relativeLayout);
112 | imageButton = (ImageButton) itemView.findViewById(R.id.imageButton);
113 | imageView = (ImageView) itemView.findViewById(R.id.imageView);
114 | }
115 | }
116 |
117 | class OnItemLongClickListener implements View.OnLongClickListener {
118 | private int mPosition;
119 |
120 | public OnItemLongClickListener(int position) {
121 | mPosition = position;
122 | }
123 |
124 | @Override
125 | public boolean onLongClick(View v) {
126 | isShowDeleteIcon = !isShowDeleteIcon;
127 | notifyDataSetChanged();
128 | return true;
129 | }
130 | }
131 |
132 | class OnItemClickListener implements View.OnClickListener {
133 | private int mTargetPos;
134 |
135 | public OnItemClickListener(int adjustedPos) {
136 | mTargetPos = adjustedPos;
137 | }
138 |
139 | @Override
140 | public void onClick(View v) {
141 | int id = v.getId();
142 | if (id == R.id.imageButton) {
143 | removeItem(mTargetPos);
144 | } else {
145 | Toast.makeText(mContext, "position:" + mTargetPos, Toast.LENGTH_SHORT).show();
146 | }
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ckr/pagesnaphelper/adapter/MyFragmentPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pagesnaphelper.adapter;
2 |
3 | import android.support.v4.app.Fragment;
4 | import android.support.v4.app.FragmentManager;
5 | import android.support.v4.app.FragmentPagerAdapter;
6 |
7 | import com.ckr.pagesnaphelper.view.BaseFragment;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * Created by PC大佬 on 2018/1/14.
13 | */
14 |
15 | public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
16 | List fragmentList;
17 | private String[] titles;
18 |
19 | public MyFragmentPagerAdapter(FragmentManager fm, List fragmentList, String[] titles) {
20 | super(fm);
21 | this.fragmentList = fragmentList;
22 | this.titles = titles;
23 | }
24 |
25 | @Override
26 | public Fragment getItem(int position) {
27 | return fragmentList.get(position);
28 | }
29 |
30 | @Override
31 | public int getCount() {
32 | return fragmentList.size();
33 | }
34 |
35 | @Override
36 | public CharSequence getPageTitle(int position) {
37 | return titles[position];
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ckr/pagesnaphelper/model/Item.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pagesnaphelper.model;
2 |
3 | /**
4 | * Created by PC大佬 on 2018/1/13.
5 | */
6 |
7 | public class Item implements Cloneable{
8 | private String name;
9 |
10 | public Item() {
11 | }
12 |
13 | public void setName(String name) {
14 | this.name = name;
15 | }
16 |
17 | public String getName() {
18 | return name;
19 | }
20 |
21 | @Override
22 | public Object clone() throws CloneNotSupportedException {
23 | return super.clone();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ckr/pagesnaphelper/view/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pagesnaphelper.view;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.CallSuper;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import com.ckr.pageview.transform.BaseTransformer;
12 |
13 | import butterknife.ButterKnife;
14 | import butterknife.Unbinder;
15 |
16 | /**
17 | * Created by PC大佬 on 2018/1/14.
18 | */
19 |
20 | public abstract class BaseFragment extends Fragment {
21 | private View view;
22 | private Unbinder unbinder;
23 |
24 | @Nullable
25 | @Override
26 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
27 | Bundle savedInstanceState) {
28 | view = inflater.inflate(getContentLayoutId(), container, false);
29 | unbinder = ButterKnife.bind(this, view);
30 | init();
31 | return view;
32 | }
33 |
34 | @CallSuper
35 | @Override
36 | public void onResume() {
37 | super.onResume();
38 | if (getUserVisibleHint()) {
39 | onVisible();
40 | }
41 | }
42 |
43 | @Override
44 | public void onDestroyView() {
45 | super.onDestroyView();
46 | unbinder.unbind();
47 | }
48 |
49 | protected abstract int getContentLayoutId();
50 |
51 | protected abstract void init();
52 |
53 | @Override
54 | public void setUserVisibleHint(boolean isVisibleToUser) {
55 | super.setUserVisibleHint(isVisibleToUser);
56 | if (isVisibleToUser&&isResumed()) {
57 | onVisible();
58 | } else {
59 | onInvisible();
60 | }
61 | }
62 |
63 | protected void onVisible() {
64 | }
65 |
66 | protected void onInvisible() {
67 | }
68 |
69 | protected void addData(int index) {}
70 |
71 | protected void jumpToPage(int page) {}
72 |
73 | public abstract void refreshFragment(BaseTransformer baseTransformer);
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ckr/pagesnaphelper/view/MainFragment.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pagesnaphelper.view;
2 |
3 |
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.design.widget.TabLayout;
7 | import android.support.v4.app.Fragment;
8 | import android.support.v4.app.FragmentManager;
9 | import android.support.v4.view.ViewPager;
10 | import android.text.TextUtils;
11 | import android.view.View;
12 | import android.widget.EditText;
13 | import android.widget.Toast;
14 |
15 | import com.ckr.pagesnaphelper.R;
16 | import com.ckr.pagesnaphelper.adapter.MyFragmentPagerAdapter;
17 | import com.ckr.pageview.transform.BaseTransformer;
18 |
19 | import java.util.ArrayList;
20 |
21 | import butterknife.BindArray;
22 | import butterknife.BindView;
23 | import butterknife.OnClick;
24 |
25 | import static com.ckr.pagesnaphelper.R.id.editText;
26 |
27 | /**
28 | * A simple {@link Fragment} subclass.
29 | */
30 | public class MainFragment extends BaseFragment implements ViewPager.OnPageChangeListener {
31 | private static final String TAG = "MainFragment";
32 | private static final String ARGS_PAGE = "mCurrentPage";
33 | @BindView(R.id.myViewPager)
34 | ViewPager myViewPager;
35 | @BindView(R.id.tabLayout)
36 | TabLayout tabLayout;
37 | @BindView(editText)
38 | EditText addText;
39 | @BindView(R.id.editText2)
40 | EditText jumpText;
41 | @BindArray(R.array.tab_title)
42 | String[] TITLES;
43 | private FragmentManager fragmentManager;
44 | private ArrayList fragmentList;
45 | private int mCurrentPage;
46 | private Bundle saveState;
47 | private BaseTransformer baseTransformer;
48 |
49 | public static MainFragment newInstance() {
50 | Bundle args = new Bundle();
51 | MainFragment fragment = new MainFragment();
52 | fragment.setArguments(args);
53 | return fragment;
54 | }
55 |
56 | @Override
57 | protected int getContentLayoutId() {
58 | return R.layout.fragment_main;
59 | }
60 |
61 | @Override
62 | protected void init() {
63 | initFragment();
64 | initView();
65 | }
66 |
67 | private void initFragment() {
68 | int length = TITLES.length;
69 | fragmentManager = getChildFragmentManager();
70 | fragmentList = new ArrayList<>(length);
71 | for (int i = 0; i < length; i++) {
72 | String name = makeFragmentName(R.id.myViewPager, i);
73 | BaseFragment fragment = (BaseFragment) fragmentManager.findFragmentByTag(name);
74 | if (fragment == null) {
75 | if (i == 0) {
76 | fragmentList.add(PageFragment.newInstance(R.layout.fragment_horizontal_linear, R.layout.item_horizontal_linear));
77 | } else if (i == 1) {
78 | fragmentList.add(PageFragment.newInstance(R.layout.fragment_horizontal_grid, R.layout.item_horizontal_grid));
79 | } else if (i == 2) {
80 | fragmentList.add(PageFragment.newInstance(R.layout.fragment_vertical_linear, R.layout.item_vertical_linear));
81 | } else if (i == 3) {
82 | fragmentList.add(PageFragment.newInstance(R.layout.fragment_vertical_grid, R.layout.item_vertical_grid));
83 | } else if (i == 4) {
84 | // fragmentList.add(PageFragment.newInstance(R.layout.fragment_horizontal_grid2, R.layout.item_horizontal_grid2));
85 | }
86 | } else {
87 | fragmentList.add(fragment);
88 | }
89 | }
90 | }
91 |
92 | private static String makeFragmentName(int viewId, long id) {
93 | return "android:switcher:" + viewId + ":" + id;
94 | }
95 |
96 | private void initView() {
97 | myViewPager.addOnPageChangeListener(this);
98 | myViewPager.setAdapter(new MyFragmentPagerAdapter(fragmentManager, fragmentList, TITLES));
99 | tabLayout.setupWithViewPager(myViewPager);
100 | }
101 |
102 | @Override
103 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
104 | Bundle bundle = restoreState();
105 | if (bundle != null) {
106 | mCurrentPage = bundle.getInt(ARGS_PAGE, mCurrentPage);
107 | }
108 | myViewPager.setCurrentItem(mCurrentPage, false);
109 | }
110 |
111 | private Bundle restoreState() {
112 | Bundle arguments = getArguments();
113 | if (arguments == null) {
114 | return null;
115 | }
116 | Bundle bundle = arguments.getBundle(MainFragment.class.getName());
117 | return bundle;
118 | }
119 |
120 | @Override
121 | public void onSaveInstanceState(Bundle outState) {
122 | saveState = outState;
123 | saveState();
124 | }
125 |
126 | private void saveState() {
127 | if (saveState == null) {
128 | saveState = new Bundle();
129 | }
130 | saveState.putInt(ARGS_PAGE, mCurrentPage);
131 | Bundle arguments = getArguments();
132 | arguments.putBundle(MainFragment.class.getName(), saveState);
133 | }
134 |
135 | @Override
136 | public void onDestroyView() {
137 | super.onDestroyView();
138 | if (saveState == null) {
139 | saveState();
140 | }
141 | }
142 |
143 |
144 | @OnClick({R.id.add, R.id.jump})
145 | public void onViewClicked(View view) {
146 | switch (view.getId()) {
147 | case R.id.add:
148 | String text = addText.getText().toString().trim();
149 | int index = -1;
150 | if (!TextUtils.isEmpty(text)) {
151 | index = Integer.valueOf(text);
152 | }
153 | fragmentList.get(mCurrentPage).addData(index);
154 | break;
155 | case R.id.jump:
156 | text = jumpText.getText().toString().trim();
157 | int page = 0;
158 | if (!TextUtils.isEmpty(text)) {
159 | page = Integer.valueOf(text);
160 | }else {
161 | Toast.makeText(getActivity(),"内容不能为空",Toast.LENGTH_LONG).show();
162 | }
163 | fragmentList.get(mCurrentPage).jumpToPage(page);
164 | break;
165 | }
166 | }
167 |
168 | @Override
169 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
170 | }
171 |
172 | @Override
173 | public void onPageSelected(int position) {
174 | mCurrentPage = position;
175 | fragmentList.get(mCurrentPage).refreshFragment(this.baseTransformer);
176 | }
177 |
178 | @Override
179 | public void onPageScrollStateChanged(int state) {
180 | }
181 |
182 | @Override
183 | public void refreshFragment(BaseTransformer baseTransformer) {
184 | this.baseTransformer = baseTransformer;
185 | fragmentList.get(mCurrentPage).refreshFragment(this.baseTransformer);
186 | }
187 | }
188 |
189 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ckr/pagesnaphelper/view/PageFragment.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pagesnaphelper.view;
2 |
3 |
4 | import android.content.Context;
5 | import android.os.Bundle;
6 | import android.support.annotation.LayoutRes;
7 | import android.support.v4.app.Fragment;
8 | import android.support.v7.widget.PageRecyclerView;
9 | import android.util.Log;
10 |
11 | import com.ckr.pagesnaphelper.R;
12 | import com.ckr.pagesnaphelper.adapter.MainAdapter;
13 | import com.ckr.pagesnaphelper.model.Item;
14 | import com.ckr.pageview.transform.BaseTransformer;
15 | import com.ckr.pageview.view.PageView;
16 |
17 | import java.util.ArrayList;
18 |
19 | import butterknife.BindView;
20 |
21 | //import com.ckr.pageview.view.PageRecyclerView;
22 |
23 | /**
24 | * A simple {@link Fragment} subclass.
25 | */
26 | public class PageFragment extends BaseFragment implements PageRecyclerView.OnPageChangeListener {
27 | private static final String TAG = "PageFragment";
28 | private static final String ID_LAYOUT = "layoutId";
29 | private static final String ID_LAYOUT_ITEM = "itemLayoutId";
30 | @BindView(R.id.pageView)
31 | PageView pageView;
32 | private MainAdapter mainAdapter;
33 | private ArrayList
- items;
34 | private final static int CAPACITY = 24;
35 | private int layoutId;
36 | private int itemLayoutId;
37 | private int startCount = 100;
38 | private boolean isVisible = false;
39 | private boolean isLooping;
40 |
41 | public static PageFragment newInstance(@LayoutRes int layoutId, @LayoutRes int itemLayoutId) {
42 | Bundle args = new Bundle();
43 | args.putInt(ID_LAYOUT, layoutId);
44 | args.putInt(ID_LAYOUT_ITEM, itemLayoutId);
45 | PageFragment fragment = new PageFragment();
46 | fragment.setArguments(args);
47 | return fragment;
48 | }
49 |
50 | @Override
51 | public void onAttach(Context context) {
52 | super.onAttach(context);
53 | Bundle arguments = getArguments();
54 | if (arguments != null) {
55 | layoutId = arguments.getInt(ID_LAYOUT, R.layout.fragment_horizontal_grid);
56 | itemLayoutId = arguments.getInt(ID_LAYOUT_ITEM, R.layout.item_horizontal_grid);
57 | }
58 | }
59 |
60 | @Override
61 | protected int getContentLayoutId() {
62 | return layoutId;
63 | }
64 |
65 | @Override
66 | protected void init() {
67 | initData();
68 | initView();
69 | }
70 |
71 | private void initView() {
72 | pageView.addOnPageChangeListener(this);
73 | //AppCompatActivity版本>=26.1.0才生效
74 | //pageView.registerLifeCycleObserver();
75 | //pageView.hideIndicatorContainer(2);
76 | mainAdapter = new MainAdapter(getContext(), itemLayoutId);
77 | pageView.setAdapter(mainAdapter);
78 | isLooping = mainAdapter.isLooping();
79 | if (isLooping) {
80 | Log.d(TAG, "initView: " + isVisible);
81 | pageView.updateAll(items.subList(0, 3));
82 | // pageView.setCurrentItem(1, false);
83 | } else {
84 | pageView.updateAll(items);
85 | }
86 | }
87 |
88 | private void initData() {
89 | items = new ArrayList<>(CAPACITY);
90 | Item item = new Item();
91 | try {
92 | for (int i = 0; i < CAPACITY; i++) {
93 | Item clone = (Item) item.clone();
94 | clone.setName("item " + i);
95 | items.add(clone);
96 | }
97 | } catch (CloneNotSupportedException e) {
98 | e.printStackTrace();
99 | }
100 | }
101 |
102 | @Override
103 | protected void onVisible() {
104 | if (isLooping) {
105 | Log.d(TAG, "onVisible: " + isVisible);
106 | }
107 | isVisible = true;
108 | if (pageView != null) {
109 | pageView.restartLooping();
110 | }
111 | }
112 |
113 | @Override
114 | protected void onInvisible() {
115 | if (isLooping) {
116 | Log.d(TAG, "onInvisible: " + isVisible);
117 | }
118 | isVisible = false;
119 | if (pageView != null) {
120 | pageView.stopLooping();
121 | }
122 | }
123 |
124 | @Override
125 | public void onResume() {
126 | super.onResume();
127 | if (isLooping) {
128 | Log.d(TAG, "onResume: " + isVisible);
129 | }
130 | if (pageView != null && isVisible) {
131 | pageView.restartLooping();
132 | }
133 | }
134 |
135 | @Override
136 | public void onStop() {
137 | super.onStop();
138 | if (isLooping) {
139 | Log.d(TAG, "onStop: " + isVisible);
140 | }
141 | if (pageView != null) {
142 | pageView.stopLooping();
143 | }
144 | }
145 |
146 | @Override
147 | protected void addData(int index) {
148 | if (mainAdapter.isLooping()) {
149 | // mainAdapter.updateAll(new ArrayList
- ());
150 | pageView.updateAll(items.subList(0, index > CAPACITY ? CAPACITY : index));
151 | // pageView.setCurrentItem(MAX_VALUE / 2, false);
152 | return;
153 | }
154 | int itemCount = mainAdapter.getRawItemCount();
155 | Item item = new Item();
156 | item.setName("item " + startCount);
157 | startCount++;
158 | if (index == -1 || index >= itemCount) {
159 | mainAdapter.updateItem(item);
160 | } else {
161 | mainAdapter.updateItem(index, item);
162 | }
163 | }
164 |
165 | @Override
166 | protected void jumpToPage(int page) {
167 | if (mainAdapter.isLooping()) {
168 | return;
169 | }
170 | int pageCount = mainAdapter.getPageCount();
171 | if (page > pageCount - 1) {
172 | page = pageCount - 1;
173 | }
174 | pageView.setCurrentItem(page, false);
175 | }
176 |
177 | @Override
178 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
179 | Log.d(TAG, "onPageScrolled() called with: position = [" + position + "], positionOffset = [" + positionOffset + "], positionOffsetPixels = [" + positionOffsetPixels + "]");
180 | }
181 |
182 | @Override
183 | public void onPageSelected(int position) {
184 | Log.d(TAG, "onPageSelected() called with: position = [" + position + "]");
185 | }
186 |
187 | @Override
188 | public void onPageScrollStateChanged(int state) {
189 | Log.d(TAG, "onPageScrollStateChanged() called with: state = [" + state + "]");
190 | }
191 |
192 | @Override
193 | public void refreshFragment(BaseTransformer baseTransformer) {
194 | if (mainAdapter == null) {
195 | return;
196 | }
197 | if (mainAdapter.getPageRow() * mainAdapter.getPageColumn() == 1) {
198 | pageView.addPageTransformer(baseTransformer);
199 | }
200 | }
201 |
202 | @Override
203 | public void onDestroyView() {
204 | if (pageView != null) {
205 | pageView.release();
206 | }
207 | super.onDestroyView();
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ckr/pagesnaphelper/widget/MyViewPager.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pagesnaphelper.widget;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.ViewPager;
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 |
8 |
9 | public class MyViewPager extends ViewPager {
10 | private boolean isCanScroll = false;
11 |
12 | public MyViewPager(Context context) {
13 | super(context);
14 | }
15 |
16 | public MyViewPager(Context context, AttributeSet attrs) {
17 | super(context, attrs);
18 | }
19 |
20 | public void setScanScroll(boolean isCanScroll) {
21 | this.isCanScroll = isCanScroll;
22 | }
23 |
24 | @Override
25 | public void scrollTo(int x, int y) {
26 | super.scrollTo(x, y);
27 | }
28 |
29 | @Override
30 | public void setCurrentItem(int item) {
31 | super.setCurrentItem(item, false);
32 | }
33 |
34 | @Override
35 | public void setCurrentItem(int item, boolean smoothScroll) {
36 | super.setCurrentItem(item, false);
37 | }
38 |
39 | @Override
40 | public boolean onTouchEvent(MotionEvent arg0) {
41 | if (isCanScroll) {
42 | return super.onTouchEvent(arg0);
43 | } else {
44 | return false;
45 | }
46 | }
47 |
48 | @Override
49 | public boolean onInterceptTouchEvent(MotionEvent arg0) {
50 | if (isCanScroll) {
51 | return super.onInterceptTouchEvent(arg0);
52 | } else {
53 | return false;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_color1.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_color2.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_color3.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_color4.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_color5.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_color6.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_delete.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
-
5 |
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_tablayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_textview.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_point_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_point_unselected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/item_horizontal_grid.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
20 |
21 |
33 |
34 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/item_horizontal_grid2.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
20 |
21 |
33 |
34 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_horizontal_grid.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_horizontal_grid2.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_horizontal_linear.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
26 |
27 |
32 |
33 |
44 |
45 |
53 |
54 |
67 |
68 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_vertical_grid.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_vertical_linear.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_horizontal_grid.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
20 |
21 |
33 |
34 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_horizontal_grid2.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
20 |
21 |
33 |
34 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_horizontal_linear.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
21 |
22 |
31 |
32 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_vertical_grid.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
22 |
23 |
33 |
34 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_vertical_linear.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
29 |
30 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-xxhdpi/ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-xxhdpi/ic_picture.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_picture1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-xxhdpi/ic_picture1.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-en/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PageSnapHelper
3 |
4 |
5 | - CAROUSEL
6 | - HG
7 | - VL
8 | - VG
9 | - HG2
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
8 |
9 | #6c3d61
10 | #6c87e1
11 | #8c6472
12 | #7b6f45
13 | #517c3f
14 | #478384
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 翻页
3 |
4 |
5 | - 无限轮播
6 | - 水平网格
7 | - 竖直线性
8 | - 竖直网格
9 | - 水平网格2
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | apply from:"config.gradle"
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.2'
9 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
10 | classpath 'com.novoda:bintray-release:0.6.1'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/config.gradle:
--------------------------------------------------------------------------------
1 | //全局参数
2 | ext {
3 | appConfig = [
4 | versionCode : 122,
5 | versionName : "1.2.2",
6 | applicationId: "com.ckr.pageView",
7 | ]
8 |
9 | androidConfig = [
10 | compileSdkVersion: 25,
11 | buildToolsVersion: "25.0.3",
12 | minSdkVersion : 15,
13 | targetSdkVersion : 25,
14 | ]
15 |
16 | supportVersion = "25.3.1"
17 |
18 | pageViewConfig = [
19 | versionCode: 133,
20 | versionName: "1.2.13",
21 | publishVersion: "1.2.13"
22 | ]
23 | }
--------------------------------------------------------------------------------
/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 | android.enableAapt2=false
19 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/pageview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/pageview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.novoda.bintray-release'
3 |
4 |
5 | def siteUrl = 'https://github.com/ckrgithub/PageRecyclerView'
6 | publish {
7 | repoName = 'Page'
8 | userOrg = 'ckrjfrog'
9 | groupId = 'ckrjfrog.Page'
10 | artifactId = 'PageView'
11 | publishVersion = rootProject.pageViewConfig.publishVersion
12 | desc = '自定义recyclerView实现分页功能'
13 | website = siteUrl
14 | }
15 | tasks.withType(Javadoc) {
16 | options.addStringOption('Xdoclint:none', '-quiet')
17 | options.addStringOption('encoding', 'UTF-8')
18 | options.addStringOption('charSet', 'UTF-8')
19 | }
20 |
21 | android {
22 | compileSdkVersion rootProject.ext.androidConfig.compileSdkVersion
23 | buildToolsVersion rootProject.ext.androidConfig.buildToolsVersion
24 |
25 | defaultConfig {
26 | minSdkVersion rootProject.ext.androidConfig.minSdkVersion
27 | targetSdkVersion rootProject.ext.androidConfig.targetSdkVersion
28 | versionCode rootProject.pageViewConfig.versionCode
29 | versionName rootProject.pageViewConfig.versionName
30 | }
31 |
32 | buildTypes {
33 | release {
34 | minifyEnabled false
35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
36 | buildConfigField("boolean","isDebug","false")
37 | }
38 | debug{
39 | minifyEnabled false
40 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
41 | buildConfigField("boolean","isDebug","true")
42 | }
43 | }
44 | lintOptions {
45 | abortOnError false
46 | }
47 | }
48 |
49 | dependencies {
50 | compile fileTree(dir: 'libs', include: ['*.jar'])
51 | compile "com.android.support:appcompat-v7:$rootProject.supportVersion"
52 | provided "com.android.support:recyclerview-v7:$rootProject.supportVersion"
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/pageview/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 |
--------------------------------------------------------------------------------
/pageview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/pageview/src/main/java/android/support/v7/widget/PageRecyclerView.java:
--------------------------------------------------------------------------------
1 | package android.support.v7.widget;
2 |
3 | import android.content.Context;
4 | import android.content.res.Configuration;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.os.Parcelable;
8 | import android.support.annotation.IntRange;
9 | import android.support.annotation.NonNull;
10 | import android.util.AttributeSet;
11 | import android.view.MotionEvent;
12 | import android.view.View;
13 | import android.view.animation.Interpolator;
14 |
15 | import com.ckr.pageview.adapter.BasePageAdapter;
16 | import com.ckr.pageview.adapter.OnPageDataListener;
17 | import com.ckr.pageview.transform.DepthPageTransformer;
18 | import com.ckr.pageview.transform.StackTransformer;
19 |
20 | import java.lang.reflect.Field;
21 | import java.lang.reflect.InvocationTargetException;
22 | import java.lang.reflect.Method;
23 | import java.math.RoundingMode;
24 | import java.text.DecimalFormat;
25 |
26 | import static com.ckr.pageview.utils.PageLog.Logd;
27 | import static com.ckr.pageview.utils.PageLog.Loge;
28 | import static com.ckr.pageview.utils.PageLog.Logi;
29 | import static com.ckr.pageview.utils.PageLog.Logv;
30 |
31 | /**
32 | * Created by PC大佬 on 2018/7/14.
33 | */
34 |
35 | public class PageRecyclerView extends RecyclerView implements RecyclerView.ChildDrawingOrderCallback {
36 | private static final String TAG = "PageRecyclerView";
37 | private static final String ARGS_SCROLL_OFFSET = "mScrollOffset";
38 | private static final String ARGS_PAGE = "mCurrentPage";
39 | private static final String ARGS_SUPER = "super";
40 | private static final String ARGS_WIDTH = "mScrollWidth";
41 | private static final String ARGS_HEIGHT = "mScrollHeight";
42 | private static final String ARGS_FORWARD_DIRECTION = "mForwardDirection";
43 | private static final String ARGS_SAVE_STATE = "isSaveState";
44 | private static final int DEFAULT_VELOCITY = 4000;
45 | private static final int MODE_DEFAULT = 0;
46 | private static final int MODE_AUTO_WIDTH = 1;
47 | private static final int MODE_AUTO_HEIGHT = 2;
48 | private static final int INIT_VALUE = -1;
49 | private int mVelocity = DEFAULT_VELOCITY;
50 | private int mScrollWidth;
51 | private int mScrollHeight;
52 | private int mOrientation;
53 | private int mScrollOffset;//滚动偏移量
54 | private int mDragOffset;//拖动时偏移量
55 | private int mScrollState;
56 | private int mCurrentPage;
57 | private int mLastPage;
58 | private boolean mFirstLayout = true;
59 | private boolean mIsLooping = false;
60 | private boolean isSliding;//是否是滑动
61 | private boolean mForwardDirection;//滑动方向
62 | private DecimalFormat mDecimalFormat;
63 | private PageRecyclerView.OnPageChangeListener mOnPageChangeListener;
64 | private PageRecyclerView.PageTransformer mPageTransformer;
65 | private boolean isSaveState;
66 | private boolean isOnSizeChanged;
67 | private int mSize = INIT_VALUE;
68 | private int mMeasureMode = MODE_DEFAULT;
69 | private int maxScrollDuration = 0;
70 | private int minScrollDuration = 0;
71 | private boolean enableTouchScroll = true;
72 | private Method smoothScrollBy = null;
73 | private Field mViewFlingerField = null;
74 |
75 | private static final Interpolator mQuinticInterpolator = new Interpolator() {
76 | @Override
77 | public float getInterpolation(float t) {
78 | t -= 1.0f;
79 | return t * t * t * t * t + 1.0f;
80 | }
81 | };
82 |
83 | public PageRecyclerView(Context context) {
84 | this(context, null);
85 | }
86 |
87 | public PageRecyclerView(Context context, AttributeSet attrs) {
88 | this(context, attrs, 0);
89 | }
90 |
91 | public PageRecyclerView(Context context, AttributeSet attrs, int defStyle) {
92 | super(context, attrs, defStyle);
93 | init();
94 | }
95 |
96 | public void setMaxScrollDuration(int maxScrollDuration) {
97 | this.maxScrollDuration = maxScrollDuration;
98 | }
99 |
100 | public void setMinScrollDuration(int minScrollDuration) {
101 | this.minScrollDuration = minScrollDuration;
102 | }
103 |
104 | public void setEnableTouchScroll(boolean enableTouchScroll) {
105 | this.enableTouchScroll = enableTouchScroll;
106 | }
107 |
108 | private void init() {
109 | mDecimalFormat = new DecimalFormat("0.00");
110 | mDecimalFormat.setRoundingMode(RoundingMode.HALF_UP);
111 | getScrollerByReflection();
112 | setOnFlingListener(new PageRecyclerView.OnPageFlingListener());
113 | addOnLayoutChangeListener(new OnLayoutChangeListener() {
114 | @Override
115 | public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
116 | removeOnLayoutChangeListener(this);
117 | int paddingLeft = getPaddingLeft();
118 | int paddingRight = getPaddingRight();
119 | int paddingTop = getPaddingTop();
120 | int paddingBottom = getPaddingBottom();
121 | Logd(TAG, "onLayoutChange: paddingLeft:" + paddingLeft + ",paddingRight:" + paddingRight + ",paddingTop:" + paddingTop + ",paddingBottom:" + paddingBottom);
122 | mScrollWidth = getWidth() - paddingLeft - paddingRight;
123 | mScrollHeight = getHeight() - paddingTop - paddingBottom;
124 | Logd(TAG, "onLayoutChange: mScrollWidth:" + mScrollWidth + ",mScrollHeight:" + mScrollHeight
125 | + ",mCurrentPage:" + mCurrentPage + ",mFirstLayout:" + mFirstLayout + ",isSaveState:" + isSaveState
126 | + ",mForwardDirection:" + mForwardDirection);
127 | label:
128 | if (mFirstLayout) {
129 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
130 | notifySizeChanged(mScrollWidth);
131 | mMeasureMode = MODE_AUTO_WIDTH;
132 | int mOffset = mScrollOffset;
133 | mScrollOffset = mCurrentPage * mScrollWidth;
134 | if (mScrollWidth == 0) {
135 | break label;
136 | }
137 | if (mIsLooping && !isSaveState) {
138 | PageRecyclerView.super.scrollToPosition(mCurrentPage);
139 | } else {
140 | if (!mIsLooping && isOnSizeChanged) {//屏幕大小变化,如:横竖屏切换
141 | int lastScrollOffset = mCurrentPage * mScrollWidth;
142 | mCurrentPage = 0;
143 | mScrollOffset = 0;
144 | smoothScrollBy(lastScrollOffset, 0, calculateTimeForHorizontalScrolling(mVelocity, Math.abs(lastScrollOffset)));
145 | } else {
146 | int remainder = mOffset % mScrollWidth;
147 | Loge(TAG, "onLayoutChange: remainder:" + remainder);
148 | if (remainder != 0) {//滑动中,页面切换回来后继续惯性滑动
149 | mScrollOffset = mOffset;
150 | int moveX = mScrollWidth - remainder;
151 | if (mForwardDirection) {
152 | smoothScrollBy(moveX, 0, calculateTimeForHorizontalScrolling(mVelocity, Math.abs(moveX)));
153 | } else {
154 | smoothScrollBy(-remainder, 0, calculateTimeForHorizontalScrolling(mVelocity, Math.abs(remainder)));
155 | }
156 | }
157 | }
158 | }
159 | } else {
160 | notifySizeChanged(mScrollHeight);
161 | mMeasureMode = MODE_AUTO_HEIGHT;
162 | int mOffset = mScrollOffset;
163 | mScrollOffset = mCurrentPage * mScrollHeight;
164 | if (mScrollHeight == 0) {
165 | break label;
166 | }
167 | if (mIsLooping && !isSaveState) {
168 | PageRecyclerView.super.scrollToPosition(mCurrentPage);
169 | } else {
170 | if (!mIsLooping && isOnSizeChanged) {
171 | int lastScrollOffset = mCurrentPage * mScrollHeight;
172 | mCurrentPage = 0;
173 | mScrollOffset = 0;
174 | smoothScrollBy(0, lastScrollOffset, calculateTimeForHorizontalScrolling(mVelocity, Math.abs(lastScrollOffset)));
175 | } else {
176 | int remainder = mOffset % mScrollHeight;
177 | if (remainder != 0) {
178 | mScrollOffset = mOffset;
179 | int moveY = mScrollHeight - remainder;
180 | if (mForwardDirection) {
181 | smoothScrollBy(0, moveY, calculateTimeForVerticalScrolling(mVelocity, Math.abs(moveY)));
182 | } else {
183 | smoothScrollBy(0, -remainder, calculateTimeForVerticalScrolling(mVelocity, Math.abs(remainder)));
184 | }
185 | }
186 | }
187 | }
188 | }
189 | }
190 | mFirstLayout = false;
191 | isSaveState = false;
192 | Logd(TAG, "onLayoutChange: mScrollOffset:" + mScrollOffset);
193 | }
194 | });
195 | setChildDrawingOrderCallback(this);
196 | }
197 |
198 | /**
199 | * {@link ViewFlinger}
200 | */
201 | private void getScrollerByReflection() {
202 | Class> c = null;
203 | Class> ViewFlingerClass = null;
204 | try {
205 | c = Class.forName(getClass().getSuperclass().getName());
206 | mViewFlingerField = c.getDeclaredField("mViewFlinger");
207 | mViewFlingerField.setAccessible(true);
208 | ViewFlingerClass = Class.forName(mViewFlingerField.getType().getName());
209 | smoothScrollBy = ViewFlingerClass.getDeclaredMethod("smoothScrollBy",
210 | int.class, int.class, int.class, Interpolator.class);
211 | smoothScrollBy.setAccessible(true);
212 | } catch (ClassNotFoundException e) {
213 | e.printStackTrace();
214 | } catch (NoSuchFieldException e) {
215 | e.printStackTrace();
216 | } catch (NoSuchMethodException e) {
217 | e.printStackTrace();
218 | }
219 | }
220 |
221 | private void notifySizeChanged(int size) {
222 | Logd(TAG, "notifySizeChanged: size:" + size);
223 | if (this.mSize != size) {
224 | Adapter adapter = getAdapter();
225 | if (adapter != null && adapter instanceof BasePageAdapter) {
226 | BasePageAdapter pageAdapter = (BasePageAdapter) adapter;
227 | if (pageAdapter.isAutoSize()) {
228 | pageAdapter.notifySizeChanged(size);
229 | Loge(TAG, "notifySizeChanged: s:" + this.mSize);
230 | if (this.mSize == INIT_VALUE) {
231 | setAdapter(adapter);
232 | }
233 | }
234 | }
235 | }
236 | this.mSize = size;
237 | }
238 |
239 | @Override
240 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
241 | super.onSizeChanged(w, h, oldw, oldh);
242 | Logi(TAG, "onSizeChanged: w:" + w + ",h:" + h);
243 | isOnSizeChanged = true;
244 | int paddingLeft = getPaddingLeft();
245 | int paddingRight = getPaddingRight();
246 | int paddingTop = getPaddingTop();
247 | int paddingBottom = getPaddingBottom();
248 | mScrollWidth = getWidth() - paddingLeft - paddingRight;
249 | mScrollHeight = getHeight() - paddingTop - paddingBottom;
250 |
251 | if (mIsLooping) {
252 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
253 | mScrollOffset = mCurrentPage * mScrollWidth;
254 | } else {
255 | mScrollOffset = mCurrentPage * mScrollHeight;
256 | }
257 | post(new Runnable() {
258 | @Override
259 | public void run() {
260 | scrollToPosition(mCurrentPage);
261 | }
262 | });
263 | }
264 | }
265 |
266 | @Override
267 | public int onGetChildDrawingOrder(int childCount, int i) {
268 | Logv(TAG, "onGetChildDrawingOrder: childCount:" + childCount + ",i:" + i);
269 | if (mPageTransformer != null) {
270 | String name = mPageTransformer.getClass().getName();
271 | if (name == StackTransformer.class.getName()
272 | || name == DepthPageTransformer.class.getName()) {//自定义Item绘制顺序
273 | if (childCount == 2) {
274 | return 0 == i ? childCount - 1 : 0;
275 | }
276 | }
277 | }
278 | return i;
279 | }
280 |
281 | @Override
282 | protected void onConfigurationChanged(Configuration newConfig) {
283 | super.onConfigurationChanged(newConfig);
284 | }
285 |
286 | public int getSize() {
287 | return mSize;
288 | }
289 |
290 | public int getCurrentPage() {
291 | return mCurrentPage;
292 | }
293 |
294 | public void setOrientation(@OnPageDataListener.LayoutOrientation int mOrientation) {
295 | this.mOrientation = mOrientation;
296 | }
297 |
298 | public void setLooping(boolean isLooping) {
299 | this.mIsLooping = isLooping;
300 | }
301 |
302 | public void setVelocity(@IntRange(from = 1) int mVelocity) {
303 | this.mVelocity = mVelocity;
304 | }
305 |
306 | private void smoothScrollBy(int dx, int dy, int duration) {
307 | try {
308 | smoothScrollBy.invoke(mViewFlingerField.get(this), dx, dy, duration, mQuinticInterpolator);
309 | } catch (IllegalAccessException e) {
310 | e.printStackTrace();
311 | } catch (InvocationTargetException e) {
312 | e.printStackTrace();
313 | }
314 | }
315 |
316 | @Override
317 | public boolean onInterceptTouchEvent(MotionEvent e) {
318 | if (!enableTouchScroll) {
319 | return false;
320 | }
321 | return super.onInterceptTouchEvent(e);
322 | }
323 |
324 | @Override
325 | public boolean onTouchEvent(MotionEvent e) {
326 | if (!enableTouchScroll) {
327 | return true;
328 | }
329 | return super.onTouchEvent(e);
330 | }
331 |
332 | @Override
333 | public void onScrollStateChanged(int state) {
334 | Logd(TAG, "onScrollStateChanged,mScrollState:" + state);
335 | this.mScrollState = state;
336 | if (mOnPageChangeListener != null) {
337 | mOnPageChangeListener.onPageScrollStateChanged(state);
338 | }
339 | switch (state) {
340 | case SCROLL_STATE_IDLE://0
341 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
342 | if (mScrollWidth != 0) {
343 | if (isSliding) {//放手后的滑动
344 | int t = mScrollOffset / mScrollWidth;
345 | int deltaX = mScrollOffset - t * mScrollWidth;
346 | if (!mForwardDirection) {//向前
347 | deltaX = deltaX - mScrollWidth;
348 | } else {//向后
349 | }
350 | Logd(TAG, "isSliding=true,deltaX:" + deltaX + ",mScrollOffset:" + mScrollOffset);
351 | moveX(deltaX);
352 | } else {//用手拖动
353 | Logd(TAG, "isSliding=false,mDragOffset:" + mDragOffset);
354 | moveX(mDragOffset);
355 | }
356 | }
357 | } else {
358 | if (mScrollHeight != 0) {
359 | if (isSliding) {//放手后的滑动
360 | int t = mScrollOffset / mScrollHeight;
361 | int deltaY = mScrollOffset - t * mScrollHeight;
362 | if (!mForwardDirection) {
363 | deltaY = deltaY - mScrollHeight;
364 | } else {
365 | }
366 | Logd(TAG, "isSliding=true,deltaY:" + deltaY + ",mScrollOffset:" + mScrollOffset);
367 | moveY(deltaY);
368 | } else {//用手拖动
369 | Logd(TAG, "isSliding=false,mDragOffset:" + mDragOffset);
370 | moveY(mDragOffset);
371 | }
372 | }
373 | }
374 | mDragOffset = 0;
375 | isSliding = false;
376 | break;
377 | case SCROLL_STATE_DRAGGING://1
378 | break;
379 | case SCROLL_STATE_SETTLING://2
380 | isSliding = true;
381 | break;
382 | }
383 | }
384 |
385 | private void moveX(int deltaX) {
386 | Logd(TAG, "move,deltaX:" + deltaX + ",mCurrentPage:" + mCurrentPage);
387 | if (Math.abs(deltaX) == 0 || Math.abs(deltaX) == mScrollWidth) {
388 | return;
389 | }
390 | int itemWidth = mScrollWidth / 2;
391 | if (deltaX >= itemWidth) {//下一页
392 | int moveX = mScrollWidth - deltaX;
393 | Logd(TAG, "move,deltaX:" + moveX);
394 | smoothScrollBy(moveX, 0, calculateTimeForHorizontalScrolling(mVelocity, Math.abs(moveX)));
395 | } else if (deltaX <= -itemWidth) {//上一页
396 | int moveX = -(mScrollWidth + deltaX);
397 | Logd(TAG, "move,deltaX:" + moveX);
398 | smoothScrollBy(moveX, 0, calculateTimeForHorizontalScrolling(mVelocity, Math.abs(moveX)));
399 | } else {//回弹
400 | Logd(TAG, "move,deltaX:" + deltaX);
401 | smoothScrollBy(-deltaX, 0, calculateTimeForHorizontalScrolling(mVelocity, Math.abs(deltaX)));
402 | }
403 | }
404 |
405 | private void moveY(int deltaY) {
406 | Logd(TAG, "move,deltaY:" + deltaY + ",mCurrentPage:" + mCurrentPage);
407 | if (Math.abs(deltaY) == 0 || Math.abs(deltaY) == mScrollHeight) {
408 | return;
409 | }
410 | int itemHeight = mScrollHeight / 2;
411 | if (deltaY >= itemHeight) {//下一页
412 | int moveY = mScrollHeight - deltaY;
413 | Logd(TAG, "move,deltaY:" + moveY);
414 | smoothScrollBy(0, moveY, calculateTimeForVerticalScrolling(mVelocity, Math.abs(moveY)));
415 | } else if (deltaY <= -itemHeight) {//上一页
416 | int moveY = -(mScrollHeight + deltaY);
417 | Logd(TAG, "move,deltaY:" + moveY);
418 | smoothScrollBy(0, moveY, calculateTimeForVerticalScrolling(mVelocity, Math.abs(moveY)));
419 | } else {//回弹
420 | Logd(TAG, "move,deltaY:" + deltaY);
421 | smoothScrollBy(0, -deltaY, calculateTimeForVerticalScrolling(mVelocity, Math.abs(deltaY)));
422 | }
423 | }
424 |
425 | @Override
426 | public void onScrolled(int dx, int dy) {
427 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
428 | mScrollOffset += dx;
429 | if (mScrollState == SCROLL_STATE_DRAGGING) {
430 | mDragOffset += dx;
431 | }
432 | if (dx < 0) {
433 | mForwardDirection = false;
434 | } else if (dx > 0) {
435 | mForwardDirection = true;
436 | }
437 | Logd(TAG, "onScrolled: mScrollOffset:" + mScrollOffset + ",mCurrentPage:" + mCurrentPage +
438 | ",mDragOffset:" + mDragOffset + ",mForwardDirection:" + mForwardDirection + ",mScrollWidth:" + mScrollWidth);
439 | if (mScrollWidth == 0) {
440 | return;
441 | }
442 | mLastPage = mCurrentPage;
443 | if (mScrollOffset % mScrollWidth == 0) {
444 | mCurrentPage = mScrollOffset / mScrollWidth;
445 | } else if (dx < 0) {
446 | int targetPage = mScrollOffset / mScrollWidth + 1;
447 | mCurrentPage = Math.min(targetPage, mCurrentPage);
448 | } else {
449 | int targetPage = mScrollOffset / mScrollWidth;
450 | mCurrentPage = Math.max(targetPage, mCurrentPage);
451 | }
452 | if (mOnPageChangeListener != null) {
453 | int positionOffsetPixels = mScrollOffset % mScrollWidth;
454 | float positionOffset = Float.parseFloat(mDecimalFormat.format(mScrollOffset % mScrollWidth / (double) mScrollWidth));
455 | mOnPageChangeListener.onPageScrolled(mCurrentPage, positionOffset, positionOffsetPixels);
456 | if (mLastPage - mCurrentPage != 0 || positionOffset == 0) {
457 | mOnPageChangeListener.onPageSelected(mCurrentPage);
458 | }
459 | }
460 | if (mPageTransformer != null) {
461 | int scrollX = getScrollX();
462 | int childCount = getChildCount();
463 | for (int i = 0; i < childCount; i++) {
464 | View child = getChildAt(i);
465 | int left = child.getLeft();
466 | float transformPos = (left - scrollX - getPaddingLeft()) / (float) mScrollWidth;
467 | boolean nextPage = mScrollOffset >= mLastPage * mScrollWidth;
468 | Logd(TAG, "onScrolled: transformPos:" + transformPos + ",left:" + left
469 | + ",mScrollWidth:" + mScrollWidth + ",childCount:" + childCount
470 | + ",nextPage:" + nextPage);
471 | mPageTransformer.transformPage(child, transformPos, nextPage, mOrientation);
472 | }
473 | }
474 | } else {
475 | mScrollOffset += dy;
476 | if (mScrollState == SCROLL_STATE_DRAGGING) {
477 | mDragOffset += dy;
478 | }
479 | if (dy < 0) {
480 | mForwardDirection = false;
481 | } else if (dy > 0) {
482 | mForwardDirection = true;
483 | }
484 | Logd(TAG, "onScrolled: mScrollOffset:" + mScrollOffset + ",mCurrentPage:" + mCurrentPage +
485 | ",mDragOffset:" + mDragOffset + ",mForwardDirection:" + mForwardDirection + ",mScrollHeight:" + mScrollHeight);
486 | if (mScrollHeight == 0) {
487 | return;
488 | }
489 | mLastPage = mCurrentPage;
490 | if (mScrollOffset % mScrollHeight == 0) {
491 | mCurrentPage = mScrollOffset / mScrollHeight;
492 | } else if (dy < 0) {
493 | int targetPage = mScrollOffset / mScrollHeight + 1;
494 | mCurrentPage = Math.min(targetPage, mCurrentPage);
495 | } else {
496 | int targetPage = mScrollOffset / mScrollHeight;
497 | mCurrentPage = Math.max(targetPage, mCurrentPage);
498 | }
499 | if (mOnPageChangeListener != null) {
500 | int positionOffsetPixels = mScrollOffset % mScrollHeight;
501 | float positionOffset = Float.parseFloat(mDecimalFormat.format(mScrollOffset % mScrollHeight / (double) mScrollHeight));
502 | mOnPageChangeListener.onPageScrolled(mCurrentPage, positionOffset, positionOffsetPixels);
503 | if (mLastPage - mCurrentPage != 0 || positionOffset == 0) {
504 | mOnPageChangeListener.onPageSelected(mCurrentPage);
505 | }
506 | }
507 | if (mPageTransformer != null) {
508 | int scrollY = getScrollY();
509 | int childCount = getChildCount();
510 | for (int i = 0; i < childCount; i++) {
511 | View child = getChildAt(i);
512 | int top = child.getTop();
513 | float transformPos = (top - scrollY - getPaddingTop()) / (float) mScrollHeight;
514 | boolean nextPage = mScrollOffset >= mLastPage * mScrollHeight;
515 | Logd(TAG, "onScrolled: transformPos:" + transformPos + ",top:" + top
516 | + ",mScrollHeight:" + mScrollHeight + ",childCount:" + childCount
517 | + ",nextPage:" + nextPage);
518 | mPageTransformer.transformPage(child, transformPos, nextPage, mOrientation);
519 | }
520 | }
521 | }
522 | Logd(TAG, "onScrolled,mCurrentPage:" + mCurrentPage);
523 | }
524 |
525 | public void scrollToEndPage(@IntRange(from = 0) int page) {
526 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
527 | mScrollOffset = page * mScrollWidth;
528 | } else {
529 | mScrollOffset = page * mScrollHeight;
530 | }
531 | super.scrollToPosition(getAdapter().getItemCount() - 1);
532 | }
533 |
534 | public void scrollToBeginPage() {
535 | mScrollOffset = 0;
536 | super.scrollToPosition(0);
537 | }
538 |
539 | public void scrollToPage(@IntRange(from = 0) int page, boolean smoothScroll) {
540 | if (mCurrentPage == page) {
541 | return;
542 | }
543 | if (mFirstLayout) {
544 | mCurrentPage = page;
545 | } else {
546 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
547 | int scrollX = page * mScrollWidth;
548 | int moveX = scrollX - mScrollOffset;
549 | if (mScrollWidth == 0) {//中断recyclerView滚动
550 | mCurrentPage = page;
551 | return;
552 | }
553 | if (smoothScroll) {
554 | smoothScrollBy(moveX, 0, calculateTimeForHorizontalScrolling(mVelocity, moveX));
555 | } else {
556 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {//compat recyclerview-v7-26.1.0 above
557 | scrollBy(moveX, 0);
558 | } else {
559 | smoothScrollBy(moveX, 0, 0);
560 | }
561 | }
562 | } else {
563 | int scrollY = page * mScrollHeight;
564 | int moveY = scrollY - mScrollOffset;
565 | if (mScrollHeight == 0) {//中断recyclerView滚动
566 | mCurrentPage = page;
567 | return;
568 | }
569 | if (smoothScroll) {
570 | smoothScrollBy(0, moveY, calculateTimeForVerticalScrolling(mVelocity, moveY));
571 | } else {
572 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {//compat recyclerview-v7-26.1.0
573 | scrollBy(0, moveY);
574 | } else {
575 | smoothScrollBy(0, moveY, 0);
576 | }
577 | }
578 | }
579 | }
580 | Logd(TAG, "scrollToPage: mCurrentPage:" + mCurrentPage + ",page:" + page);
581 | }
582 |
583 | private class OnPageFlingListener extends OnFlingListener {
584 | /**
585 | * {@link android.support.v7.widget.PagerSnapHelper}
586 | *
587 | * @param velocityX
588 | * @param velocityY
589 | * @return
590 | */
591 | @Override
592 | public boolean onFling(int velocityX, int velocityY) {
593 | LayoutManager layoutManager = getLayoutManager();
594 | if (layoutManager == null) {
595 | return false;
596 | }
597 | Adapter adapter = getAdapter();
598 | if (adapter == null) {
599 | return false;
600 | }
601 | int minFlingVelocity = getMinFlingVelocity();
602 | boolean fling = (Math.abs(velocityY) > minFlingVelocity || Math.abs(velocityX) > minFlingVelocity)
603 | && snapFromFling(layoutManager, velocityX, velocityY);
604 | return fling;
605 | }
606 | }
607 |
608 | private boolean snapFromFling(@NonNull LayoutManager layoutManager, int velocityX,
609 | int velocityY) {
610 | final int itemCount = layoutManager.getItemCount();
611 | if (itemCount == 0) {
612 | return false;
613 | }
614 | Logd(TAG, "snapFromFling,mScrollState:" + this.mScrollState + ",velocityX:" + velocityX + ",velocityY:" + velocityY);
615 | if (SCROLL_STATE_DRAGGING == this.mScrollState) {
616 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
617 | int moveX = getMoveDistance(mScrollOffset, mScrollWidth);
618 | Loge(TAG, "snapFromFling: deltaX:" + moveX + ",mCurrentPage:" + mCurrentPage);
619 | if (Math.abs(moveX) != 0 && Math.abs(moveX) != mScrollWidth) {
620 | smoothScrollBy(moveX, 0, calculateTimeForHorizontalScrolling(velocityX, moveX));
621 | return true;
622 | }
623 | } else {
624 | int moveY = getMoveDistance(mScrollOffset, mScrollHeight);
625 | Loge(TAG, "snapFromFling: deltaY:" + moveY + ",mCurrentPage:" + mCurrentPage);
626 | if (Math.abs(moveY) != 0 && Math.abs(moveY) != mScrollHeight) {
627 | smoothScrollBy(0, moveY, calculateTimeForVerticalScrolling(velocityY, moveY));
628 | return true;
629 | }
630 | }
631 | }
632 | return false;
633 | }
634 |
635 | private int getMoveDistance(int scrollDistance, int length) {
636 | int moveDistance;
637 | if (mForwardDirection) {
638 | int targetPage = scrollDistance / length + 1;
639 | moveDistance = targetPage * length - scrollDistance;
640 | } else {
641 | int targetPage = scrollDistance / length;
642 | moveDistance = targetPage * length - scrollDistance;
643 | }
644 | return moveDistance;
645 | }
646 |
647 | /**
648 | * {@link android.support.v4.view.ViewPager}的smoothScrollTo(int,int ,int)
649 | *
650 | * @param velocity
651 | * @param dx
652 | * @return
653 | */
654 | private int calculateTimeForHorizontalScrolling(int velocity, int dx) {
655 | final int width = mScrollWidth;
656 | final int halfWidth = width / 2;
657 | final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);
658 | final float distance = halfWidth + halfWidth
659 | * distanceInfluenceForSnapDuration(distanceRatio);
660 | int duration;
661 | velocity = Math.abs(velocity);
662 | if (velocity > 0) {
663 | duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
664 | } else {
665 | final float pageWidth = width * 1.0f;
666 | final float pageDelta = (float) Math.abs(dx) / (pageWidth);
667 | duration = (int) ((pageDelta + 1) * 100);
668 | }
669 | duration = Math.max(Math.min(duration, maxScrollDuration), minScrollDuration);
670 | return duration;
671 | }
672 |
673 | private int calculateTimeForVerticalScrolling(int velocity, int dy) {
674 | final int height = mScrollHeight;
675 | final int halfHeight = height / 2;
676 | final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / height);
677 | final float distance = halfHeight + halfHeight
678 | * distanceInfluenceForSnapDuration(distanceRatio);
679 | int duration;
680 | velocity = Math.abs(velocity);
681 | if (velocity > 0) {
682 | duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
683 | } else {
684 | final float pageWidth = height * 1.0f;
685 | final float pageDelta = (float) Math.abs(dy) / (pageWidth);
686 | duration = (int) ((pageDelta + 1) * 100);
687 | }
688 | duration = Math.max(Math.min(duration, maxScrollDuration), minScrollDuration);
689 | return duration;
690 | }
691 |
692 | private float distanceInfluenceForSnapDuration(float f) {
693 | f -= 0.5f; // center the values about 0.
694 | f *= 0.3f * Math.PI / 2.0f;
695 | return (float) Math.sin(f);
696 | }
697 |
698 | @Override
699 | protected void onRestoreInstanceState(Parcelable state) {
700 | Bundle bundle = (Bundle) state;
701 | mScrollOffset = bundle.getInt(ARGS_SCROLL_OFFSET, 0);
702 | mCurrentPage = bundle.getInt(ARGS_PAGE, 0);
703 | mScrollWidth = bundle.getInt(ARGS_WIDTH, 0);
704 | mScrollHeight = bundle.getInt(ARGS_HEIGHT, 0);
705 | mForwardDirection = bundle.getBoolean(ARGS_FORWARD_DIRECTION, true);
706 | isSaveState = bundle.getBoolean(ARGS_SAVE_STATE, false);
707 | Parcelable parcelable = bundle.getParcelable(ARGS_SUPER);
708 | Logv(TAG, "onLayoutChange onRestoreInstanceState: mOrientation:" + mOrientation + ",mScrollOffset:" + mScrollOffset + ",mScrollWidth:" + mScrollWidth
709 | + ",mScrollHeight:" + mScrollHeight + ",mCurrentPage:" + mCurrentPage + ",mForwardDirection:" + mForwardDirection);
710 | super.onRestoreInstanceState(parcelable);
711 | }
712 |
713 | @Override
714 | protected Parcelable onSaveInstanceState() {
715 | Logv(TAG, "onLayoutChange onSaveInstanceState: mOrientation:" + mOrientation + ",mScrollOffset:" + mScrollOffset + ",mScrollWidth:" + mScrollWidth
716 | + ",mScrollHeight:" + mScrollHeight + ",mCurrentPage:" + mCurrentPage + ",mForwardDirection:" + mForwardDirection);
717 | Bundle bundle = new Bundle();
718 | bundle.putInt(ARGS_SCROLL_OFFSET, mScrollOffset);
719 | bundle.putInt(ARGS_PAGE, mCurrentPage);
720 | bundle.putInt(ARGS_WIDTH, mScrollWidth);
721 | bundle.putInt(ARGS_HEIGHT, mScrollHeight);
722 | bundle.putBoolean(ARGS_FORWARD_DIRECTION, mForwardDirection);
723 | bundle.putBoolean(ARGS_SAVE_STATE, true);
724 | bundle.putParcelable(ARGS_SUPER, super.onSaveInstanceState());
725 | return bundle;
726 | }
727 |
728 | public void addOnPageChangeListener(PageRecyclerView.OnPageChangeListener listener) {
729 | this.mOnPageChangeListener = listener;
730 | }
731 |
732 | public void addPageTransformer(PageRecyclerView.PageTransformer pageTransformer) {
733 | this.mPageTransformer = pageTransformer;
734 | }
735 |
736 | public interface OnPageChangeListener {
737 | void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
738 |
739 | void onPageSelected(int position);
740 |
741 | void onPageScrollStateChanged(int state);
742 | }
743 |
744 | public interface PageTransformer {
745 | void transformPage(View page, float position, boolean forwardDirection, @OnPageDataListener.LayoutOrientation int mOrientation);
746 | }
747 | }
748 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/adapter/BasePageAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.IntRange;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | import static com.ckr.pageview.utils.PageLog.Logd;
14 | import static com.ckr.pageview.utils.PageLog.Logi;
15 |
16 |
17 | /**
18 | * Created by PC大佬 on 2018/1/15.
19 | */
20 |
21 | public abstract class BasePageAdapter extends RecyclerView.Adapter implements OnPageDataListener, OnAutoSizeListener {
22 | private static final String TAG = "BasePageAdapter";
23 | public static final int MIN_ITEM_COUNT = 6;
24 | protected Context mContext;
25 | protected List mTargetData;
26 | protected List mRawData;
27 | protected int mRow;
28 | protected int mColumn;
29 | private int mPageCount;
30 | protected int mOrientation;
31 | protected int mLayoutFlag;
32 | protected boolean mIsLooping;
33 | protected boolean mIsAutosize;
34 | private OnIndicatorListener mOnIndicatorListener;
35 | private int widthOrHeight;
36 |
37 | public BasePageAdapter(Context context) {
38 | mContext = context;
39 | mRawData = new ArrayList<>();
40 | mTargetData = new ArrayList<>();
41 | }
42 |
43 | public BasePageAdapter setRow(@IntRange(from = 1) int mRow) {
44 | this.mRow = mRow;
45 | return this;
46 | }
47 |
48 | public BasePageAdapter setColumn(@IntRange(from = 1) int mColumn) {
49 | this.mColumn = mColumn;
50 | return this;
51 | }
52 |
53 | public BasePageAdapter setOrientation(@LayoutOrientation int mOrientation) {
54 | this.mOrientation = mOrientation;
55 | return this;
56 | }
57 |
58 | public BasePageAdapter setLayoutFlag(@LayoutFlag int mLayoutFlag) {
59 | this.mLayoutFlag = mLayoutFlag;
60 | return this;
61 | }
62 |
63 | public BasePageAdapter setLooping(boolean isLooping) {
64 | this.mIsLooping = isLooping;
65 | return this;
66 | }
67 |
68 | public BasePageAdapter setAutosize(boolean autosize) {
69 | this.mIsAutosize = autosize;
70 | return this;
71 | }
72 |
73 | public BasePageAdapter setOnIndicatorListener(OnIndicatorListener listener) {
74 | mOnIndicatorListener = listener;
75 | return this;
76 | }
77 |
78 | public void updateAll(List list) {
79 | if (list == null || mRawData == null)
80 | return;
81 | mRawData.clear();
82 | mRawData.addAll(list);
83 | supplyData(mRawData);
84 | notifyDataSetChanged();
85 | if (mOnIndicatorListener != null) {
86 | mOnIndicatorListener.updateIndicator();
87 | }
88 | }
89 |
90 | public void updateItem(T t) {
91 | if (t == null) {
92 | return;
93 | }
94 | int index = mRawData.size();
95 | mRawData.add(t);
96 | int pageCount = (int) Math.ceil(mRawData.size() / (double) (mRow * mColumn));
97 | if (pageCount == this.mPageCount) {
98 | mTargetData.add(index, t);
99 | mTargetData.remove(mTargetData.size() - 1);
100 | notifyDataSetChanged();
101 | } else {
102 | supplyData(mRawData);
103 | notifyDataSetChanged();
104 | if (mOnIndicatorListener != null) {
105 | mOnIndicatorListener.updateIndicator();
106 | }
107 | }
108 | }
109 |
110 | public void updateItem(int start, T t) {
111 | if (t == null) {
112 | return;
113 | }
114 | if (start < 0 && start > mRawData.size()) {
115 | throw new ArrayIndexOutOfBoundsException(start);
116 | }
117 | mRawData.add(start, t);
118 | int pageCount = (int) Math.ceil(mRawData.size() / (double) (mRow * mColumn));
119 | if (pageCount == this.mPageCount) {
120 | mTargetData.add(start, t);
121 | mTargetData.remove(mTargetData.size() - 1);
122 | notifyDataSetChanged();
123 | } else {
124 | supplyData(mRawData);
125 | notifyDataSetChanged();
126 | if (mOnIndicatorListener != null) {
127 | mOnIndicatorListener.updateIndicator();
128 | }
129 | }
130 | }
131 |
132 | public void removeItem(int adjustedPosition) {
133 | if (adjustedPosition < 0 && adjustedPosition >= mRawData.size()) {
134 | throw new ArrayIndexOutOfBoundsException(adjustedPosition);
135 | }
136 | mRawData.remove(adjustedPosition);
137 | int pageCount = (int) Math.ceil(mRawData.size() / (double) (mRow * mColumn));
138 | if (pageCount == this.mPageCount) {
139 | mTargetData.remove(adjustedPosition);
140 | mTargetData.add(null);
141 | notifyDataSetChanged();
142 | } else {
143 | supplyData(mRawData);
144 | notifyDataSetChanged();
145 | if (mOnIndicatorListener != null) {
146 | mOnIndicatorListener.updateIndicator();
147 | }
148 | }
149 | }
150 |
151 | private void supplyData(List list) {
152 | if (list == null) {
153 | return;
154 | }
155 | Logd(TAG, "supplyData,size:" + list.size());
156 | mTargetData.clear();
157 | mTargetData.addAll(list);
158 | mPageCount = (int) Math.ceil(list.size() / (double) (mRow * mColumn));//多少页
159 | Logd(TAG, "supplyData,pages:" + mPageCount);
160 | for (int i = list.size(); i < mPageCount * mRow * mColumn; i++) {
161 | mTargetData.add(null);
162 | }
163 | }
164 |
165 | @Override
166 | public List getRawData() {
167 | return mRawData;
168 | }
169 |
170 | @Override
171 | public int getItemViewType(int position) {
172 | return position;
173 | }
174 |
175 | @Override
176 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
177 | View itemView = LayoutInflater.from(mContext).inflate(getLayoutId(viewType), parent, false);
178 | if (isAutoSize()) {
179 | ViewGroup.LayoutParams layoutParams = itemView.getLayoutParams();
180 | int itemWidthOrHeight = calculateItemWidthOrHeight(viewType);
181 | if (itemWidthOrHeight > 0) {
182 | if (mOrientation == HORIZONTAL) {
183 | layoutParams.width = itemWidthOrHeight;
184 | } else {
185 | layoutParams.height = itemWidthOrHeight;
186 | }
187 | Logi(TAG, "onMeasure onCreateViewHolder: width:" + layoutParams.width + ",height:" + layoutParams.height);
188 | itemView.setLayoutParams(layoutParams);
189 | }
190 | }
191 | return getViewHolder(itemView, viewType);
192 | }
193 |
194 | @Override
195 | public void onBindViewHolder(ViewHolder holder, int position) {
196 | Logd(TAG, "onBindViewHolder: position:" + position + ",size:" + mTargetData.size());
197 | int index = position;
198 | if (mIsLooping) {
199 | index = position % mTargetData.size();
200 | }
201 | int adjustedPosition = adjustPosition(index);
202 | convert(holder, index, mTargetData.get(index), adjustedPosition, mTargetData.get(adjustedPosition));
203 | }
204 |
205 | @Override
206 | public int getItemCount() {
207 | return mTargetData.size();
208 | }
209 |
210 | protected int adjustPosition(int index) {
211 | int pos = index;
212 | if (isGridLayout() && mOrientation == OnPageDataListener.LINEAR) {
213 | int sum = mColumn * mRow;
214 | int remainder = index % sum;
215 | int x = remainder / mRow;
216 | int y = remainder % mRow;
217 | pos = x + y * mColumn;
218 | pos = pos + sum * (index / sum);
219 | }
220 | return pos;
221 | }
222 |
223 | @Override
224 | public int getPageColumn() {
225 | return mColumn;
226 | }
227 |
228 | @Override
229 | public int getPageRow() {
230 | return mRow;
231 | }
232 |
233 | @Override
234 | public int getLayoutOrientation() {
235 | return mOrientation;
236 | }
237 |
238 | @Override
239 | public int getLayoutFlag() {
240 | return mLayoutFlag;
241 | }
242 |
243 | @Override
244 | public boolean isLooping() {
245 | return mIsLooping;
246 | }
247 |
248 | @Override
249 | public int getPageCount() {
250 | return mPageCount;
251 | }
252 |
253 | @Override
254 | public int getRawItemCount() {
255 | return mRawData.size();
256 | }
257 |
258 |
259 | @Override
260 | public void notifySizeChanged(@IntRange(from = 0) int size) {
261 | this.widthOrHeight = size;
262 | }
263 |
264 | @Override
265 | public int calculateItemWidthOrHeight(int position) {
266 | if (isGridLayout()) {
267 | if (mOrientation == HORIZONTAL) {
268 | int countPerPage = mColumn * mRow;
269 | int value = widthOrHeight / mColumn;
270 | int remainder = position % countPerPage;
271 | if (remainder == countPerPage - 2 || remainder == countPerPage - 1) {
272 | return widthOrHeight - value * (mColumn - 1);
273 | } else {
274 | return value;
275 | }
276 | } else {
277 | int countPerPage = mColumn * mRow;
278 | int value = widthOrHeight / mRow;
279 | int remainder = position % countPerPage;
280 | if (remainder == countPerPage - 2 || remainder == countPerPage - 1) {
281 | return widthOrHeight - value * (mRow - 1);
282 | } else {
283 | return value;
284 | }
285 | }
286 | }
287 | return 0;
288 | }
289 |
290 | @Override
291 | public boolean isAutoSize() {
292 | return mIsAutosize && isGridLayout();
293 | }
294 |
295 | private boolean isGridLayout() {
296 | return mLayoutFlag == GRID;
297 | }
298 |
299 | protected abstract int getLayoutId(int viewType);
300 |
301 | protected abstract ViewHolder getViewHolder(View itemView, int viewType);
302 |
303 | protected abstract void convert(ViewHolder holder, int originalPos, T originalItem, int adjustedPos, T adjustedItem);
304 |
305 | }
306 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/adapter/OnAutoSizeListener.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.adapter;
2 |
3 | /**
4 | * Created by ckr on 2018/9/12.
5 | */
6 |
7 | public interface OnAutoSizeListener {
8 | void notifySizeChanged(int size);
9 | int calculateItemWidthOrHeight(int position);
10 | boolean isAutoSize();
11 | }
12 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/adapter/OnIndicatorListener.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.adapter;
2 |
3 | /**
4 | * Created by PC大佬 on 2018/1/20.
5 | */
6 |
7 | public interface OnIndicatorListener {
8 | void updateIndicator();
9 | }
10 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/adapter/OnPageDataListener.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.adapter;
2 |
3 | import android.support.annotation.IntDef;
4 |
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.util.List;
8 |
9 | /**
10 | * Created by PC大佬 on 2018/1/16.
11 | */
12 |
13 | public interface OnPageDataListener {
14 | int ONE = 1;
15 | int TWO = 2;
16 | int THREE = 3;
17 | int FOUR = 4;
18 | int FIVE = 5;
19 | int HORIZONTAL = 0;
20 | int VERTICAL = 1;
21 | int LINEAR = 0;
22 | int GRID = 1;
23 |
24 | @Retention(RetentionPolicy.SOURCE)
25 | @IntDef({ONE, TWO})
26 | @interface PageRow {
27 | }
28 |
29 | @Retention(RetentionPolicy.SOURCE)
30 | @IntDef({ONE, TWO, THREE, FOUR, FIVE})
31 | @interface PageColumn {
32 | }
33 |
34 | @Retention(RetentionPolicy.SOURCE)
35 | @IntDef({HORIZONTAL, VERTICAL})
36 | @interface LayoutOrientation {
37 | }
38 |
39 | @Retention(RetentionPolicy.SOURCE)
40 | @IntDef({LINEAR, GRID})
41 | @interface LayoutFlag {
42 | }
43 |
44 | @PageRow
45 | int getPageColumn();
46 |
47 | @PageColumn
48 | int getPageRow();
49 |
50 | @LayoutOrientation
51 | int getLayoutOrientation();
52 |
53 | @LayoutFlag
54 | int getLayoutFlag();
55 |
56 | boolean isLooping();
57 |
58 | int getPageCount();
59 |
60 | int getRawItemCount();
61 |
62 | List getRawData();
63 | }
64 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/manager/LifecycleManager.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.manager;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v4.app.FragmentActivity;
6 |
7 | import com.ckr.pageview.view.PageView;
8 |
9 | import static com.ckr.pageview.utils.PageLog.Logd;
10 |
11 | /**
12 | * Created on 2019/11/24
13 | *
14 | * @author ckr
15 | */
16 | public class LifecycleManager {
17 | private static final String TAG = "LifecycleManager";
18 | private FragmentActivity mHostActivity;
19 | private Fragment mHostFragment;
20 | private PageView mPageView;
21 |
22 | public LifecycleManager(PageView view) {
23 | this.mPageView = view;
24 | }
25 |
26 | public void onDetachedFromWindow() {
27 | Logd(TAG, "onDetachedFromWindow");
28 | removeLifeCycleObserver(mHostActivity);
29 | removeLifeCycleObserver(mHostFragment);
30 | // mHostActivity = null;
31 | // mHostFragment = null;
32 | if (mPageView != null) {
33 | mPageView.stopLooping();
34 | }
35 | }
36 |
37 | public void onAttachedToWindow() {
38 | Logd(TAG, "onAttachedToWindow");
39 | registerLifeCycleObserver(mHostActivity);
40 | registerLifeCycleObserver(mHostFragment);
41 | if (mPageView != null) {
42 | mPageView.restartLooping();
43 | }
44 | }
45 |
46 | public void onResume() {
47 | Logd(TAG, "onResume");
48 | if (mPageView != null) {
49 | mPageView.restartLooping();
50 | }
51 | }
52 |
53 | public void onStop() {
54 | Logd(TAG, "onStop");
55 | if (mPageView != null) {
56 | mPageView.stopLooping();
57 | }
58 | }
59 |
60 | public void onDestroy() {
61 | Logd(TAG, "onDestroy");
62 | }
63 |
64 | public void registerLifeCycleObserver(@NonNull FragmentActivity activity) {
65 | if (activity == null) {
66 | return;
67 | }
68 | mHostActivity = activity;
69 | // activity.getLifecycle().addObserver(this);
70 | }
71 |
72 | public void removeLifeCycleObserver(@NonNull FragmentActivity activity) {
73 | if (activity == null) {
74 | return;
75 | }
76 | // activity.getLifecycle().removeObserver(this);
77 | }
78 |
79 | public void registerLifeCycleObserver(@NonNull Fragment fragment) {
80 | if (fragment == null) {
81 | return;
82 | }
83 | mHostFragment = fragment;
84 | // mHostFragment.getLifecycle().addObserver(this);
85 | }
86 |
87 | public void removeLifeCycleObserver(@NonNull Fragment fragment) {
88 | if (fragment == null) {
89 | return;
90 | }
91 | // fragment.getLifecycle().removeObserver(this);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/AccordionTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Toxic Bakery
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ckr.pageview.transform;
18 |
19 | import android.support.v4.view.ViewCompat;
20 | import android.view.View;
21 |
22 | import com.ckr.pageview.adapter.OnPageDataListener;
23 |
24 | public class AccordionTransformer extends BaseTransformer {
25 |
26 | @Override
27 | protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
28 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
29 | ViewCompat.setPivotX(view, position < 0 ? view.getWidth() : 0);
30 | ViewCompat.setScaleX(view, position < 0 ? 1f + position : (1f - position));
31 | } else {
32 | ViewCompat.setPivotY(view, position < 0 ? view.getHeight() : 0);
33 | ViewCompat.setPivotX(view, view.getWidth());
34 | ViewCompat.setScaleY(view, position < 0 ? 1f + position : (1f - position));
35 | }
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/BaseTransformer.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.transform;
2 |
3 | import android.support.v4.view.ViewCompat;
4 | import android.support.v7.widget.PageRecyclerView;
5 | import android.view.View;
6 |
7 | import com.ckr.pageview.adapter.OnPageDataListener;
8 |
9 | import static com.ckr.pageview.utils.PageLog.Logd;
10 |
11 | /**
12 | * Created by PC大佬 on 2018/4/6.
13 | */
14 |
15 | public abstract class BaseTransformer implements PageRecyclerView.PageTransformer {
16 | protected static final String TAG = "BaseTransformer";
17 |
18 | protected abstract void onTransform(View view, float position, boolean forwardDirection, @OnPageDataListener.LayoutOrientation int mOrientation);
19 |
20 | @Override
21 | public void transformPage(View page, float position, boolean forwardDirection, int mOrientation) {
22 | Logd(TAG, "transformPage: position:" + position);
23 | onPreTransform(page, position, mOrientation);
24 | onTransform(page, position, forwardDirection, mOrientation);
25 | onPostTransform(page, position, mOrientation);
26 | }
27 |
28 | protected void onPreTransform(View view, float position, @OnPageDataListener.LayoutOrientation int mOrientation) {
29 | ViewCompat.setAlpha(view, 1);
30 | ViewCompat.setPivotX(view, 0);
31 | ViewCompat.setPivotY(view, 0);
32 | ViewCompat.setRotationY(view, 0);
33 | ViewCompat.setRotationX(view, 0);
34 | ViewCompat.setScaleX(view, 1);
35 | ViewCompat.setScaleY(view, 1);
36 | ViewCompat.setTranslationX(view, 0);
37 | ViewCompat.setTranslationY(view, 0);
38 | }
39 |
40 | protected void onPostTransform(View view, float position, @OnPageDataListener.LayoutOrientation int mOrientation) {
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/CubeOutTransformer.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.transform;
2 |
3 | import android.support.v4.view.ViewCompat;
4 | import android.view.View;
5 |
6 | import com.ckr.pageview.adapter.OnPageDataListener;
7 |
8 | /**
9 | * Created by PC大佬 on 2018/4/6.
10 | */
11 |
12 | public class CubeOutTransformer extends BaseTransformer {
13 |
14 |
15 | @Override
16 | protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
17 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
18 | ViewCompat.setPivotX(view, position < 0f ? view.getWidth() : 0f);
19 | ViewCompat.setPivotY(view, view.getHeight() * 0.5f);
20 | ViewCompat.setRotationY(view, 90f * position);
21 | } else {
22 | ViewCompat.setPivotY(view, position < 0f ? view.getHeight() : 0f);
23 | ViewCompat.setPivotX(view, view.getWidth() * 0.5f);
24 | ViewCompat.setRotationX(view, -90f * position);
25 | }
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/DefaultTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Toxic Bakery
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ckr.pageview.transform;
18 |
19 | import android.view.View;
20 |
21 | public class DefaultTransformer extends BaseTransformer {
22 |
23 | @Override
24 | protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/DepthPageTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Toxic Bakery
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ckr.pageview.transform;
18 |
19 | import android.support.v4.view.ViewCompat;
20 | import android.view.View;
21 |
22 | import com.ckr.pageview.adapter.OnPageDataListener;
23 |
24 | public class DepthPageTransformer extends BaseTransformer {
25 |
26 | private static final float MIN_SCALE = 0.75f;
27 |
28 | @Override
29 | protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
30 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
31 | if (position <= 0f) {
32 | ViewCompat.setTranslationX(view, 0f);
33 | ViewCompat.setScaleX(view, 1f);
34 | ViewCompat.setScaleY(view, 1f);
35 | } else if (position <= 1f) {
36 | final float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
37 | ViewCompat.setAlpha(view, 1 - position);
38 | ViewCompat.setPivotY(view, 0.5f * view.getHeight());
39 | ViewCompat.setTranslationX(view, view.getWidth() * -position);
40 | ViewCompat.setScaleX(view, scaleFactor);
41 | ViewCompat.setScaleY(view, scaleFactor);
42 | }
43 | }else {
44 | if (position <= 0f) {
45 | ViewCompat.setTranslationY(view, 0f);
46 | ViewCompat.setScaleX(view, 1f);
47 | ViewCompat.setScaleY(view, 1f);
48 | } else if (position <= 1f) {
49 | final float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
50 | ViewCompat.setAlpha(view, 1 - position);
51 | ViewCompat.setPivotX(view, 0.5f * view.getWidth());
52 | ViewCompat.setTranslationY(view, view.getHeight() * -position);
53 | ViewCompat.setScaleX(view, scaleFactor);
54 | ViewCompat.setScaleY(view, scaleFactor);
55 | }
56 | }
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/FlipTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Toxic Bakery
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ckr.pageview.transform;
18 |
19 | import android.support.v4.view.ViewCompat;
20 | import android.view.View;
21 |
22 | import com.ckr.pageview.adapter.OnPageDataListener;
23 |
24 | public class FlipTransformer extends BaseTransformer {
25 |
26 | @Override
27 | protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
28 | final float rotation = 180f * (position);
29 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
30 | ViewCompat.setAlpha(view, rotation > 90f || rotation < -90f ? 0 : 1);
31 | ViewCompat.setPivotX(view, view.getWidth() * 0.5f);
32 | ViewCompat.setPivotY(view, view.getHeight() * 0.5f);
33 | ViewCompat.setRotationY(view, rotation);
34 | } else {
35 | ViewCompat.setAlpha(view, rotation > 90f || rotation < -90f ? 0 : 1);
36 | ViewCompat.setPivotX(view, view.getWidth() * 0.5f);
37 | ViewCompat.setPivotY(view, view.getHeight() * 0.5f);
38 | ViewCompat.setRotationX(view, -rotation);
39 | }
40 | }
41 |
42 | @Override
43 | protected void onPreTransform(View view, float position, int mOrientation) {
44 | super.onPreTransform(view, position, mOrientation);
45 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
46 | view.setTranslationX(-view.getWidth() * (position));
47 | } else {
48 | view.setTranslationY(-view.getHeight() * (position));
49 | }
50 | }
51 |
52 | @Override
53 | protected void onPostTransform(View page, float position, int mOrientation) {
54 | super.onPostTransform(page, position, mOrientation);
55 |
56 | //resolve problem: new page can't handle click event!
57 | if (position > -0.5f && position < 0.5f) {
58 | page.setVisibility(View.VISIBLE);
59 | } else {
60 | page.setVisibility(View.INVISIBLE);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/ScaleInOutTransformer.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.transform;
2 |
3 | import android.view.View;
4 |
5 | import com.ckr.pageview.adapter.OnPageDataListener;
6 |
7 | public class ScaleInOutTransformer extends BaseTransformer {
8 |
9 | @Override
10 | protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
11 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
12 | view.setPivotX(position < 0 ? 0 : view.getWidth());
13 | view.setPivotY(view.getHeight() / 2f);
14 | float scale = position < 0 ? 1f + position : 1f - position;
15 | view.setScaleX(scale);
16 | view.setScaleY(scale);
17 | } else {
18 | view.setPivotY(position < 0 ? 0 : view.getHeight());
19 | view.setPivotX(view.getWidth() / 2f);
20 | float scale = position < 0 ? 1f + position : 1f - position;
21 | view.setScaleX(scale);
22 | view.setScaleY(scale);
23 | }
24 | }
25 |
26 | @Override
27 | protected void onPreTransform(View view, float position, int mOrientation) {
28 | super.onPreTransform(view, position, mOrientation);
29 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
30 | view.setTranslationX(-view.getWidth() * position);
31 | } else {
32 | view.setTranslationY(-view.getHeight() * position);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/StackTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Toxic Bakery
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ckr.pageview.transform;
18 |
19 | import android.view.View;
20 |
21 | import com.ckr.pageview.adapter.OnPageDataListener;
22 |
23 | public class StackTransformer extends BaseTransformer {
24 |
25 | @Override
26 | protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
27 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
28 | view.setTranslationX(position < 0 ? 0f : -view.getWidth() * position);
29 | } else {
30 | view.setTranslationY(position < 0 ? 0f : -view.getHeight() * position);
31 | }
32 | }
33 |
34 | @Override
35 | protected void onPreTransform(View view, float position, int mOrientation) {
36 | super.onPreTransform(view, position, mOrientation);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/TabletTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Toxic Bakery
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ckr.pageview.transform;
18 |
19 | import android.graphics.Camera;
20 | import android.graphics.Matrix;
21 | import android.view.View;
22 |
23 | import com.ckr.pageview.adapter.OnPageDataListener;
24 |
25 | public class TabletTransformer extends BaseTransformer {
26 |
27 | private static final Matrix OFFSET_MATRIX = new Matrix();
28 | private static final Camera OFFSET_CAMERA = new Camera();
29 | private static final float[] OFFSET_TEMP_FLOAT = new float[2];
30 |
31 | @Override
32 | protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
33 | final float rotation = (position < 0 ? 30f : -30f) * Math.abs(position);
34 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
35 | view.setTranslationX(getOffsetForRotation(rotation, view.getWidth(), view.getHeight(), mOrientation));
36 | view.setPivotX(view.getWidth() * 0.5f);
37 | view.setPivotY(0);
38 | view.setRotationY(rotation);
39 | } else {
40 | view.setTranslationY(getOffsetForRotation(rotation, view.getWidth(), view.getHeight(), mOrientation));
41 | view.setPivotY(view.getHeight() * 0.5f);
42 | view.setPivotX(0);
43 | view.setRotationX(-rotation);
44 | }
45 |
46 | }
47 |
48 | protected static final float getOffsetForRotation(float degrees, int width, int height, int mOrientation) {
49 | OFFSET_MATRIX.reset();
50 | OFFSET_CAMERA.save();
51 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
52 | OFFSET_CAMERA.rotateY(Math.abs(degrees));
53 | } else {
54 | OFFSET_CAMERA.rotateX(-Math.abs(degrees));
55 | }
56 | OFFSET_CAMERA.getMatrix(OFFSET_MATRIX);
57 | OFFSET_CAMERA.restore();
58 |
59 | OFFSET_MATRIX.preTranslate(-width * 0.5f, -height * 0.5f);
60 | OFFSET_MATRIX.postTranslate(width * 0.5f, height * 0.5f);
61 | OFFSET_TEMP_FLOAT[0] = width;
62 | OFFSET_TEMP_FLOAT[1] = height;
63 | OFFSET_MATRIX.mapPoints(OFFSET_TEMP_FLOAT);
64 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
65 | return (width - OFFSET_TEMP_FLOAT[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
66 | } else {
67 | return (height - OFFSET_TEMP_FLOAT[1]) * (degrees > 0.0f ? 1.0f : -1.0f);
68 | }
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/Transformer.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.transform;
2 |
3 | /**
4 | * Created by PC大佬 on 2018/4/6.
5 | */
6 |
7 | public enum Transformer {
8 | Default(DefaultTransformer.class),
9 | Accordion(AccordionTransformer.class),
10 | CubeOut(CubeOutTransformer.class),
11 | DepthPage(DepthPageTransformer.class),
12 | FlipHorizontal(FlipTransformer.class),
13 | ScaleInOut(ScaleInOutTransformer.class),
14 | Stack(StackTransformer.class),
15 | Tablet(TabletTransformer.class),
16 | ZoomIn(ZoomInTransformer.class),
17 | ZoomOutSlide(ZoomOutSlideTransformer.class);
18 |
19 | private Class mClazz;
20 |
21 | private Transformer(Class clazz) {
22 | mClazz = clazz;
23 | }
24 |
25 | public BaseTransformer getTransformer() {
26 | try {
27 | if (mClazz == null) {
28 | return null;
29 | } else {
30 | return (BaseTransformer) mClazz.newInstance();
31 | }
32 | } catch (Exception e) {
33 | throw new Error("Can not init mClazz instance");
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/ZoomInTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Toxic Bakery
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ckr.pageview.transform;
18 |
19 | import android.view.View;
20 |
21 | import com.ckr.pageview.adapter.OnPageDataListener;
22 |
23 | public class ZoomInTransformer extends BaseTransformer {
24 |
25 | @Override
26 | protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
27 | final float scale = position < 0 ? position + 1f : Math.abs(1f - position);
28 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
29 | view.setScaleX(scale);
30 | view.setScaleY(scale);
31 | view.setPivotX(view.getWidth() * 0.5f);
32 | view.setPivotY(view.getHeight() * 0.5f);
33 | view.setAlpha(position < -1f || position > 1f ? 0f : 1f - (scale - 1f));
34 | } else {
35 | view.setScaleX(scale);
36 | view.setScaleY(scale);
37 | view.setPivotX(view.getWidth() * 0.5f);
38 | view.setPivotY(view.getHeight() * 0.5f);
39 | view.setAlpha(position < -1f || position > 1f ? 0f : 1f - (scale - 1f));
40 | }
41 |
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/transform/ZoomOutSlideTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Toxic Bakery
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ckr.pageview.transform;
18 |
19 | import android.util.DisplayMetrics;
20 | import android.util.Log;
21 | import android.util.TypedValue;
22 | import android.view.View;
23 |
24 | import com.ckr.pageview.adapter.OnPageDataListener;
25 |
26 | public class ZoomOutSlideTransformer extends BaseTransformer {
27 |
28 | private static final float MIN_SCALE = 0.78f;
29 | private static final float MIN_ALPHA = 0.5f;
30 |
31 | @Override
32 | protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
33 | if (mOrientation == OnPageDataListener.HORIZONTAL) {
34 | if (position >= -1 || position <= 1) {
35 | // Modify the default slide transition to shrink the page as well
36 | final float height = view.getHeight();
37 | final float width = view.getWidth();
38 | final float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
39 | final float vertMargin = height * (1 - scaleFactor) / 2;
40 | final float horzMargin = width * (1 - scaleFactor) / 2;
41 |
42 | // Center vertically
43 | view.setPivotY(0.5f * height);
44 | view.setPivotX(0.5f * width);
45 |
46 | if (position < 0) {
47 | view.setTranslationX(horzMargin - vertMargin / 2);
48 | } else {
49 | view.setTranslationX(-horzMargin + vertMargin / 2);
50 | }
51 |
52 | // Scale the page down (between MIN_SCALE and 1)
53 | view.setScaleX(scaleFactor);
54 | view.setScaleY(scaleFactor);
55 |
56 | // Fade the page relative to its size.
57 | view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
58 | }
59 | } else {
60 | if (position >= -1 || position <= 1) {
61 | // Modify the default slide transition to shrink the page as well
62 | final float height = view.getHeight();
63 | final float width = view.getWidth();
64 | final float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
65 | final float vertMargin = height * (1 - scaleFactor) / 2;
66 | final float horzMargin = width * (1 - scaleFactor) / 2;
67 |
68 | // Center vertically
69 | view.setPivotY(0.5f * height);
70 | view.setPivotX(0.5f * width);
71 |
72 | if (position < 0) {
73 | view.setTranslationY(vertMargin - horzMargin / 2);
74 | } else {
75 | view.setTranslationY(-vertMargin + horzMargin / 2);
76 | }
77 |
78 | // Scale the page down (between MIN_SCALE and 1)
79 | view.setScaleX(scaleFactor);
80 | view.setScaleY(scaleFactor);
81 |
82 | // Fade the page relative to its size.
83 | view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
84 | }
85 | }
86 |
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/utils/PageLog.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.utils;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * Created by PC大佬 on 2018/1/26.
7 | */
8 |
9 | public class PageLog {
10 | private static final String TAG = "PageLog";
11 | private static boolean isDebug = false;
12 |
13 | public static void debug() {
14 | PageLog.isDebug = true;
15 | }
16 |
17 | public static void Logv(String msg) {
18 | Logv("", msg);
19 | }
20 |
21 | public static void Logv(String tag, String msg) {
22 | if (isDebug) {
23 | Log.v(TAG, tag + "--->" + msg);
24 | }
25 | }
26 |
27 | public static void Logd(String msg) {
28 | Logd("", msg);
29 | }
30 |
31 | public static void Logd(String tag, String msg) {
32 | if (isDebug) {
33 | Log.d(TAG, tag + "--->" + msg);
34 | }
35 | }
36 |
37 | public static void Logi(String msg) {
38 | Logi("", msg);
39 | }
40 |
41 | public static void Logi(String tag, String msg) {
42 | if (isDebug) {
43 | Log.i(TAG, tag + "--->" + msg);
44 | }
45 | }
46 |
47 | public static void Logw(String msg) {
48 | Logw("", msg);
49 | }
50 |
51 | public static void Logw(String tag, String msg) {
52 | if (isDebug) {
53 | Log.w(TAG, tag + "--->" + msg);
54 | }
55 | }
56 |
57 | public static void Loge(String msg) {
58 | Loge("", msg);
59 | }
60 |
61 | public static void Loge(String tag, String msg) {
62 | if (isDebug) {
63 | Log.e(TAG, tag + "--->" + msg);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/pageview/src/main/java/com/ckr/pageview/view/PageHandler.java:
--------------------------------------------------------------------------------
1 | package com.ckr.pageview.view;
2 |
3 | import android.os.Handler;
4 | import android.os.Message;
5 |
6 | import java.lang.ref.WeakReference;
7 |
8 | /**
9 | * Created by ckr on 2018/1/29.
10 | */
11 | public class PageHandler extends Handler {
12 | public static final int MSG_START_LOOPING = 0;
13 | public static final int MSG_STOP_LOOPING = 1;
14 | private WeakReference weakReference;
15 |
16 | public PageHandler(WeakReference wk) {
17 | weakReference = wk;
18 | }
19 |
20 | @Override
21 | public void handleMessage(Message msg) {
22 | super.handleMessage(msg);
23 | PageView mPageView = weakReference.get();
24 | if (mPageView == null) {
25 | return;
26 | }
27 | if (mPageView.getHandler().hasMessages(MSG_START_LOOPING)) {
28 | mPageView.getHandler().removeMessages(MSG_START_LOOPING);
29 | }
30 | switch (msg.what) {
31 | case MSG_START_LOOPING:
32 | mPageView.setCurrentItem(mPageView.getCurrentItem() + (mPageView.getPageCount() == 0 ? 0 : 1));
33 | mPageView.getHandler().sendEmptyMessageDelayed(MSG_START_LOOPING, mPageView.getLoopingInterval());
34 | break;
35 | case MSG_STOP_LOOPING:
36 | break;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/pageview/src/main/res/drawable/shape_point_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/pageview/src/main/res/drawable/shape_point_unselected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/pageview/src/main/res/layout/horizontal_page_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
24 |
25 |
31 |
32 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/pageview/src/main/res/layout/vertical_page_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
24 |
25 |
31 |
32 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/pageview/src/main/res/values/attrs_page_view.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 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | 3000
65 | #ff0000
66 | #000000
67 | 5dp
68 | 5dp
69 | 5dp
70 | 30dp
71 | 30dp
72 | 0x11
73 |
74 |
--------------------------------------------------------------------------------
/pageview/src/main/res/values/indicator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 5dp
4 | 5dp
5 | 5dp
6 | 26dp
7 | 26dp
8 | #ff0000
9 | #000000
10 | 16dp
11 |
12 |
--------------------------------------------------------------------------------
/pageview/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | pageview
3 |
4 |
--------------------------------------------------------------------------------
/screenRecorder/Screenshot_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/screenRecorder/Screenshot_1.gif
--------------------------------------------------------------------------------
/screenRecorder/Screenshot_2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/screenRecorder/Screenshot_2.gif
--------------------------------------------------------------------------------
/screenRecorder/Screenshot_3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/screenRecorder/Screenshot_3.gif
--------------------------------------------------------------------------------
/screenRecorder/Screenshot_4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/screenRecorder/Screenshot_4.gif
--------------------------------------------------------------------------------
/screenRecorder/Screenshot_5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/screenRecorder/Screenshot_5.gif
--------------------------------------------------------------------------------
/screenRecorder/qq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckrgithub/PageRecyclerView/e149577358526b383623e57b8a0845bc82f8d55d/screenRecorder/qq.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':pageview'
2 |
--------------------------------------------------------------------------------