diff --git a/.gitignore b/.gitignore
index 65d29b8fb2f205725d5adb85b6de7ee8230955dd..d2e9afc7cef8d8ef96b6e320c364d1b8b83b9691 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,36 +1,17 @@
-# Built application files
-*.apk
-*.ap_
-
-# Files for the Dalvik VM
-*.dex
-
-# Java class files
-*.class
-
-# Generated files
-bin/
-gen/
-
-# Gradle files
-.gradle/
-build/
-
-# Local configuration file (sdk path, etc)
-local.properties
-
-# Proguard folder generated by Eclipse
-proguard/
-
-# Log Files
-*.log
-
-# Android Studio
-.idea/
-.gradle
-.navigation/
*.iml
-captures/
-
-# Mac
-.DS_Store
\ No newline at end of file
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+/entry/.preview
+.cxx
+/.idea/
+/recyclerview_fastscroll/upload.gradle
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index e564f1f352cfb3ab0be6ccea629d7c89f792327e..0000000000000000000000000000000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-language: android
-jdk: oraclejdk8
-android:
- components:
- - tools
- - platform-tools
- - build-tools-28.0.3
- - android-28
- - extra-android-support
- - extra-android-m2repository
- - extra-google-m2repository
- licenses:
- - ".+"
-script:
- - ./gradlew build connectedCheck
-before_install:
-- yes | sdkmanager "platforms;android-28"
-- mkdir "$ANDROID_HOME/licenses" || true
-- echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_HOME/licenses/android-sdk-license"
-- echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_HOME/licenses/android-sdk-preview-license"
-- echo y | android update sdk --no-ui --all --filter build-tools-28.0.3
-before_cache:
-- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
-- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
-cache:
- directories:
- - "$HOME/.gradle/caches/"
- - "$HOME/.gradle/wrapper/"
- - "$HOME/.android/build-cache"
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..e02d0e910b49b026b606905081ed9d2da19fc18a
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,2 @@
+## 0.0.1-SNAPSHOT
+ohos 第一个版本,完整实现了原库的全部 api
\ No newline at end of file
diff --git a/CHANGES.md b/CHANGES.md
deleted file mode 100644
index 00d3984b19e2330ec0297256ec3b87256987a48d..0000000000000000000000000000000000000000
--- a/CHANGES.md
+++ /dev/null
@@ -1,91 +0,0 @@
-### Changelog
-
-2.0.1
-
-- Fixed scrolling smoothness regression
-- Updated thumb style to more closely match Google's recent changes
-
-2.0.0
-
-- Version updated due to binary incompatible change in 1.0.21 (AndroidX migration)
-- Improved vertical alignment of popup text
-- Renamed `FastScrollerPopupPosition` to `PopupPosition`
-
-1.0.21 (Backwards incompatible change & incorrect version)
-
-- Migrated to AndroidX
-- LayoutManager.reverseLayout(true) is now supported
-- Fixed an issue where popup text wasn't vertically centered
-- Respect top and bottom padding of RecyclerView when drawing thumb/track
-
-1.0.20
-
-- Crash fix
-
-1.0.19
-
-- Update dependencies, compile SDK to Android 28
-- Fixed an issue where thumb colour was not persisted after setThumbColor()
-- Fixed a compilation issue on Android 28
-- Fixed 'scrolling jitter' when using items with varying height
-
-1.0.18
-
-- Added method `showScrollbar()` to `FastScrollRecyclerView`
-- Added method `setThumbInactiveColor(ColorInt)` to `FastScroller`
-- Renamed `setThumbInactiveColor(boolean) to enableThumbInactiveColor(boolean)`.
-- Renamed `setStateChangeListener` to `setOnFastScrollStateChangedListener`
-- Renamed `setThumbEnabled` to `setFastScrollEnabled`
-- Set `enableThumbInactiveColor` to true by default
-- Pass `ViewHolder` into `MeasurableAdapter` to ease item height calculations
-- Dependency updates
-
-1.0.17
-
-- `MeasurableAdapter` tweaks
-- Improved sample, better demonstration of `MeasurableAdapter`
-- Add option to enable/disable fastscroll (via `fastScrollThumbEnabled` property)
-- Dependency updates
-
-1.0.16
-
-- Added support for varying row heights via `MeasurableAdapter`
-
-1.0.15
-
-- Fixed an issue preventing the view from rendering in the Android Studio 'design' panel.
-- Updated dependencies
-
-1.0.14
-
-- Make it possible to set popup position programmatically
-
-1.0.13
-
-- Added option to position the FastScroll-Popup in the center of the RecyclerView (rather than tracking adjacent to the FastScroll thumb)
-
-1.0.12
-
-- Fixed a Proguard Obfuscation issue preventing animations from running
-- Fixed an issue where popup background color ignored alpha channel
-- Added support for item decorations
-
-1.0.11
-
-- Added FastScrollStateChanged listener. Notifies when scrolling starts & stops.
-
-1.0.10
-
-- Added methods/attributes to set popup background & text size
-- Added method to set popup typeface
-- Fixed issue where item decorations were drawn over the top of the popup (#18)
-- Updated dependencies
-
-v1.0.9
-
-- Updated gradle & dependencies
-- Fixed crash when no adapter was set on the `RecyclerView`
-- Fixed crash when `RecyclerView` children are null (`itemCount` is non zero, but `getChildAt(0)` returns null).
-
-v1.0.6
-- The `FastScrollPopup` no longer requires your adapter to implement `SectionIndexer`, but rather `FastScrollRecyclerView.SectionedAdapter`, which is much easier to use.
\ No newline at end of file
diff --git a/LICENSE.md b/LICENSE
similarity index 98%
rename from LICENSE.md
rename to LICENSE
index 1d59b4b6fc7b9c08bb9199b29e657e1a83d5057d..48c13f8926adb867eee74111e94b09bef397f502 100644
--- a/LICENSE.md
+++ b/LICENSE
@@ -1,4 +1,4 @@
-### Licenses
+Licenses
RecyclerView-FastScroll
diff --git a/NOTICE b/NOTICE
deleted file mode 100644
index b405860d7cf2a7509ca84b696ee99db54fc759ef..0000000000000000000000000000000000000000
--- a/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2016, Tim Malseed
- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
diff --git a/README.OPENSOURCE b/README.OPENSOURCE
new file mode 100644
index 0000000000000000000000000000000000000000..e5e8820ceef32a1473eed70bc3c1f24074c565af
--- /dev/null
+++ b/README.OPENSOURCE
@@ -0,0 +1,19 @@
+[
+
+ {
+
+ "Name": "RecyclerView-FastScroll",
+
+ "License": " Apache License ",
+
+ "License File": "LICENSE",
+
+ "Version Number": "2.0.1"
+
+ "Upstream URL": "https://github.com/timusus/RecyclerView-FastScroll",
+
+ "Description": "一个简单的快速滚动列表控件。"
+
+ }
+
+]
\ No newline at end of file
diff --git a/README.md b/README.md
index 4e9f85953ede87d8462fa0695d49350d5eb1a83c..c4de45b9cae584751d465f0906dcc9a585f12303 100644
--- a/README.md
+++ b/README.md
@@ -1,111 +1,105 @@
# RecyclerView-FastScroll
-[](https://maven-badges.herokuapp.com/maven-central/com.simplecityapps/recyclerview-fastscroll) [](https://android-arsenal.com/api?level=14)
-[](NOTICE)
-[](https://travis-ci.org/timusus/RecyclerView-FastScroll)
-
-A simple `FastScroller` for Android's `RecyclerView`.
-
-Supports vertical `RecyclerViews` using either `LinearLayoutManager` or `GridLayoutManager` (including multiple spans).
-
-The style is loosely based on the `ListView` `FastScroller` from whatever the last version of Lollipop was. This library borrows heavily from [Google's Launcher3 FastScroller](https://android.googlesource.com/platform/packages/apps/Launcher3/)
-
-
-
-
-### Gradle
-`compile 'com.simplecityapps:recyclerview-fastscroll:2.0.1'`
+#### 项目介绍
+- 项目名称:RecyclerView-FastScroll
+- 所属系列:openharmony的第三方组件适配移植
+- 功能:一个简单的快速滚动列表控件
+- 项目移植状态:主功能完成
+- 调用差异:无
+- 开发版本:sdk6,DevEco Studio 2.2 Beta1
+- 基线版本:Release 2.0.1
+
+#### 效果演示
+
+
+
+#### 安装教程
+
+1.在项目根目录下的build.gradle文件中,
+ ```gradle
+allprojects {
+ repositories {
+ maven {
+ url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
+ }
+ }
+}
+ ```
+2.在entry模块的build.gradle文件中,
+ ```gradle
+ dependencies {
+ implementation('com.gitee.chinasoft_ohos:RecyclerView-FastScroll:0.0.1-SNAPSHOT')
+ ......
+ }
+```
-### Usage
-You must use `FastScrollRecyclerView` as your base `RecyclerView`. See the sample project if you're having trouble.
+在sdk6,DevEco Studio 2.2 Beta1下项目可直接运行
+如无法运行,删除项目.gradle,.idea,build,gradle,build.gradle文件,
+并依据自己的版本创建新项目,将新项目的对应文件复制到根目录下
-Via xml:
+#### 使用说明
-```
+```xml
+ ohos:id="$+id:listview"
+ ohos:height="match_parent"
+ ohos:width="match_parent"
+ app:fastScrollPopupBgColor="#FF4081"
+ app:fastScrollPopupTextColor="#ffffff"
+ app:fastScrollThumbColor="#FF4081" />
```
-To display the `FastScrollPopup`, your adapter must implement `FastScrollRecyclerView.SectionedAdapter` and override `getSectionName()`.
-
-If you need to know when fast-scrolling starts or stops, you can attach an OnFastScrollStateChangedListener to the FastScrollRecyclerView.
-
-
-##### Varying Row Heights
-
-By default, `FastScrollRecyclerView` assumes that all items in the adapter have the same height. If your adapter has
-item views with different heights, then you should make your adapter implement the `MeasurableAdapter` interface and
-override `getViewTypeHeight()` – otherwise the scroll thumb may not appear in the correct position and scrolling may
-be inconsistent.
-
-`getViewTypeHeight()` returns the height of a single view of a given type in pixels. The height of each view must be
-fixed and constant between all instances of a view type. Because the implementor is responsible for computing this
-value before views are laid out, this is not suitable for view types where the height of a view is determined by a
-variable number of lines of text that the item consumes.
+要显示FastScrollPopup,适配器必须实现FastScrollRecyclerView.SectionedAdapter并重写getSectionName()。
+如果你需要知道什么时候快速滚动开始或停止,你可以设置一个OnFastScrollStateChangedListener到FastScrollRecyclerView。
-Currently, `MeasurableAdapter` only works with `LinearLayoutManager`. Using `MeasurableAdapter` with a
-`GridLayoutManager` that has more than one span will cause the scrollbar thumb to reach the bottom of the list before
-the halfway point on the scrollbar's background.
+不同高度
+默认情况下,FastScrollRecyclerView适配器中的所有项目具有相同的高度。如果您的适配器然后你应该让你的适配器实现MeasurableAdapter接口和
+重写getViewTypeHeight() 否则滚动拇指可能不会出现在正确的位置,滚动可能是不一致的。
+getViewTypeHeight()返回给定类型的单个视图的高度,以像素为单位。每个视图的高度必须是一个视图类型的所有实例之间是固定不变的。因为实现者负责计算这个值,这不适用于视图类型,其中视图的高度是由
+项目所使用的文本行数可变。
-##### Customisation
-
-You can enable/disable autohide using the `fastScrollAutoHide` & `fastScrollAutoHideDelay` attributes in xml:
-
-```
-
- ...
+ app:fastScrollPopupTextColor="#ffffff"
+ app:fastScrollPopupTextSize="32fp"
+ app:fastScrollPopupTextVerticalAlignmentMode="font_metrics"
+ app:fastScrollThumbColor="#FF4081"
+ app:fastScrollThumbEnabled="true"/>
```
+#### 测试信息
-Or programmatically via
+CodeCheck代码测试无异常
-- `setThumbColor(@ColorInt int color)`
-- `setTrackColor(@ColorInt int color)`
-- `setPopupBgColor(@ColorInt int color)`
-- `setPopupTextColor(@ColorInt int color)`
-- `setPopupTextSize(int size)`
-- `setPopupPosition(@FastScroller.FastScrollerPopupPosition int position)`
+CloudTest代码测试无异常
+病毒安全检测通过
-You can enable/disable fast-scrolling via:
+当前版本demo功能与原组件基本无差异
-```
-
+public class MultiViewTypeAdapter extends RecyclerView.Adapter
implements FastScrollRecyclerView.SectionedAdapter,
FastScrollRecyclerView.MeasurableAdapter {
@Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false));
+ public ViewHolder onCreateViewHolder(Component parent, int viewType) {
+ if (ResourceTable.Layout_list_item == viewType) {
+ return new ViewHolder(LayoutScatter.getInstance(parent.getContext()).parse(
+ ResourceTable.Layout_list_item, null, false));
+ } else {
+ return new ViewHolder(LayoutScatter.getInstance(parent.getContext()).parse(
+ ResourceTable.Layout_list_item_header, null, false));
+ }
}
@Override
- public int getItemViewType(int position) {
- if (position % 4 == 0) {
- return R.layout.list_item_header;
- }
- return R.layout.list_item;
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ ViewHolder viewHolder = (ViewHolder) holder;
+ viewHolder.text.setText(getNameForItem(position));
}
- @SuppressLint("DefaultLocale")
@Override
- public void onBindViewHolder(ViewHolder holder, int position) {
- holder.text.setText(getNameForItem(position));
+ public int getItemViewType(int position) {
+ if (position % 4 == 0) {
+ return ResourceTable.Layout_list_item_header;
+ }
+ return ResourceTable.Layout_list_item;
}
@Override
@@ -40,8 +39,6 @@ public class MultiViewTypeAdapter extends RecyclerView.Adapter cache = new HashMap<>();
+
+ public PagerAdapter(AbilitySlice abilitySlice) {
+ this.abilitySlice = abilitySlice;
+ }
+
+ @Override
+ public int getCount() {
+ return 2;
+ }
+
+ @Override
+ public Object createPageInContainer(ComponentContainer componentContainer, int i) {
+ if (cache.get(i) == null) {
+ DirectionalLayout layout = (DirectionalLayout) LayoutScatter.getInstance(abilitySlice).parse(
+ ResourceTable.Layout_page_item, null, false);
+ FastScrollRecyclerView listView = (FastScrollRecyclerView) layout.findComponentById(ResourceTable.Id_listview);
+ if (i == 0) {
+ listView.setAdapter(new SimpleRecyclerAdapter());
+ } else {
+ listView.setAdapter(new MultiViewTypeAdapter());
+ }
+ cache.put(i, layout);
+ componentContainer.addComponent(cache.get(i));
+ }
+ return componentContainer;
+ }
+
+ @Override
+ public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) {
+ componentContainer.removeComponent((Component) o);
+ }
+
+ @Override
+ public boolean isPageMatchToObject(Component component, Object o) {
+ return false;
+ }
+
+}
diff --git a/entry/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/SimpleRecyclerAdapter.java b/entry/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/SimpleRecyclerAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a27360eccbaeb2b3c2bed06fcd412ca5cb0088b
--- /dev/null
+++ b/entry/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/SimpleRecyclerAdapter.java
@@ -0,0 +1,50 @@
+package com.simplecityapps.recyclerview_fastscroll.sample;
+
+import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
+import com.simplecityapps.recyclerview_fastscroll.views.RecyclerView;
+import ohos.agp.components.*;
+import ohos.agp.components.element.VectorElement;
+
+public class SimpleRecyclerAdapter extends RecyclerView.Adapter implements FastScrollRecyclerView.SectionedAdapter {
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(Component parent, int viewType) {
+ return new ViewHolder(LayoutScatter.getInstance(parent.getContext()).parse(
+ ResourceTable.Layout_list_item, null, false));
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ ViewHolder viewHolder = (ViewHolder) holder;
+ viewHolder.text.setText(String.format("Item %d",position + 1));
+ }
+
+ @Override
+ public int getItemCount() {
+ return 200;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return 0;
+ }
+
+ @Override
+ public String getSectionName(int position) {
+ return String.format("%d", position + 1);
+ }
+
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ public Text text;
+ public Image image;
+
+ ViewHolder(Component itemView) {
+ super(itemView);
+ text = (Text) itemView.findComponentById(ResourceTable.Id_text);
+ image = (Image) itemView.findComponentById(ResourceTable.Id_image);
+ VectorElement ele = new VectorElement(itemView.getContext(), ResourceTable.Media_ic_extension_24dp);
+ image.setBackground(ele);
+ }
+ }
+}
diff --git a/entry/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/slice/MainAbilitySlice.java b/entry/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/slice/MainAbilitySlice.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c7f678f43d3e941169631ed59668e00cc72fb77
--- /dev/null
+++ b/entry/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/slice/MainAbilitySlice.java
@@ -0,0 +1,131 @@
+package com.simplecityapps.recyclerview_fastscroll.sample.slice;
+
+import com.simplecityapps.recyclerview_fastscroll.sample.PagerAdapter;
+import com.simplecityapps.recyclerview_fastscroll.sample.ResourceTable;
+import ohos.aafwk.ability.AbilitySlice;
+import ohos.aafwk.content.Intent;
+import ohos.agp.components.Component;
+import ohos.agp.components.PageSlider;
+import ohos.agp.components.Text;
+import ohos.agp.utils.Color;
+import ohos.agp.utils.Point;
+import ohos.agp.window.service.Display;
+import ohos.agp.window.service.DisplayManager;
+import ohos.agp.window.service.WindowManager;
+
+import java.util.Optional;
+
+public class MainAbilitySlice extends AbilitySlice {
+ PageSlider pageslider;
+ Text text1;
+ Text text2;
+
+ private float textLeft1;
+ private float textLeft2;
+
+ private float lastV;
+
+ Point pt = new Point();
+ @Override
+ public void onStart(Intent intent) {
+ super.onStart(intent);
+ super.setUIContent(ResourceTable.Layout_ability_main);
+ getWindow().setStatusBarColor(Color.getIntColor("#2E409F"));
+ getWindow().addWindowFlags(WindowManager.LayoutConfig.MARK_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+
+ pageslider = (PageSlider) findComponentById(ResourceTable.Id_pageslider);
+ text1 = (Text) findComponentById(ResourceTable.Id_text1);
+ text2 = (Text) findComponentById(ResourceTable.Id_text2);
+
+ Optional
+ display = DisplayManager.getInstance().getDefaultDisplay(MainAbilitySlice.this);
+ display.get().getSize(pt);
+ text1.setBindStateChangedListener(new Component.BindStateChangedListener() {
+ @Override
+ public void onComponentBoundToWindow(Component component) {
+ textLeft1 = pt.getPointX() / 2f - text1.getWidth() / 2f;
+ text1.setTranslationX(textLeft1);
+ }
+
+ @Override
+ public void onComponentUnboundFromWindow(Component component) {
+
+ }
+ });
+ text2.setBindStateChangedListener(new Component.BindStateChangedListener() {
+ @Override
+ public void onComponentBoundToWindow(Component component) {
+ textLeft2 = pt.getPointX() - text2.getWidth();
+ text2.setTranslationX(textLeft2);
+ }
+
+ @Override
+ public void onComponentUnboundFromWindow(Component component) {
+
+ }
+ });
+ pageslider.setProvider(new PagerAdapter(this));
+
+ pageslider.addPageChangedListener(new PageSlider.PageChangedListener() {
+ @Override
+ public void onPageSliding(int i, float v, int i1) {
+
+ if(i1 < lastV&& lastV==1){
+ lastV = 1;
+ }else{
+ lastV = i1;
+ }
+
+ System.out.println("addPageChangedListener onPageSliding " + i + "==" + lastV + "==" + i1);
+
+ if (lastV > 0) {
+ if(v>0.5){
+ text1.setTextColor(new Color(Color.getIntColor("#787878")));
+ text2.setTextColor(new Color(Color.getIntColor("#000000")));
+ text1.setTranslationX(0);
+ text2.setTranslationX(textLeft2-textLeft2*(v-0.5f));
+ }else{
+ text1.setTranslationX(textLeft1-textLeft1*v*2);
+ text2.setTranslationX(textLeft2);
+ text1.setTextColor(new Color(Color.getIntColor("#000000")));
+ text2.setTextColor(new Color(Color.getIntColor("#787878")));
+ }
+ } else {
+ if(v>0.5){
+ text2.setTranslationX(textLeft2);
+ text1.setTranslationX(textLeft1*(v-0.5f)*2);
+ text1.setTextColor(new Color(Color.getIntColor("#000000")));
+ text2.setTextColor(new Color(Color.getIntColor("#787878")));
+ }else{
+ text2.setTranslationX(textLeft1+textLeft1*v*2);
+ text1.setTranslationX(0);
+ text1.setTextColor(new Color(Color.getIntColor("#787878")));
+ text2.setTextColor(new Color(Color.getIntColor("#000000")));
+ }
+ }
+
+
+ }
+
+ @Override
+ public void onPageSlideStateChanged(int i) {
+ System.out.println("addPageChangedListener onPageSlideStateChanged " + i);
+ }
+
+ @Override
+ public void onPageChosen(int i) {
+ System.out.println("addPageChangedListener onPageChosen " + i);
+ }
+ });
+ }
+
+ @Override
+ public void onActive() {
+ super.onActive();
+ }
+
+ @Override
+ public void onForeground(Intent intent) {
+ super.onForeground(intent);
+ }
+}
diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..c2a6b66cf9bbe3634a9332007717dfd5f2db38bf
--- /dev/null
+++ b/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "entry_MainAbility",
+ "value": "entry_MainAbility"
+ },
+ {
+ "name": "mainability_description",
+ "value": "Java_Empty Ability"
+ },
+ {
+ "name": "mainability_HelloWorld",
+ "value": "Hello World"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/entry/src/main/resources/base/graphic/background_ability_main.xml b/entry/src/main/resources/base/graphic/background_ability_main.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c0c0a3df480fa387a452b9c40ca191cc918a3fc0
--- /dev/null
+++ b/entry/src/main/resources/base/graphic/background_ability_main.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/entry/src/main/resources/base/layout/ability_main.xml b/entry/src/main/resources/base/layout/ability_main.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3f525650d8eab79241835336295f892e383961b7
--- /dev/null
+++ b/entry/src/main/resources/base/layout/ability_main.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/entry/src/main/resources/base/layout/list_item.xml b/entry/src/main/resources/base/layout/list_item.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bd0fe171830c5d123deb9a5b53de6243381cb409
--- /dev/null
+++ b/entry/src/main/resources/base/layout/list_item.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/entry/src/main/resources/base/layout/list_item_header.xml b/entry/src/main/resources/base/layout/list_item_header.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e5cb4323e976b33922da7ec04b8671b1c7c21ed0
--- /dev/null
+++ b/entry/src/main/resources/base/layout/list_item_header.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/entry/src/main/resources/base/layout/page_item.xml b/entry/src/main/resources/base/layout/page_item.xml
new file mode 100644
index 0000000000000000000000000000000000000000..73e8824f4ab05bbdb857ec48df20fbc13c5ffdb4
--- /dev/null
+++ b/entry/src/main/resources/base/layout/page_item.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/entry/src/main/resources/base/media/ic_extension_24dp.xml b/entry/src/main/resources/base/media/ic_extension_24dp.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6a6646f4176c4023c5f1abc97daf4f479038ff5f
--- /dev/null
+++ b/entry/src/main/resources/base/media/ic_extension_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/entry/src/main/resources/base/media/icon.png b/entry/src/main/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/entry/src/main/resources/base/media/icon.png differ
diff --git a/entry/src/main/resources/base/media/list_divider.xml b/entry/src/main/resources/base/media/list_divider.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1001ee14290e76f52dab4e8e6d0128d4efb09f80
--- /dev/null
+++ b/entry/src/main/resources/base/media/list_divider.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/entry/src/main/resources/en/element/string.json b/entry/src/main/resources/en/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..e35cbbceb4e9d9f6fa193b9a340079d880e7e855
--- /dev/null
+++ b/entry/src/main/resources/en/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "entry_MainAbility",
+ "value": "RecyclerView-FastScroll"
+ },
+ {
+ "name": "mainability_description",
+ "value": "Java_Empty Ability"
+ },
+ {
+ "name": "mainability_HelloWorld",
+ "value": "Hello World"
+ }
+ ]
+}
diff --git a/entry/src/main/resources/zh/element/string.json b/entry/src/main/resources/zh/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..5d32f6f95ec396d5cd62727840513447dd4479ea
--- /dev/null
+++ b/entry/src/main/resources/zh/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "entry_MainAbility",
+ "value": "RecyclerView-FastScroll"
+ },
+ {
+ "name": "mainability_description",
+ "value": "Java_Empty Ability"
+ },
+ {
+ "name": "mainability_HelloWorld",
+ "value": "你好,世界"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/entry/src/ohosTest/java/com/simplecityapps/recyclerview_fastscroll/sample/ExampleOhosTest.java b/entry/src/ohosTest/java/com/simplecityapps/recyclerview_fastscroll/sample/ExampleOhosTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b71f9b4562e40acb8082992d831906e019770d7b
--- /dev/null
+++ b/entry/src/ohosTest/java/com/simplecityapps/recyclerview_fastscroll/sample/ExampleOhosTest.java
@@ -0,0 +1,18 @@
+package com.simplecityapps.recyclerview_fastscroll.sample;
+
+import ohos.aafwk.ability.delegation.AbilityDelegatorRegistry;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ExampleOhosTest {
+
+ /**
+ * 纯UI组件,不涉及单元测试
+ */
+ @Test
+ public void testBundleName() {
+ final String actualBundleName = AbilityDelegatorRegistry.getArguments().getTestBundleName();
+ assertEquals("com.simplecityapps.recyclerview_fastscroll.sample", actualBundleName);
+ }
+}
\ No newline at end of file
diff --git a/entry/src/test/java/com/simplecityapps/recyclerview_fastscroll/sample/ExampleTest.java b/entry/src/test/java/com/simplecityapps/recyclerview_fastscroll/sample/ExampleTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..70fd52142d35b815a1ed5dd2ccda05f216359206
--- /dev/null
+++ b/entry/src/test/java/com/simplecityapps/recyclerview_fastscroll/sample/ExampleTest.java
@@ -0,0 +1,9 @@
+package com.simplecityapps.recyclerview_fastscroll.sample;
+
+import org.junit.Test;
+
+public class ExampleTest {
+ @Test
+ public void onStart() {
+ }
+}
diff --git a/gradle.properties b/gradle.properties
index 210ead18ea374fd2c1dae2b5dc956d9ced11a3d1..be492496f9a20ac2d980ef4fc30061f4184c1c40 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,19 +1,13 @@
# Project-wide Gradle settings.
-
-# IDE (e.g. Android Studio) users:
+# IDE (e.g. DevEco Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
-
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
-
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-# Default value: -Xmx10248m -XX:MaxPermSize=256m
-# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
-
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-android.useAndroidX=true
+# If the Chinese output is garbled, please configure the following parameter.
+# This function is enabled by default when the DevEco Studio builds the hap/app,if you need disable gradle parallel,you should set org.gradle.parallel false.
+# more information see https://docs.gradle.org/current/userguide/performance.html
+# org.gradle.parallel=false
+# org.gradle.jvmargs=-Dfile.encoding=GBK
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 05ef575b0cd0173fc735f2857ce4bd594ce4f6bd..490fda8577df6c95960ba7077c43220e5bb2c0d9 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 8a5f7719e01c30d8137dba89ff2c7b327479aac4..f59159e865d4b59feb1b8c44b001f62fc5d58df4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,2 +1,5 @@
-#Fri Feb 08 13:50:42 AEDT 2019
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.2-all.zip
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://repo.huaweicloud.com/gradle/gradle-6.3-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 9d82f78915133e1c35a6ea51252590fb38efac2f..2fe81a7d95e4f9ad2c9b2a046707d36ceb3980b3 100755
--- a/gradlew
+++ b/gradlew
@@ -1,4 +1,20 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
##############################################################################
##
@@ -6,20 +22,38 @@
##
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
-warn ( ) {
+warn () {
echo "$*"
}
-die ( ) {
+die () {
echo
echo "$*"
echo
@@ -30,6 +64,7 @@ die ( ) {
cygwin=false
msys=false
darwin=false
+nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
@@ -40,26 +75,11 @@ case "`uname`" in
MINGW* )
msys=true
;;
+ NONSTOP* )
+ nonstop=true
+ ;;
esac
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -85,7 +105,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -105,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
@@ -134,27 +154,30 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
- i=$((i+1))
+ i=`expr $i + 1`
done
case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index aec99730b4e8fcd90b57a0e8e01544fea7c31a89..62bd9b9ccefea2b65ae41e5d9a545e2021b90a1d 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,90 +1,103 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/img/1.gif b/img/1.gif
new file mode 100644
index 0000000000000000000000000000000000000000..bfd76e594e0d4f7a075ca69e987a1aad7135996b
Binary files /dev/null and b/img/1.gif differ
diff --git a/img/2.gif b/img/2.gif
new file mode 100644
index 0000000000000000000000000000000000000000..7cb233e7f1820b6df765916bcefa1e17977cf653
Binary files /dev/null and b/img/2.gif differ
diff --git a/recyclerview-fastscroll/bintray.properties b/recyclerview-fastscroll/bintray.properties
deleted file mode 100644
index 3a13b4c245dc40c72e176a7fb1a7ebc0dd7dbe82..0000000000000000000000000000000000000000
--- a/recyclerview-fastscroll/bintray.properties
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Copyright (c) 2016 Tim Malseed
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-group = com.simplecityapps
-version = 2.0.1
-
-repo = maven
-pkgName = recyclerview-fastscroll
-description = A simple FastScroller for Android's RecyclerView
-
-siteUrl = https://github.com/timusus/RecyclerView-FastScroll
-issuesUrl = https://github.com/timusus/RecyclerView-FastScroll/issues
-gitUrl = https://github.com/timusus/RecyclerView-FastScroll.git
-
-licenceName = Apache License Version 2.0
-licenceUrl = http://www.apache.org/licenses/LICENSE-2.0.txt
-licenceDistribution = repo
-
-developerId = timusus
-developerName = Tim Malseed
-developerEmail = t.malseed@gmail.com
-
-publishJavadoc = true
-publishSources = true
-publishDownloadNumbers = true
\ No newline at end of file
diff --git a/recyclerview-fastscroll/build.gradle b/recyclerview-fastscroll/build.gradle
deleted file mode 100644
index eae4c7df834f909a380332e6c38a46e2c5c5447c..0000000000000000000000000000000000000000
--- a/recyclerview-fastscroll/build.gradle
+++ /dev/null
@@ -1,29 +0,0 @@
-apply plugin: 'com.android.library'
-
-android {
- compileSdkVersion 28
- buildToolsVersion "28.0.3"
-
- defaultConfig {
- minSdkVersion 14
- versionCode 18
- versionName "2.0.1"
- }
-
- lintOptions {
- abortOnError false
- }
-}
-
-dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
-
- //RecyclerView
- implementation 'androidx.recyclerview:recyclerview:1.1.0'
-
- // AppCompat
- implementation 'androidx.appcompat:appcompat:1.1.0'
-}
-
-//To deploy, re-comment following line & run ./gradlew clean assembleRelease install bintrayUpload
-//apply from : 'deploy.gradle'
\ No newline at end of file
diff --git a/recyclerview-fastscroll/deploy.gradle b/recyclerview-fastscroll/deploy.gradle
deleted file mode 100644
index d0cbe5b6aac48a1e41b9cc8432667293d72d7fef..0000000000000000000000000000000000000000
--- a/recyclerview-fastscroll/deploy.gradle
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2016 Tim Malseed
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-apply plugin: 'com.github.dcendents.android-maven'
-apply plugin: 'com.jfrog.bintray'
-
-def Properties bintrayProps = new Properties()
-File bintrayProperties = file('bintray.properties')
-if (bintrayProperties.exists()) {
- bintrayProps.load(new FileInputStream(bintrayProperties))
-}
-
-group = bintrayProps['group']
-version = bintrayProps['version']
-
-def pkgRepo = bintrayProps['repo']
-def pkgName = bintrayProps['pkgName']
-def libraryDescription = bintrayProps['description']
-
-def siteUrl = bintrayProps['siteUrl'] // Homepage URL of the library
-def gitUrl = bintrayProps['gitUrl'] // Git repository URL
-def issuesUrl = bintrayProps['issuesUrl']
-
-def licenceName = bintrayProps['licenceName']
-def licenceUrl = bintrayProps['licenceUrl']
-def licenceDistribution = bintrayProps['licenceDistribution']
-
-def developerId = bintrayProps['developerId']
-def developerName = bintrayProps['developerName']
-def developerEmail = bintrayProps['developerEmail']
-def developerOrg = bintrayProps['developerOrg']
-
-def publishJavadoc = bintrayProps['publishJavadoc']
-def publishSources = bintrayProps['publishSources']
-def publishDownloadNumbers = bintrayProps['publishDownloadNumbers']
-
-task sourcesJar(type: Jar) {
- from android.sourceSets.main.java.srcDirs
- classifier = 'sources'
-}
-
-task javadoc(type: Javadoc) {
- source = android.sourceSets.main.java.srcDirs
- classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
-}
-
-task javadocJar(type: Jar, dependsOn: javadoc) {
- classifier = 'javadoc'
- from javadoc.destinationDir
-}
-
-artifacts {
- if (publishJavadoc) {
- archives javadocJar
- }
- if (publishSources) {
- archives sourcesJar
- }
-}
-
-Properties properties = new Properties()
-File propertiesFile = project.rootProject.file('local.properties')
-if(propertiesFile.exists()) {
- properties.load(new FileInputStream(propertiesFile))
-} else {
- properties.setProperty('bintray.apikey', System.getenv('BINTRAY_KEY'))
- properties.setProperty('bintray.user', System.getenv('BINTRAY_USER'))
-}
-
-bintray {
- user = properties['bintray.user']
- key = properties['bintray.apikey']
-
- configurations = ['archives']
- publish = true
-
- pkg {
- repo = pkgRepo
- if (developerOrg) {
- userOrg = developerOrg
- }
- name = pkgName
- desc = libraryDescription
- websiteUrl = siteUrl
- vcsUrl = gitUrl
- issueTrackerUrl = issuesUrl
- publicDownloadNumbers = publishDownloadNumbers
- version {
- name = project.version
- vcsTag = project.version
- gpg {
- sign = true //Determines whether to GPG sign the files. The default is false
- passphrase = properties.getProperty("bintray.gpg.password")
- //Optional. The passphrase for GPG signing'
- }
- }
- }
-}
-
-install {
- repositories.mavenInstaller {
- pom {
- project {
- packaging 'aar'
- name pkgName
- description libraryDescription
- url siteUrl
- licenses {
- license {
- name licenceName
- url licenceUrl
- distribution licenceDistribution
- }
- }
- developers {
- developer {
- id developerId
- name developerName
- if (developerEmail) {
- email developerEmail
- }
- }
- }
- scm {
- connection gitUrl
- developerConnection gitUrl
- url siteUrl
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/recyclerview-fastscroll/src/main/AndroidManifest.xml b/recyclerview-fastscroll/src/main/AndroidManifest.xml
deleted file mode 100644
index eaef0fd5a0726e396d2e53f0d7d7bf9307bd0c50..0000000000000000000000000000000000000000
--- a/recyclerview-fastscroll/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
diff --git a/recyclerview-fastscroll/src/main/res/values/attrs.xml b/recyclerview-fastscroll/src/main/res/values/attrs.xml
deleted file mode 100644
index 8fa521d20db247d4cb85fa527e8517c9d8f180a3..0000000000000000000000000000000000000000
--- a/recyclerview-fastscroll/src/main/res/values/attrs.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/sample/.gitignore b/recyclerview_fastscroll/.gitignore
similarity index 31%
rename from sample/.gitignore
rename to recyclerview_fastscroll/.gitignore
index 796b96d1c402326528b4ba3c12ee9d92d0e212e9..924c6961b7baf13cb71666efb6e646b3841b2ca7 100644
--- a/sample/.gitignore
+++ b/recyclerview_fastscroll/.gitignore
@@ -1 +1,2 @@
/build
+/upload.gradle
diff --git a/recyclerview_fastscroll/build.gradle b/recyclerview_fastscroll/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..02beede046b2c6269a3c4aaa16fdc12c0b766404
--- /dev/null
+++ b/recyclerview_fastscroll/build.gradle
@@ -0,0 +1,22 @@
+apply plugin: 'com.huawei.ohos.library'
+//For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510
+ohos {
+ compileSdkVersion 6
+ defaultConfig {
+ compatibleSdkVersion 5
+ }
+ buildTypes {
+ release {
+ proguardOpt {
+ proguardEnabled false
+ rulesFiles 'proguard-rules.pro'
+ }
+ }
+ }
+
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ testImplementation 'junit:junit:4.13'
+}
diff --git a/recyclerview_fastscroll/consumer-rules.pro b/recyclerview_fastscroll/consumer-rules.pro
new file mode 100644
index 0000000000000000000000000000000000000000..9dccc613bc71b04b83531f550bdab2fb667ecfc9
--- /dev/null
+++ b/recyclerview_fastscroll/consumer-rules.pro
@@ -0,0 +1 @@
+# Add har specific ProGuard rules for consumer here.
\ No newline at end of file
diff --git a/recyclerview_fastscroll/proguard-rules.pro b/recyclerview_fastscroll/proguard-rules.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f7666e47561d514b2a76d5a7dfbb43ede86da92a
--- /dev/null
+++ b/recyclerview_fastscroll/proguard-rules.pro
@@ -0,0 +1 @@
+# config module specific ProGuard rules here.
\ No newline at end of file
diff --git a/recyclerview_fastscroll/src/main/config.json b/recyclerview_fastscroll/src/main/config.json
new file mode 100644
index 0000000000000000000000000000000000000000..f7adb26f5e8c913aa2c63865fca1e42e1a97e328
--- /dev/null
+++ b/recyclerview_fastscroll/src/main/config.json
@@ -0,0 +1,24 @@
+{
+ "app": {
+ "bundleName": "com.simplecityapps.recyclerview_fastscroll.sample",
+ "vendor": "simplecityapps",
+ "version": {
+ "code": 1000000,
+ "name": "1.0.0"
+ }
+ },
+ "deviceConfig": {
+ },
+ "module": {
+ "package": "com.simplecityapps.recyclerview_fastscroll",
+ "deviceType": [
+ "phone",
+ "tv"
+ ],
+ "distro": {
+ "deliveryWithInstall": true,
+ "moduleName": "recyclerview_fastscroll",
+ "moduleType": "har"
+ }
+ }
+}
\ No newline at end of file
diff --git a/recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/interfaces/OnFastScrollStateChangeListener.java b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/interfaces/OnFastScrollStateChangeListener.java
similarity index 100%
rename from recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/interfaces/OnFastScrollStateChangeListener.java
rename to recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/interfaces/OnFastScrollStateChangeListener.java
diff --git a/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/RectUtils.java b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/RectUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a1582cd13320077a78a235b594d3c7c2e16e1ed
--- /dev/null
+++ b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/RectUtils.java
@@ -0,0 +1,19 @@
+package com.simplecityapps.recyclerview_fastscroll.utils;
+
+import ohos.agp.utils.Rect;
+
+public class RectUtils {
+
+ public static void inset(Rect rect,int dx, int dy) {
+ rect.left += dx;
+ rect.top += dy;
+ rect.right -= dx;
+ rect.bottom -= dy;
+ }
+
+ public static boolean contains(Rect rect,int x, int y) {
+ return rect.left < rect.right && rect.top < rect.bottom // check for empty first
+ && x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom;
+ }
+
+}
diff --git a/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/TypedAttrUtils.java b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/TypedAttrUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..0bdea0d07a459fe7a272fce1264b13158c030181
--- /dev/null
+++ b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/TypedAttrUtils.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.simplecityapps.recyclerview_fastscroll.utils;
+
+import ohos.agp.components.Attr;
+import ohos.agp.components.AttrSet;
+import ohos.agp.components.element.Element;
+import ohos.agp.utils.Color;
+import ohos.hiviewdfx.HiLog;
+import ohos.hiviewdfx.HiLogLabel;
+
+import java.util.NoSuchElementException;
+
+/**
+ * @ClassName: TypedAttrUtils
+ * @Description: TypedAttrUtils 工具类
+ * @CreateDate: 2021/4/15 15:55
+ * @UpdateUser: 更新者
+ * @UpdateDate: 2021/4/15 15:55
+ * @UpdateRemark: 更新内容
+ * @Version: 1.0
+ */
+public final class TypedAttrUtils {
+ static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "zhk");
+
+ /**
+ * getLayoutDimension
+ *
+ * @param attrs 集合
+ * @param attrName attrName
+ * @param defValue defValue
+ * @return int
+ */
+ public static int getIntColor(AttrSet attrs, String attrName, int defValue) {
+ Attr attr = attrNoSuchElement(attrs, attrName);
+ if (attr == null) {
+ return defValue;
+ } else {
+ return attr.getColorValue().getValue();
+ }
+ }
+
+ /**
+ * getLayoutDimension
+ *
+ * @param attrs 集合
+ * @param attrName attrName
+ * @param defValue defValue
+ * @return color
+ */
+ public static Color getColor(AttrSet attrs, String attrName, Color defValue) {
+ Attr attr = attrNoSuchElement(attrs, attrName);
+ if (attr == null) {
+ return defValue;
+ } else {
+ return attr.getColorValue();
+ }
+ }
+
+ /**
+ * getColor
+ *
+ * @param attrs 集合
+ * @param attrName attrName
+ * @param defValue defValue
+ * @return color
+ */
+ public static Color getColor(AttrSet attrs, String attrName, int defValue) {
+ return getColor(attrs, attrName, new Color(defValue));
+ }
+
+ /**
+ * getLayoutDimension
+ *
+ * @param attrs 集合
+ * @param attrName attrName
+ * @param defValue defValue
+ * @return int
+ */
+ public static int getInteger(AttrSet attrs, String attrName, int defValue) {
+ Attr attr = attrNoSuchElement(attrs, attrName);
+ if (attr == null) {
+ return defValue;
+ } else {
+ return attr.getIntegerValue();
+ }
+ }
+
+ /**
+ * getElement
+ *
+ * @param attrs attrs
+ * @param attrName attrName
+ * @param defValue defValue
+ * @return Element
+ */
+ public static Element getElement(AttrSet attrs, String attrName, Element defValue) {
+ Attr attr = attrNoSuchElement(attrs, attrName);
+ if (attr == null) {
+ return defValue;
+ } else {
+ return attr.getElement();
+ }
+ }
+
+ /**
+ * getLayoutDimension
+ *
+ * @param attrs 集合
+ * @param attrName attrName
+ * @param defValue defValue
+ * @return float
+ */
+ public static float getFloat(AttrSet attrs, String attrName, float defValue) {
+ Attr attr = attrNoSuchElement(attrs, attrName);
+ if (attr == null) {
+ return defValue;
+ } else {
+ return attr.getFloatValue();
+ }
+ }
+
+ /**
+ * getLayoutDimension
+ *
+ * @param attrs 集合
+ * @param attrName attrName
+ * @param defValue defValue
+ * @return long
+ */
+ public static long getLong(AttrSet attrs, String attrName, long defValue) {
+ Attr attr = attrNoSuchElement(attrs, attrName);
+ if (attr == null) {
+ return defValue;
+ } else {
+ return attr.getLongValue();
+ }
+ }
+
+ /**
+ * getLayoutDimension
+ *
+ * @param attrs 集合
+ * @param attrName attrName
+ * @param isDefValue defValue
+ * @return boolean
+ */
+ public static boolean getBoolean(AttrSet attrs, String attrName, boolean isDefValue) {
+ Attr attr = attrNoSuchElement(attrs, attrName);
+ if (attr == null) {
+ return isDefValue;
+ } else {
+ return attr.getBoolValue();
+ }
+ }
+
+ /**
+ * getLayoutDimension
+ *
+ * @param attrs 集合
+ * @param attrName attrName
+ * @param defValue defValue
+ * @return String
+ */
+ public static String getString(AttrSet attrs, String attrName, String defValue) {
+ Attr attr = attrNoSuchElement(attrs, attrName);
+ if (attr == null) {
+ return defValue;
+ } else {
+ return attr.getStringValue();
+ }
+ }
+
+ /**
+ * getLayoutDimension
+ *
+ * @param attrs 集合
+ * @param attrName attrName
+ * @param defValue defValue
+ * @return int
+ */
+ public static float getDimensionPixelSize(AttrSet attrs, String attrName, float defValue) {
+ Attr attr = attrNoSuchElement(attrs, attrName);
+ if (attr == null) {
+ return defValue;
+ } else {
+ return attr.getDimensionValue();
+ }
+ }
+
+ /**
+ * getLayoutDimension
+ *
+ * @param attrs 集合
+ * @param attrName attrName
+ * @param defValue defValue
+ * @return int
+ */
+ public static int getLayoutDimension(AttrSet attrs, String attrName, int defValue) {
+ Attr attr = attrNoSuchElement(attrs, attrName);
+ if (attr == null) {
+ return defValue;
+ } else {
+ HiLog.info(LABEL, "attr.getDimensionValue() = " + attr.getDimensionValue());
+ return attr.getDimensionValue();
+ }
+ }
+
+ private static Attr attrNoSuchElement(AttrSet attrs, String attrName) {
+ Attr attr = null;
+ try {
+ attr = attrs.getAttr(attrName).get();
+ } catch (NoSuchElementException e) {
+ HiLog.info(LABEL, "Exception = " + e.toString());
+ }
+ return attr;
+ }
+}
diff --git a/recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/Utils.java b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/Utils.java
similarity index 38%
rename from recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/Utils.java
rename to recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/Utils.java
index f3bc8ea68d196ddced31d8fc43b7289c39e2a7ed..31aeebdbb9fb2292be13bb8f5a848ab78d968fed 100644
--- a/recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/Utils.java
+++ b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/utils/Utils.java
@@ -16,39 +16,59 @@
package com.simplecityapps.recyclerview_fastscroll.utils;
-import android.annotation.TargetApi;
-import android.content.res.Resources;
-import android.os.Build;
-import android.util.TypedValue;
-import android.view.View;
+import ohos.agp.components.AttrHelper;
+import ohos.agp.utils.Rect;
+import ohos.agp.utils.RectFloat;
+import ohos.app.Context;
public class Utils {
/**
* Converts dp to px
*
- * @param res Resources
- * @param dp the value in dp
+ * @param context Resources
+ * @param dp the value in dp
* @return int
*/
- public static int toPixels(Resources res, float dp) {
- return (int) (dp * res.getDisplayMetrics().density);
+ public static int toPixels(Context context, float dp) {
+ return AttrHelper.vp2px(dp, context);
}
/**
* Converts sp to px
*
- * @param res Resources
- * @param sp the value in sp
+ * @param context Resources
+ * @param sp the value in sp
* @return int
*/
- public static int toScreenPixels(Resources res, float sp) {
- return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, res.getDisplayMetrics());
+ public static int toScreenPixels(Context context, float sp) {
+ return AttrHelper.fp2px(sp, context);
}
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
- public static boolean isRtl(Resources res) {
- return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) &&
- (res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
+ public static boolean isRtl() {
+ return false;
+ }
+
+ public static void rectUnion(Rect one, Rect tow) {
+ if ((tow.left < tow.right) && (tow.top < tow.bottom)) {
+ if ((one.left < one.right) && (one.top < one.bottom)) {
+ if (one.left > tow.left) one.left = tow.left;
+ if (one.top > tow.top) one.top = tow.top;
+ if (one.right < tow.right) one.right = tow.right;
+ if (one.bottom < tow.bottom) one.bottom = tow.bottom;
+ } else {
+ one.left = tow.left;
+ one.top = tow.top;
+ one.right = tow.right;
+ one.bottom = tow.bottom;
+ }
+ }
+ }
+
+ public static void rectFloatSet(RectFloat one, RectFloat tow) {
+ one.bottom = tow.bottom;
+ one.top = tow.top;
+ one.left = tow.left;
+ one.right = tow.right;
}
}
diff --git a/recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollPopup.java b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollPopup.java
similarity index 67%
rename from recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollPopup.java
rename to recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollPopup.java
index 7290b8ce86048f313cfa5c4d55d92ab26f940245..e4aee1e55c1d6769f2c3b8a6ea9f98ca9d29d8f4 100644
--- a/recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollPopup.java
+++ b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollPopup.java
@@ -16,34 +16,26 @@
package com.simplecityapps.recyclerview_fastscroll.views;
-import android.animation.ObjectAnimator;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Typeface;
-import android.text.TextUtils;
-
import com.simplecityapps.recyclerview_fastscroll.utils.Utils;
-
-import androidx.annotation.Keep;
+import ohos.agp.animation.AnimatorValue;
+import ohos.agp.render.Canvas;
+import ohos.agp.render.Paint;
+import ohos.agp.render.Path;
+import ohos.agp.text.Font;
+import ohos.agp.utils.Color;
+import ohos.agp.utils.Rect;
+import ohos.agp.utils.RectFloat;
+import ohos.agp.utils.TextTool;
public class FastScrollPopup {
private FastScrollRecyclerView mRecyclerView;
-
- private Resources mRes;
-
private int mBackgroundSize;
private int mCornerRadius;
private Path mBackgroundPath = new Path();
- private RectF mBackgroundRect = new RectF();
+ private RectFloat mBackgroundRect = new RectFloat();
private Paint mBackgroundPaint;
- private int mBackgroundColor = 0xff000000;
private Rect mInvalidateRect = new Rect();
private Rect mTmpRect = new Rect();
@@ -58,52 +50,49 @@ public class FastScrollPopup {
private float mAlpha = 1;
- private ObjectAnimator mAlphaAnimator;
+ private AnimatorValue mAlphaAnimator;
private boolean mVisible;
@FastScroller.PopupTextVerticalAlignmentMode private int mTextVerticalAlignmentMode;
@FastScroller.PopupPosition private int mPosition;
- FastScrollPopup(Resources resources, FastScrollRecyclerView recyclerView) {
-
- mRes = resources;
-
+ FastScrollPopup( FastScrollRecyclerView recyclerView) {
mRecyclerView = recyclerView;
- mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
- mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBackgroundPaint = new Paint();
+ mBackgroundPaint.setAntiAlias(true);
+ mTextPaint = new Paint();
+ mTextPaint.setAntiAlias(true);
mTextPaint.setAlpha(0);
- setTextSize(Utils.toScreenPixels(mRes, 32));
- setBackgroundSize(Utils.toPixels(mRes, 62));
+ setTextSize(Utils.toScreenPixels(recyclerView.getContext(), 32));
+ setBackgroundSize(Utils.toPixels(recyclerView.getContext(), 62));
}
- public void setBgColor(int color) {
- mBackgroundColor = color;
+ public void setBgColor(Color color) {
mBackgroundPaint.setColor(color);
- mRecyclerView.invalidate(mBgBounds);
+ mRecyclerView.invalidate();
}
- public void setTextColor(int color) {
+ public void setTextColor(Color color) {
mTextPaint.setColor(color);
- mRecyclerView.invalidate(mBgBounds);
+ mRecyclerView.invalidate();
}
public void setTextSize(int size) {
mTextPaint.setTextSize(size);
- mRecyclerView.invalidate(mBgBounds);
+ mRecyclerView.invalidate();
}
public void setBackgroundSize(int size) {
mBackgroundSize = size;
mCornerRadius = mBackgroundSize / 2;
- mRecyclerView.invalidate(mBgBounds);
+ mRecyclerView.invalidate();
}
- public void setTypeface(Typeface typeface) {
- mTextPaint.setTypeface(typeface);
- mRecyclerView.invalidate(mBgBounds);
+ public void setTypeface(Font typeface) {
+ mTextPaint.setFont(typeface);
+ mRecyclerView.invalidate();
}
/**
@@ -113,22 +102,33 @@ public class FastScrollPopup {
if (mVisible != visible) {
mVisible = visible;
if (mAlphaAnimator != null) {
+ mAlphaAnimator.release();
mAlphaAnimator.cancel();
}
- mAlphaAnimator = ObjectAnimator.ofFloat(this, "alpha", visible ? 1f : 0f);
- mAlphaAnimator.setDuration(visible ? 200 : 150);
- mAlphaAnimator.start();
+ if (visible) {
+ setAlpha(1);
+ } else {
+ setAlpha(0);
+ }
+// mAlphaAnimator = new AnimatorValue();
+// mAlphaAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
+// @Override
+// public void onUpdate(AnimatorValue animatorValue, float v) {
+//
+// mRecyclerView.invalidate();
+// }
+// });
+// mAlphaAnimator.setDuration(visible ? 200 : 150);
+// mAlphaAnimator.start();
}
}
// Setter/getter for the popup alpha for animations
- @Keep
public void setAlpha(float alpha) {
mAlpha = alpha;
- mRecyclerView.invalidate(mBgBounds);
+ mRecyclerView.invalidate();
}
- @Keep
public float getAlpha() {
return mAlpha;
}
@@ -156,7 +156,7 @@ public class FastScrollPopup {
return new float[]{mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius};
}
- if (Utils.isRtl(mRes)) {
+ if (mRecyclerView.isRtl()) {
return new float[]{mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, 0, 0};
} else {
return new float[]{mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, 0, 0, mCornerRadius, mCornerRadius};
@@ -167,32 +167,33 @@ public class FastScrollPopup {
if (isVisible()) {
// Draw the fast scroller popup
int restoreCount = canvas.save();
- canvas.translate(mBgBounds.left, mBgBounds.top);
- mTmpRect.set(mBgBounds);
- mTmpRect.offsetTo(0, 0);
-
+// canvas.translate(mBgBounds.left, mBgBounds.top);
+ mTmpRect.set(mBgBounds.left,mBgBounds.top,mBgBounds.right,mBgBounds.bottom);
+ mTmpRect.offset(0, 0);
mBackgroundPath.reset();
- mBackgroundRect.set(mTmpRect);
+ mBackgroundRect.bottom =mTmpRect.bottom;
+ mBackgroundRect.top =mTmpRect.top;
+ mBackgroundRect.left =mTmpRect.left;
+ mBackgroundRect.right =mTmpRect.right;
float[] radii = createRadii();
float baselinePosition;
if (mTextVerticalAlignmentMode == FastScroller.PopupTextVerticalAlignmentMode.FONT_METRICS) {
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
- baselinePosition = (mBgBounds.height() - fontMetrics.ascent - fontMetrics.descent) / 2f;
+ baselinePosition = (mBgBounds.getHeight() - fontMetrics.ascent - fontMetrics.descent) / 2f;
} else {
- baselinePosition = (mBgBounds.height() + mTextBounds.height()) / 2f;
+ baselinePosition = (mBgBounds.getHeight() + mTextBounds.getHeight()) / 2f;
}
- mBackgroundPath.addRoundRect(mBackgroundRect, radii, Path.Direction.CW);
+ mBackgroundPath.addRoundRect(mBackgroundRect, radii, Path.Direction.CLOCK_WISE);
- mBackgroundPaint.setAlpha((int) (Color.alpha(mBackgroundColor) * mAlpha));
- mTextPaint.setAlpha((int) (mAlpha * 255));
+ mBackgroundPaint.setAlpha(mAlpha);
+ mTextPaint.setAlpha((int) (mAlpha * 1));
canvas.drawPath(mBackgroundPath, mBackgroundPaint);
- canvas.drawText(
+ canvas.drawText(mTextPaint,
mSectionName,
- (mBgBounds.width() - mTextBounds.width()) / 2f,
- baselinePosition,
- mTextPaint
+ (mBgBounds.getWidth() - mTextBounds.getWidth()) / 2f+mBgBounds.left,
+ baselinePosition+mBgBounds.top
);
canvas.restoreToCount(restoreCount);
}
@@ -201,7 +202,7 @@ public class FastScrollPopup {
public void setSectionName(String sectionName) {
if (!sectionName.equals(mSectionName)) {
mSectionName = sectionName;
- mTextPaint.getTextBounds(sectionName, 0, sectionName.length(), mTextBounds);
+ mTextBounds = mTextPaint.getTextBounds(sectionName);
// Update the width to use measureText since that is more accurate
mTextBounds.right = (int) (mTextBounds.left + mTextPaint.measureText(sectionName));
}
@@ -213,20 +214,20 @@ public class FastScrollPopup {
* @return the invalidation rect for this update.
*/
public Rect updateFastScrollerBounds(FastScrollRecyclerView recyclerView, int thumbOffsetY) {
- mInvalidateRect.set(mBgBounds);
+ mInvalidateRect.set(mBgBounds.left,mBgBounds.top,mBgBounds.right,mBgBounds.bottom);
if (isVisible()) {
// Calculate the dimensions and position of the fast scroller popup
int edgePadding = recyclerView.getScrollBarWidth();
- int bgPadding = Math.round((mBackgroundSize - mTextBounds.height()) / 10f) * 5;
+ int bgPadding = Math.round((mBackgroundSize - mTextBounds.getHeight()) / 10f) * 5;
int bgHeight = mBackgroundSize;
- int bgWidth = Math.max(mBackgroundSize, mTextBounds.width() + (2 * bgPadding));
+ int bgWidth = Math.max(mBackgroundSize, mTextBounds.getWidth() + (2 * bgPadding));
if (mPosition == FastScroller.PopupPosition.CENTER) {
mBgBounds.left = (recyclerView.getWidth() - bgWidth) / 2;
mBgBounds.right = mBgBounds.left + bgWidth;
mBgBounds.top = (recyclerView.getHeight() - bgHeight) / 2;
} else {
- if (Utils.isRtl(mRes)) {
+ if (recyclerView.isRtl()) {
mBgBounds.left = (2 * recyclerView.getScrollBarWidth());
mBgBounds.right = mBgBounds.left + bgWidth;
} else {
@@ -238,15 +239,16 @@ public class FastScrollPopup {
}
mBgBounds.bottom = mBgBounds.top + bgHeight;
} else {
- mBgBounds.setEmpty();
+ mBgBounds.clear();
}
// Combine the old and new fast scroller bounds to create the full invalidate rect
- mInvalidateRect.union(mBgBounds);
+ Utils.rectUnion(mInvalidateRect,mBgBounds);
return mInvalidateRect;
}
+
public boolean isVisible() {
- return (mAlpha > 0f) && (!TextUtils.isEmpty(mSectionName));
+ return (mAlpha > 0f) && (!TextTool.isNullOrEmpty(mSectionName));
}
}
diff --git a/recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollRecyclerView.java b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollRecyclerView.java
similarity index 35%
rename from recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollRecyclerView.java
rename to recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollRecyclerView.java
index 5dfe6f49d19b55e599d82f5f59305b4d6754c830..49e1ffb38d7ccd37c2f673af4c09ad2054342c6c 100644
--- a/recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollRecyclerView.java
+++ b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScrollRecyclerView.java
@@ -16,83 +16,67 @@
package com.simplecityapps.recyclerview_fastscroll.views;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Typeface;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseIntArray;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.simplecityapps.recyclerview_fastscroll.R;
+import com.simplecityapps.recyclerview_fastscroll.utils.TypedAttrUtils;
import com.simplecityapps.recyclerview_fastscroll.interfaces.OnFastScrollStateChangeListener;
-import com.simplecityapps.recyclerview_fastscroll.utils.Utils;
+import ohos.agp.components.AttrSet;
+import ohos.agp.components.Component;
+import ohos.agp.database.DataSetSubscriber;
+import ohos.agp.render.Canvas;
+import ohos.agp.text.Font;
+import ohos.agp.utils.Color;
+import ohos.app.Context;
+import ohos.multimodalinput.event.TouchEvent;
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
+import java.util.HashMap;
-public class FastScrollRecyclerView extends RecyclerView implements RecyclerView.OnItemTouchListener {
-
- private static final String TAG = "FastScrollRecyclerView";
+public class FastScrollRecyclerView extends RecyclerView implements Component.TouchEventListener, Component.DrawTask {
private FastScroller mScrollbar;
private boolean mFastScrollEnabled = true;
- /**
- * The current scroll state of the recycler view. We use this in onUpdateScrollbar()
- * and scrollToPositionAtProgress() to determine the scroll position of the recycler view so
- * that we can calculate what the scroll bar looks like, and where to jump to from the fast
- * scroller.
- */
- public static class ScrollPositionState {
- // The index of the first visible row
- int rowIndex;
- // The offset of the first visible row
- int rowTopOffset;
- // The height of a given row (they are currently all the same height)
- int rowHeight;
- }
-
- private ScrollPositionState mScrollPosState = new ScrollPositionState();
+ private float mDownX;
+ private float mDownY;
+ private float mLastY;
- private int mDownX;
- private int mDownY;
- private int mLastY;
-
- private SparseIntArray mScrollOffsets;
+ private HashMap mScrollOffsets;
private ScrollOffsetInvalidator mScrollOffsetInvalidator;
+
private OnFastScrollStateChangeListener mStateChangeListener;
+ /**
+ * 构造
+ *
+ * @param context context
+ */
public FastScrollRecyclerView(Context context) {
- this(context, null);
+ super(context);
}
- public FastScrollRecyclerView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ /**
+ * 构造
+ *
+ * @param context context
+ * @param attrs attrs
+ */
+ public FastScrollRecyclerView(Context context, AttrSet attrs) {
+ super(context, attrs);
+ init(context,attrs);
}
- public FastScrollRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public FastScrollRecyclerView(Context context, AttrSet attrs, String defStyleAttr) {
super(context, attrs, defStyleAttr);
+ init(context, attrs);
+ }
- TypedArray typedArray = context.getTheme().obtainStyledAttributes(
- attrs, R.styleable.FastScrollRecyclerView, 0, 0);
- try {
- mFastScrollEnabled = typedArray.getBoolean(R.styleable.FastScrollRecyclerView_fastScrollThumbEnabled, true);
- } finally {
- typedArray.recycle();
- }
-
+ private void init(Context context, AttrSet attrs) {
+ mFastScrollEnabled = TypedAttrUtils.getBoolean(attrs, "fastScrollThumbEnabled", true);
mScrollbar = new FastScroller(context, this, attrs);
mScrollOffsetInvalidator = new ScrollOffsetInvalidator();
- mScrollOffsets = new SparseIntArray();
+ mScrollOffsets = new HashMap();
+ addDrawTask(this);
+ setTouchEventListener(this);
}
public int getScrollBarWidth() {
@@ -103,69 +87,80 @@ public class FastScrollRecyclerView extends RecyclerView implements RecyclerView
return mScrollbar.getThumbHeight();
}
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- addOnItemTouchListener(this);
- }
-
- @Override
- public void setAdapter(Adapter adapter) {
+ public void setAdapter(RecyclerView.Adapter adapter) {
if (getAdapter() != null) {
- getAdapter().unregisterAdapterDataObserver(mScrollOffsetInvalidator);
+ getAdapter().removeDataSubscriber(mScrollOffsetInvalidator);
}
if (adapter != null) {
- adapter.registerAdapterDataObserver(mScrollOffsetInvalidator);
+ adapter.addDataSubscriber(mScrollOffsetInvalidator);
}
-
- super.setAdapter(adapter);
+ setItemProvider(adapter);
}
- /**
- * We intercept the touch handling only to support fast scrolling when initiated from the
- * scroll bar. Otherwise, we fall back to the default RecyclerView touch handling.
- */
- @Override
- public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent ev) {
- return handleTouchEvent(ev);
+ private RecyclerView.Adapter getAdapter() {
+ return (RecyclerView.Adapter) getItemProvider();
}
@Override
- public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent ev) {
- handleTouchEvent(ev);
+ public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
+ return handleTouchEvent(touchEvent);
}
/**
* Handles the touch event and determines whether to show the fast scroller (or updates it if
* it is already showing).
*/
- private boolean handleTouchEvent(MotionEvent ev) {
+ private boolean handleTouchEvent(TouchEvent ev) {
int action = ev.getAction();
- int x = (int) ev.getX();
- int y = (int) ev.getY();
+ float x = getTouchX(ev, 0, this);
+ float y = getTouchY(ev, 0, this);
switch (action) {
- case MotionEvent.ACTION_DOWN:
+ case TouchEvent.PRIMARY_POINT_DOWN:
// Keep track of the down positions
mDownX = x;
mDownY = mLastY = y;
mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY, mStateChangeListener);
- break;
- case MotionEvent.ACTION_MOVE:
+ return true;
+ case TouchEvent.POINT_MOVE:
+ if (mLastY != y && mScrollbar.isDragging()) {
+ scrollBy(0, (int) (-(mLastY - y) / getAvailableScrollBarHeight() * getAvailableScrollHeight((int) getAdapterHeight(), 0)));
+ }
mLastY = y;
mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY, mStateChangeListener);
break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
+ case TouchEvent.PRIMARY_POINT_UP:
+ case TouchEvent.CANCEL:
mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY, mStateChangeListener);
break;
}
return mScrollbar.isDragging();
}
- @Override
- public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ private float getTouchX(TouchEvent event, int index, Component component) {
+ float x = 0;
+ if (event.getPointerCount() > index) {
+ int[] xy = component.getLocationOnScreen();
+ if (xy != null && xy.length == 2) {
+ x = event.getPointerScreenPosition(index).getX() - xy[0];
+ } else {
+ x = event.getPointerPosition(index).getX();
+ }
+ }
+ return x;
+ }
+ private float getTouchY(TouchEvent event, int index, Component component) {
+ float y = 0;
+ if (event.getPointerCount() > index) {
+ int[] xy = component.getLocationOnScreen();
+ if (xy != null && xy.length == 2) {
+ y = event.getPointerScreenPosition(index).getY() - xy[1];
+ } else {
+ y = event.getPointerPosition(index).getY();
+ }
+ }
+ return y;
}
/**
@@ -189,183 +184,31 @@ public class FastScrollRecyclerView extends RecyclerView implements RecyclerView
return visibleHeight - mScrollbar.getThumbHeight();
}
+
@Override
- public void draw(Canvas c) {
- super.draw(c);
+ public void onDraw(Component component, Canvas canvas) {
if (mFastScrollEnabled) {
onUpdateScrollbar();
- mScrollbar.draw(c);
+ mScrollbar.draw(canvas);
}
}
- /**
- * Updates the scrollbar thumb offset to match the visible scroll of the recycler view. It does
- * this by mapping the available scroll area of the recycler view to the available space for the
- * scroll bar.
- *
- * @param scrollPosState the current scroll position
- * @param rowCount the number of rows, used to calculate the total scroll height (assumes that
- */
- protected void updateThumbPosition(ScrollPositionState scrollPosState, int rowCount) {
- int availableScrollHeight;
- int availableScrollBarHeight;
- int scrolledPastHeight;
-
- if (getAdapter() instanceof MeasurableAdapter) {
- availableScrollHeight = getAvailableScrollHeight(calculateAdapterHeight(), 0);
- scrolledPastHeight = calculateScrollDistanceToPosition(scrollPosState.rowIndex);
- } else {
- availableScrollHeight = getAvailableScrollHeight(rowCount * scrollPosState.rowHeight, 0);
- scrolledPastHeight = scrollPosState.rowIndex * scrollPosState.rowHeight;
- }
-
- availableScrollBarHeight = getAvailableScrollBarHeight();
-
- // Only show the scrollbar if there is height to be scrolled
- if (availableScrollHeight <= 0) {
- mScrollbar.setThumbPosition(-1, -1);
- return;
- }
-
- // Calculate the current scroll position, the scrollY of the recycler view accounts for the
- // view padding, while the scrollBarY is drawn right up to the background padding (ignoring
- // padding)
- int scrollY = Math.min(availableScrollHeight, getPaddingTop() + scrolledPastHeight);
- if (isLayoutManagerReversed()) {
- scrollY = scrollY + scrollPosState.rowTopOffset - availableScrollBarHeight;
- } else {
- scrollY = scrollY - scrollPosState.rowTopOffset;
- }
- int scrollBarY = (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
- if (isLayoutManagerReversed()) {
- scrollBarY = availableScrollBarHeight - scrollBarY + getPaddingBottom();
- } else {
- scrollBarY += getPaddingTop();
- }
-
- // Calculate the position and size of the scroll bar
- int scrollBarX;
- if (Utils.isRtl(getResources())) {
- scrollBarX = 0;
- } else {
- scrollBarX = getWidth() - mScrollbar.getWidth();
- }
- mScrollbar.setThumbPosition(scrollBarX, scrollBarY);
- }
-
/**
* Maps the touch (from 0..1) to the adapter position that should be visible.
*/
- public String scrollToPositionAtProgress(float touchFraction) {
- int itemCount = getAdapter().getItemCount();
- if (itemCount == 0) {
- return "";
- }
- int spanCount = 1;
- int rowCount = itemCount;
- if (getLayoutManager() instanceof GridLayoutManager) {
- spanCount = ((GridLayoutManager) getLayoutManager()).getSpanCount();
- rowCount = (int) Math.ceil((double) rowCount / spanCount);
- }
-
- // Stop the scroller if it is scrolling
- stopScroll();
-
- getCurScrollState(mScrollPosState);
-
- float itemPos;
- int availableScrollHeight;
-
- int scrollPosition;
- int scrollOffset;
-
- if (getAdapter() instanceof MeasurableAdapter) {
- itemPos = findItemPosition(touchFraction);
- availableScrollHeight = getAvailableScrollHeight(calculateAdapterHeight(), 0);
- int passedHeight = (int) (availableScrollHeight * touchFraction);
- scrollPosition = findMeasureAdapterFirstVisiblePosition(passedHeight);
- scrollOffset = calculateScrollDistanceToPosition(scrollPosition) - passedHeight;
- } else {
- itemPos = findItemPosition(touchFraction);
- availableScrollHeight = getAvailableScrollHeight(rowCount * mScrollPosState.rowHeight, 0);
-
- //The exact position of our desired item
- int exactItemPos = (int) (availableScrollHeight * touchFraction);
-
- //The offset used here is kind of hard to explain.
- //If the position we wish to scroll to is, say, position 10.5, we scroll to position 10,
- //and then offset by 0.5 * rowHeight. This is how we achieve smooth scrolling.
- scrollPosition = spanCount * exactItemPos / mScrollPosState.rowHeight;
- scrollOffset = -(exactItemPos % mScrollPosState.rowHeight);
- }
-
- LinearLayoutManager layoutManager = ((LinearLayoutManager) getLayoutManager());
- layoutManager.scrollToPositionWithOffset(scrollPosition, scrollOffset);
-
+ public String scrollToPositionAtProgress(float touchFraction1, float barTop) {
if (!(getAdapter() instanceof SectionedAdapter)) {
return "";
}
-
- int posInt = (int) ((touchFraction == 1) ? getAdapter().getItemCount() - 1 : itemPos);
-
SectionedAdapter sectionedAdapter = (SectionedAdapter) getAdapter();
- return sectionedAdapter.getSectionName(posInt);
- }
- @SuppressWarnings("unchecked")
- private int findMeasureAdapterFirstVisiblePosition(int passedHeight) {
- if (getAdapter() instanceof MeasurableAdapter) {
- MeasurableAdapter measurableAdapter = (MeasurableAdapter) getAdapter();
- for (int i = 0; i < getAdapter().getItemCount(); i++) {
- int top = calculateScrollDistanceToPosition(i);
- int bottom = top + measurableAdapter.getViewTypeHeight(this, findViewHolderForAdapterPosition(i), getAdapter().getItemViewType(i));
- if (i == getAdapter().getItemCount() - 1) {
- if (passedHeight >= top && passedHeight <= bottom) {
- return i;
- }
- } else {
- if (passedHeight >= top && passedHeight < bottom) {
- return i;
- }
- }
- }
- int low = calculateScrollDistanceToPosition(0);
- int height = calculateScrollDistanceToPosition(getAdapter().getItemCount() - 1)
- + measurableAdapter.getViewTypeHeight(this, findViewHolderForAdapterPosition(getAdapter().getItemCount() - 1), getAdapter().getItemViewType(getAdapter().getItemCount() - 1));
- throw new IllegalStateException(String.format("Invalid passed height: %d, [low: %d, height: %d]", passedHeight, low, height));
- } else {
- throw new IllegalStateException("findMeasureAdapterFirstVisiblePosition() should only be called where the RecyclerView.Adapter is an instance of MeasurableAdapter");
+ if (touchFraction1 == 0) {
+ return sectionedAdapter.getSectionName(0);
}
- }
-
- @SuppressWarnings("unchecked")
- private float findItemPosition(float touchFraction) {
-
- if (getAdapter() instanceof MeasurableAdapter) {
- MeasurableAdapter measurer = (MeasurableAdapter) getAdapter();
- int viewTop = (int) (touchFraction * calculateAdapterHeight());
-
- for (int i = 0; i < getAdapter().getItemCount(); i++) {
- int top = calculateScrollDistanceToPosition(i);
- int bottom = top + measurer.getViewTypeHeight(this, findViewHolderForAdapterPosition(i), getAdapter().getItemViewType(i));
- if (i == getAdapter().getItemCount() - 1) {
- if (viewTop >= top && viewTop <= bottom) {
- return i;
- }
- } else {
- if (viewTop >= top && viewTop < bottom) {
- return i;
- }
- }
- }
+ int posInt = getPosition(getOffsetY() + barTop);
- // Should never happen
- Log.w(TAG, "Failed to find a view at the provided scroll fraction (" + touchFraction + ")");
- return touchFraction * getAdapter().getItemCount();
- } else {
- return getAdapter().getItemCount() * touchFraction;
- }
+ return sectionedAdapter.getSectionName(posInt);
}
/**
@@ -377,129 +220,133 @@ public class FastScrollRecyclerView extends RecyclerView implements RecyclerView
return;
}
- int rowCount = getAdapter().getItemCount();
- if (getLayoutManager() instanceof GridLayoutManager) {
- int spanCount = ((GridLayoutManager) getLayoutManager()).getSpanCount();
- rowCount = (int) Math.ceil((double) rowCount / spanCount);
- }
+ int rowCount = getAdapter().getCount();
+
// Skip early if, there are no items.
if (rowCount == 0) {
mScrollbar.setThumbPosition(-1, -1);
return;
}
- // Skip early if, there no child laid out in the container.
- getCurScrollState(mScrollPosState);
- if (mScrollPosState.rowIndex < 0) {
- mScrollbar.setThumbPosition(-1, -1);
- return;
+ int scrollBarX;
+ int scrollBarY;
+ if (isRtl()) {
+ scrollBarX = 0;
+ } else {
+ scrollBarX = getWidth() - mScrollbar.getWidth();
}
- updateThumbPosition(mScrollPosState, rowCount);
- }
+ scrollBarY = (int) ((getOffsetY() / getAvailableScrollHeight((int) getAdapterHeight(), 0)) * getAvailableScrollBarHeight());
+ scrollBarY += getPaddingTop();
- protected boolean isLayoutManagerReversed() {
- if (getLayoutManager() instanceof LinearLayoutManager) {
- return ((LinearLayoutManager) getLayoutManager()).getReverseLayout();
- }
- return false;
+ mScrollbar.setThumbPosition(scrollBarX, scrollBarY);
}
- /**
- * Returns the current scroll state of the apps rows.
- */
- @SuppressWarnings("unchecked")
- private void getCurScrollState(ScrollPositionState stateOut) {
- stateOut.rowIndex = -1;
- stateOut.rowTopOffset = -1;
- stateOut.rowHeight = -1;
-
- int itemCount = getAdapter().getItemCount();
-
- // Return early if there are no items, or no children.
- if (itemCount == 0 || getChildCount() == 0) {
- return;
+ private float getOffsetY() {
+ float height = 0;
+ if (getAdapter() == null) {
+ return height;
}
+ int rowIndex = getItemPosByVisibleIndex(0);
+ Component component = getComponentAt(rowIndex);
- View child = getChildAt(0);
-
- stateOut.rowIndex = getChildAdapterPosition(child);
- if (getLayoutManager() instanceof GridLayoutManager) {
- stateOut.rowIndex = stateOut.rowIndex / ((GridLayoutManager) getLayoutManager()).getSpanCount();
+ if (rowIndex == 0) {
+ return Math.abs(component.getContentPositionY());
}
+
if (getAdapter() instanceof MeasurableAdapter) {
- stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child);
- stateOut.rowHeight = ((MeasurableAdapter) getAdapter()).getViewTypeHeight(this, findViewHolderForAdapterPosition(stateOut.rowIndex), getAdapter().getItemViewType(stateOut.rowIndex));
+ out:
+ for (int i = 0; i < getAdapter().getCount(); i++) {
+ if (i == rowIndex) {
+ break out;
+ }
+ height += ((MeasurableAdapter) getAdapter()).getViewTypeHeight(this, null, getAdapter().getItemViewType(i));
+
+ }
} else {
- stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child);
- stateOut.rowHeight = child.getHeight() + getLayoutManager().getTopDecorationHeight(child)
- + getLayoutManager().getBottomDecorationHeight(child);
+ out:
+ for (int i = 0; i < getAdapter().getCount(); i++) {
+ if (i == rowIndex) {
+ break out;
+ }
+ height += component.getHeight();
+ }
}
+
+ return (height + Math.abs(component.getContentPositionY()));
}
/**
- * Calculates the total height of all views above a position in the recycler view. This method
- * should only be called when the attached adapter implements {@link MeasurableAdapter}.
- *
- * @param adapterIndex The index in the adapter to find the total height above the
- * corresponding view
- * @return The total height of all views above {@code adapterIndex} in pixels
+ * 适配器高度
*/
- @SuppressWarnings("unchecked")
- private int calculateScrollDistanceToPosition(int adapterIndex) {
- if (!(getAdapter() instanceof MeasurableAdapter)) {
- throw new IllegalStateException("calculateScrollDistanceToPosition() should only be called where the RecyclerView.Adapter is an instance of MeasurableAdapter");
- }
-
- if (mScrollOffsets.indexOfKey(adapterIndex) >= 0) {
- return mScrollOffsets.get(adapterIndex);
+ private float getAdapterHeight() {
+ float height = 0;
+ if (getAdapter() == null) {
+ return height;
}
- int totalHeight = 0;
- MeasurableAdapter measurer = (MeasurableAdapter) getAdapter();
-
- // TODO Take grid layouts into account
-
- for (int i = 0; i < adapterIndex; i++) {
- mScrollOffsets.put(i, totalHeight);
- int viewType = getAdapter().getItemViewType(i);
- totalHeight += measurer.getViewTypeHeight(this, findViewHolderForAdapterPosition(i), viewType);
+ if (getAdapter() instanceof MeasurableAdapter) {
+ for (int i = 0; i < getAdapter().getCount(); i++) {
+ height += ((MeasurableAdapter) getAdapter()).getViewTypeHeight(this, null, getAdapter().getItemViewType(i));
+ }
+ } else {
+ int rowIndex = getItemPosByVisibleIndex(0);
+ Component component = getComponentAt(rowIndex);
+ height = getAdapter().getCount() * component.getHeight();
}
- mScrollOffsets.put(adapterIndex, totalHeight);
- return totalHeight;
+ return height;
}
- /**
- * Calculates the total height of the recycler view. This method should only be called when the
- * attached adapter implements {@link MeasurableAdapter}.
- *
- * @return The total height of all rows in the RecyclerView
- */
- private int calculateAdapterHeight() {
- if (!(getAdapter() instanceof MeasurableAdapter)) {
- throw new IllegalStateException("calculateAdapterHeight() should only be called where the RecyclerView.Adapter is an instance of MeasurableAdapter");
+ private int getPosition(float scrollHeight) {
+ float tempHeight = 0.0F;
+ int position = 0;
+ int itemHeight = 0;
+ if (getAdapter() instanceof MeasurableAdapter) {
+ out:
+ for (int i = 0; i < getAdapter().getCount(); i++) {
+ itemHeight = ((MeasurableAdapter) getAdapter()).getViewTypeHeight(this, null, getAdapter().getItemViewType(i));
+ if ((tempHeight + (itemHeight / 2f)) >= scrollHeight || (tempHeight + itemHeight) >= scrollHeight) {
+ position = i;
+ break out;
+ } else {
+ tempHeight += itemHeight;
+ }
+ }
+ } else {
+ int rowIndex = getItemPosByVisibleIndex(0);
+ Component component = getComponentAt(rowIndex);
+ out:
+ for (int i = 0; i < getAdapter().getCount(); i++) {
+ itemHeight = component.getHeight();
+ if ((tempHeight + (itemHeight / 2f)) >= scrollHeight || (tempHeight + itemHeight) >= scrollHeight) {
+ position = i;
+ break out;
+ } else {
+ tempHeight += itemHeight;
+ }
+ }
}
- return calculateScrollDistanceToPosition(getAdapter().getItemCount());
+ return position;
}
public void showScrollbar() {
mScrollbar.show();
}
- public void setThumbColor(@ColorInt int color) {
+ public void setThumbColor(Color color) {
mScrollbar.setThumbColor(color);
}
- public void setTrackColor(@ColorInt int color) {
+ public void setTrackColor(Color color) {
mScrollbar.setTrackColor(color);
}
- public void setPopupBgColor(@ColorInt int color) {
+ public void setPopupBgColor(Color color) {
mScrollbar.setPopupBgColor(color);
}
- public void setPopupTextColor(@ColorInt int color) {
+ public void setPopupTextColor(Color color) {
mScrollbar.setPopupTextColor(color);
}
@@ -507,7 +354,7 @@ public class FastScrollRecyclerView extends RecyclerView implements RecyclerView
mScrollbar.setPopupTextSize(textSize);
}
- public void setPopUpTypeface(Typeface typeface) {
+ public void setPopUpTypeface(Font typeface) {
mScrollbar.setPopupTypeface(typeface);
}
@@ -528,7 +375,7 @@ public class FastScrollRecyclerView extends RecyclerView implements RecyclerView
setOnFastScrollStateChangeListener(stateChangeListener);
}
- public void setThumbInactiveColor(@ColorInt int color) {
+ public void setThumbInactiveColor(Color color) {
mScrollbar.setThumbInactiveColor(color);
}
@@ -557,9 +404,10 @@ public class FastScrollRecyclerView extends RecyclerView implements RecyclerView
*/
public void setPopupPosition(@FastScroller.PopupPosition int popupPosition) {
mScrollbar.setPopupPosition(popupPosition);
+
}
- private class ScrollOffsetInvalidator extends AdapterDataObserver {
+ private class ScrollOffsetInvalidator extends DataSetSubscriber {
private void invalidateAllScrollOffsets() {
mScrollOffsets.clear();
}
@@ -570,33 +418,43 @@ public class FastScrollRecyclerView extends RecyclerView implements RecyclerView
}
@Override
- public void onItemRangeChanged(int positionStart, int itemCount) {
+ public void onInvalidated() {
+ }
+
+ @Override
+ public void onItemChanged(int position) {
invalidateAllScrollOffsets();
}
@Override
- public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+ public void onItemInserted(int position) {
invalidateAllScrollOffsets();
}
@Override
- public void onItemRangeInserted(int positionStart, int itemCount) {
+ public void onItemRemoved(int position) {
invalidateAllScrollOffsets();
}
@Override
- public void onItemRangeRemoved(int positionStart, int itemCount) {
+ public void onItemRangeChanged(int positionStart, int itemCount) {
invalidateAllScrollOffsets();
}
+
@Override
- public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ invalidateAllScrollOffsets();
+ }
+
+ @Override
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
invalidateAllScrollOffsets();
}
}
public interface SectionedAdapter {
- @NonNull
+
String getSectionName(int position);
}
@@ -606,7 +464,7 @@ public class FastScrollRecyclerView extends RecyclerView implements RecyclerView
* can be calculated. If your list uses different view heights, then make your adapter implement
* this interface.
*/
- public interface MeasurableAdapter {
+ public interface MeasurableAdapter {
/**
* Gets the height of a specific view type, including item decorations
*
@@ -615,6 +473,6 @@ public class FastScrollRecyclerView extends RecyclerView implements RecyclerView
* @param viewType The view type to get the height of
* @return The height of a single view for the given view type in pixels
*/
- int getViewTypeHeight(RecyclerView recyclerView, @Nullable VH viewHolder, int viewType);
+ int getViewTypeHeight(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int viewType);
}
}
diff --git a/recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScroller.java b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScroller.java
similarity index 43%
rename from recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScroller.java
rename to recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScroller.java
index fbc190c572d2098ca3674b33d5a7c486952198ad..d58497b05df5e203595bd1d042dc9005707bc342 100644
--- a/recyclerview-fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScroller.java
+++ b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/FastScroller.java
@@ -16,36 +16,29 @@
package com.simplecityapps.recyclerview_fastscroll.views;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Typeface;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-
-import com.simplecityapps.recyclerview_fastscroll.R;
+import com.simplecityapps.recyclerview_fastscroll.utils.TypedAttrUtils;
import com.simplecityapps.recyclerview_fastscroll.interfaces.OnFastScrollStateChangeListener;
+import com.simplecityapps.recyclerview_fastscroll.utils.RectUtils;
import com.simplecityapps.recyclerview_fastscroll.utils.Utils;
+import ohos.agp.animation.Animator;
+import ohos.agp.animation.AnimatorValue;
+import ohos.agp.components.AttrSet;
+import ohos.agp.components.Component;
+import ohos.agp.render.Canvas;
+import ohos.agp.render.Paint;
+import ohos.agp.text.Font;
+import ohos.agp.utils.Color;
+import ohos.agp.utils.Point;
+import ohos.agp.utils.Rect;
+import ohos.agp.utils.RectFloat;
+import ohos.app.Context;
+import ohos.eventhandler.EventHandler;
+import ohos.eventhandler.EventRunner;
+import ohos.eventhandler.InnerEvent;
+import ohos.multimodalinput.event.TouchEvent;
import java.lang.annotation.Retention;
-import androidx.annotation.ColorInt;
-import androidx.annotation.IntDef;
-import androidx.annotation.Keep;
-import androidx.annotation.NonNull;
-import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
-import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
-import androidx.recyclerview.widget.RecyclerView;
-
import static java.lang.annotation.RetentionPolicy.SOURCE;
@SuppressWarnings("WeakerAccess")
@@ -71,85 +64,79 @@ public class FastScroller {
// This is the offset from the top of the scrollbar when the user first starts touching. To
// prevent jumping, this offset is applied as the user scrolls.
- private int mTouchOffset;
+ private float mTouchOffset;
private Point mThumbPosition = new Point(-1, -1);
private Point mOffset = new Point(0, 0);
private boolean mIsDragging;
- private Animator mAutoHideAnimator;
+ private AnimatorValue mAutoHideAnimator;
private boolean mAnimatingShow;
private int mAutoHideDelay = DEFAULT_AUTO_HIDE_DELAY;
private boolean mAutoHideEnabled = true;
- private final Runnable mHideRunnable;
+ private Runnable mHideRunnable;
- private int mThumbActiveColor;
- private int mThumbInactiveColor = 0x79000000;
+ private Color mThumbActiveColor;
+ private Color mThumbInactiveColor;
private boolean mThumbInactiveState;
private int mTouchSlop;
-
- private int mLastY;
+ private EventHandler eventHandler = new EventHandler(EventRunner.getMainEventRunner()) {
+ protected void processEvent(InnerEvent event) {
+ super.processEvent(event);
+ }
+ };
@Retention(SOURCE)
- @IntDef({PopupTextVerticalAlignmentMode.TEXT_BOUNDS, PopupTextVerticalAlignmentMode.FONT_METRICS})
public @interface PopupTextVerticalAlignmentMode {
int TEXT_BOUNDS = 0;
int FONT_METRICS = 1;
}
- @IntDef({PopupPosition.ADJACENT, PopupPosition.CENTER})
+
public @interface PopupPosition {
int ADJACENT = 0;
int CENTER = 1;
}
- public FastScroller(Context context, FastScrollRecyclerView recyclerView, AttributeSet attrs) {
-
- Resources resources = context.getResources();
-
+ public FastScroller(Context context, FastScrollRecyclerView recyclerView, AttrSet attrs) {
mRecyclerView = recyclerView;
- mPopup = new FastScrollPopup(resources, recyclerView);
-
- mThumbHeight = Utils.toPixels(resources, 52);
- mThumbWidth = Utils.toPixels(resources, 8);
- mTrackWidth = Utils.toPixels(resources, 6);
-
- mTouchInset = Utils.toPixels(resources, -24);
-
- mThumb = new Paint(Paint.ANTI_ALIAS_FLAG);
- mTrack = new Paint(Paint.ANTI_ALIAS_FLAG);
-
- mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-
- TypedArray typedArray = context.getTheme().obtainStyledAttributes(
- attrs, R.styleable.FastScrollRecyclerView, 0, 0);
- try {
- mAutoHideEnabled = typedArray.getBoolean(R.styleable.FastScrollRecyclerView_fastScrollAutoHide, true);
- mAutoHideDelay = typedArray.getInteger(R.styleable.FastScrollRecyclerView_fastScrollAutoHideDelay, DEFAULT_AUTO_HIDE_DELAY);
- mThumbInactiveState = typedArray.getBoolean(R.styleable.FastScrollRecyclerView_fastScrollEnableThumbInactiveColor, true);
- mThumbActiveColor = typedArray.getColor(R.styleable.FastScrollRecyclerView_fastScrollThumbColor, 0x79000000);
- mThumbInactiveColor = typedArray.getColor(R.styleable.FastScrollRecyclerView_fastScrollThumbInactiveColor, 0x79000000);
-
- int trackColor = typedArray.getColor(R.styleable.FastScrollRecyclerView_fastScrollTrackColor, 0x28000000);
- int popupBgColor = typedArray.getColor(R.styleable.FastScrollRecyclerView_fastScrollPopupBgColor, 0xff000000);
- int popupTextColor = typedArray.getColor(R.styleable.FastScrollRecyclerView_fastScrollPopupTextColor, 0xffffffff);
- int popupTextSize = typedArray.getDimensionPixelSize(R.styleable.FastScrollRecyclerView_fastScrollPopupTextSize, Utils.toScreenPixels(resources, 32));
- int popupBackgroundSize = typedArray.getDimensionPixelSize(R.styleable.FastScrollRecyclerView_fastScrollPopupBackgroundSize, Utils.toPixels(resources, 62));
- @PopupTextVerticalAlignmentMode int popupTextVerticalAlignmentMode = typedArray.getInteger(R.styleable.FastScrollRecyclerView_fastScrollPopupTextVerticalAlignmentMode, PopupTextVerticalAlignmentMode.TEXT_BOUNDS);
- @PopupPosition int popupPosition = typedArray.getInteger(R.styleable.FastScrollRecyclerView_fastScrollPopupPosition, PopupPosition.ADJACENT);
-
- mTrack.setColor(trackColor);
- mThumb.setColor(mThumbInactiveState ? mThumbInactiveColor : mThumbActiveColor);
- mPopup.setBgColor(popupBgColor);
- mPopup.setTextColor(popupTextColor);
- mPopup.setTextSize(popupTextSize);
- mPopup.setBackgroundSize(popupBackgroundSize);
- mPopup.setPopupTextVerticalAlignmentMode(popupTextVerticalAlignmentMode);
- mPopup.setPopupPosition(popupPosition);
- } finally {
- typedArray.recycle();
- }
+ mPopup = new FastScrollPopup(recyclerView);
+
+ mThumbHeight = Utils.toPixels(context, 52);
+ mThumbWidth = Utils.toPixels(context, 8);
+ mTrackWidth = Utils.toPixels(context, 6);
+
+ mTouchInset = Utils.toPixels(context, -24);
+
+ mThumb = new Paint();
+ mThumb.setAntiAlias(true);
+ mTrack = new Paint();
+ mTrack.setAntiAlias(true);
+ mTouchSlop = 8;
+
+ mAutoHideEnabled = TypedAttrUtils.getBoolean(attrs, "fastScrollAutoHide", true);
+ mAutoHideDelay = TypedAttrUtils.getInteger(attrs, "fastScrollAutoHideDelay", DEFAULT_AUTO_HIDE_DELAY);
+ mThumbInactiveState = TypedAttrUtils.getBoolean(attrs, "fastScrollEnableThumbInactiveColor", true);
+ mThumbActiveColor = TypedAttrUtils.getColor(attrs, "fastScrollThumbColor", 0x79000000);
+ mThumbInactiveColor = TypedAttrUtils.getColor(attrs, "fastScrollThumbInactiveColor", 0x79000000);
+
+ Color trackColor = TypedAttrUtils.getColor(attrs, "fastScrollTrackColor", 0x28000000);
+ Color popupBgColor = TypedAttrUtils.getColor(attrs, "fastScrollPopupBgColor", 0xff000000);
+ Color popupTextColor = TypedAttrUtils.getColor(attrs, "fastScrollPopupTextColor", 0xffffffff);
+ int popupTextSize = (int) TypedAttrUtils.getDimensionPixelSize(attrs, "fastScrollPopupTextSize", Utils.toScreenPixels(recyclerView.getContext(), 32));
+ int popupBackgroundSize = (int) TypedAttrUtils.getDimensionPixelSize(attrs, "fastScrollPopupBackgroundSize", Utils.toPixels(recyclerView.getContext(), 62));
+ @PopupTextVerticalAlignmentMode int popupTextVerticalAlignmentMode = TypedAttrUtils.getInteger(attrs, "fastScrollPopupTextVerticalAlignmentMode", PopupTextVerticalAlignmentMode.TEXT_BOUNDS);
+ @PopupPosition int popupPosition = TypedAttrUtils.getInteger(attrs, "fastScrollPopupPosition", PopupPosition.ADJACENT);
+
+ mTrack.setColor(trackColor);
+ mThumb.setColor(mThumbInactiveState ? mThumbInactiveColor : mThumbActiveColor);
+ mPopup.setBgColor(popupBgColor);
+ mPopup.setTextColor(popupTextColor);
+ mPopup.setTextSize(popupTextSize);
+ mPopup.setBackgroundSize(popupBackgroundSize);
+ mPopup.setPopupTextVerticalAlignmentMode(popupTextVerticalAlignmentMode);
+ mPopup.setPopupPosition(popupPosition);
mHideRunnable = new Runnable() {
@Override
@@ -158,22 +145,29 @@ public class FastScroller {
if (mAutoHideAnimator != null) {
mAutoHideAnimator.cancel();
}
- mAutoHideAnimator = ObjectAnimator.ofInt(FastScroller.this, "offsetX", (Utils.isRtl(mRecyclerView.getResources()) ? -1 : 1) * getWidth());
- mAutoHideAnimator.setInterpolator(new FastOutLinearInInterpolator());
+
+ mAutoHideAnimator = new AnimatorValue();
+ mAutoHideAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
+ @Override
+ public void onUpdate(AnimatorValue animatorValue, float v) {
+ if (mRecyclerView.isRtl()) {
+ setOffsetX((int) (v * -1 * getWidth()));
+ } else {
+ setOffsetX((int) (v * 1 * getWidth()));
+ }
+ }
+ });
mAutoHideAnimator.setDuration(200);
mAutoHideAnimator.start();
}
}
};
- mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ mRecyclerView.addScrolledListener(new Component.ScrolledListener() {
@Override
- public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
- super.onScrolled(recyclerView, dx, dy);
-
- if (!mRecyclerView.isInEditMode()) {
- show();
- }
+ public void onContentScrolled(Component component, int i, int i1, int i2, int i3) {
+ show();
+ recyclerView.invalidate();
}
});
@@ -198,21 +192,21 @@ public class FastScroller {
* Handles the touch event and determines whether to show the fast scroller (or updates it if
* it is already showing).
*/
- public void handleTouchEvent(MotionEvent ev, int downX, int downY, int lastY,
+ public void handleTouchEvent(TouchEvent ev, float downX, float downY, float lastY,
OnFastScrollStateChangeListener stateChangeListener) {
int action = ev.getAction();
- int y = (int) ev.getY();
+ float y = getTouchY(ev, 0, mRecyclerView);
switch (action) {
- case MotionEvent.ACTION_DOWN:
+ case TouchEvent.PRIMARY_POINT_DOWN:
if (isNearPoint(downX, downY)) {
- mTouchOffset = downY - mThumbPosition.y;
+ mTouchOffset = downY - mThumbPosition.getPointY();
+ mRecyclerView.setEnabled(false);
}
break;
- case MotionEvent.ACTION_MOVE:
+ case TouchEvent.POINT_MOVE:
// Check if we should start scrolling
if (!mIsDragging && isNearPoint(downX, downY) &&
Math.abs(y - downY) > mTouchSlop) {
- mRecyclerView.getParent().requestDisallowInterceptTouchEvent(true);
mIsDragging = true;
mTouchOffset += (lastY - downY);
mPopup.animateVisibility(true);
@@ -223,37 +217,26 @@ public class FastScroller {
mThumb.setColor(mThumbActiveColor);
}
}
- if (mIsDragging) {
- if (mLastY == 0 || Math.abs(mLastY - y) >= mTouchSlop) {
- mLastY = y;
- // Update the fastscroller section name at this touch position
- boolean layoutManagerReversed = mRecyclerView.isLayoutManagerReversed();
- int bottom = mRecyclerView.getHeight() - mThumbHeight;
- float boundedY = (float) Math.max(0, Math.min(bottom, y - mTouchOffset));
-
- // Represents the amount the thumb has scrolled divided by its total scroll range
- float touchFraction = boundedY / bottom;
- if (layoutManagerReversed) {
- touchFraction = 1 - touchFraction;
- }
- String sectionName = mRecyclerView.scrollToPositionAtProgress(touchFraction);
- mPopup.setSectionName(sectionName);
- mPopup.animateVisibility(!sectionName.isEmpty());
- mRecyclerView.invalidate(mPopup.updateFastScrollerBounds(mRecyclerView, mThumbPosition.y));
- }
+ if(isDragging()){
+ float temp1 = (mThumbPosition.getPointY())/(mRecyclerView.getHeight()-getThumbHeight());
+ String sectionName = mRecyclerView.scrollToPositionAtProgress(temp1,mThumbPosition.getPointY()+getThumbHeight());
+ mPopup.setSectionName(sectionName);
+ mPopup.animateVisibility(!sectionName.isEmpty());
+ mPopup.updateFastScrollerBounds(mRecyclerView, (int) mThumbPosition.getPointY());
}
+ mRecyclerView.invalidate();
break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
+ case TouchEvent.PRIMARY_POINT_UP:
+ case TouchEvent.CANCEL:
mTouchOffset = 0;
- mLastY = 0;
if (mIsDragging) {
mIsDragging = false;
mPopup.animateVisibility(false);
if (stateChangeListener != null) {
stateChangeListener.onFastScrollStop();
}
+ mRecyclerView.setEnabled(true);
}
if (mThumbInactiveState) {
mThumb.setColor(mThumbInactiveColor);
@@ -262,107 +245,139 @@ public class FastScroller {
}
}
- RectF rect = new RectF();
+ private float getTouchY(TouchEvent event, int index, Component component) {
+ float y = 0;
+ if (event.getPointerCount() > index) {
+ int[] xy = component.getLocationOnScreen();
+ if (xy != null && xy.length == 2) {
+ y = event.getPointerScreenPosition(index).getY() - xy[1];
+ } else {
+ y = event.getPointerPosition(index).getY();
+ }
+ }
+ return y;
+ }
+
+ RectFloat rect = new RectFloat();
public void draw(Canvas canvas) {
- if (mThumbPosition.x < 0 || mThumbPosition.y < 0) {
+ if (mThumbPosition.getPointX() < 0 || mThumbPosition.getPointY() < 0) {
return;
}
-
//Background
- rect.set(mThumbPosition.x + mOffset.x + (mThumbWidth - mTrackWidth),
- mOffset.y + mRecyclerView.getPaddingTop(),
- mThumbPosition.x + mOffset.x + mTrackWidth + (mThumbWidth - mTrackWidth),
- mRecyclerView.getHeight() + mOffset.y - mRecyclerView.getPaddingBottom());
+ rect.left = mThumbPosition.getPointX() + mOffset.getPointX() + (mThumbWidth - mTrackWidth);
+ rect.top = mOffset.getPointY() + mRecyclerView.getPaddingTop();
+ rect.right = mThumbPosition.getPointX() + mOffset.getPointX() + mTrackWidth + (mThumbWidth - mTrackWidth);
+ rect.bottom = mRecyclerView.getHeight() + mOffset.getPointY() - mRecyclerView.getPaddingBottom();
canvas.drawRoundRect(rect,
mTrackWidth,
mTrackWidth,
mTrack);
//Handle
- rect.set(mThumbPosition.x + mOffset.x + (mThumbWidth - mTrackWidth) / 2,
- mThumbPosition.y + mOffset.y,
- mThumbPosition.x + mOffset.x + mThumbWidth + (mThumbWidth - mTrackWidth) / 2,
- mThumbPosition.y + mOffset.y + mThumbHeight);
+ rect.left = mThumbPosition.getPointX() + mOffset.getPointX() + (mThumbWidth - mTrackWidth) / 2f;
+ rect.top = mThumbPosition.getPointY() + mOffset.getPointY();
+ rect.right = mThumbPosition.getPointX() + mOffset.getPointX() + mThumbWidth + (mThumbWidth - mTrackWidth) / 2f;
+ rect.bottom = mThumbPosition.getPointY() + mOffset.getPointY() + mThumbHeight;
+
canvas.drawRoundRect(rect,
mThumbWidth,
mThumbWidth,
mThumb);
+
//Popup
mPopup.draw(canvas);
}
- /**
- * Returns whether the specified points are near the scroll bar bounds.
- */
- private boolean isNearPoint(int x, int y) {
- mTmpRect.set(mThumbPosition.x, mThumbPosition.y, mThumbPosition.x + mTrackWidth,
- mThumbPosition.y + mThumbHeight);
- mTmpRect.inset(mTouchInset, mTouchInset);
- return mTmpRect.contains(x, y);
+ private boolean isNearPoint(float x, float y) {
+ mTmpRect.set((int) (mThumbPosition.getPointX()), (int) mThumbPosition.getPointY(), (int) mThumbPosition.getPointX() + mTrackWidth,
+ (int) mThumbPosition.getPointY() + mThumbHeight);
+ RectUtils.inset(mTmpRect, mTouchInset, mTouchInset);
+ return RectUtils.contains(mTmpRect, (int) x, (int) y);
}
public void setThumbPosition(int x, int y) {
- if (mThumbPosition.x == x && mThumbPosition.y == y) {
+ if (mThumbPosition.getPointX() == x && mThumbPosition.getPointY() == y) {
return;
}
// do not create new objects here, this is called quite often
- mInvalidateRect.set(mThumbPosition.x + mOffset.x, mOffset.y, mThumbPosition.x + mOffset.x + mTrackWidth, mRecyclerView.getHeight() + mOffset.y);
- mThumbPosition.set(x, y);
- mInvalidateTmpRect.set(mThumbPosition.x + mOffset.x, mOffset.y, mThumbPosition.x + mOffset.x + mTrackWidth, mRecyclerView.getHeight() + mOffset.y);
- mInvalidateRect.union(mInvalidateTmpRect);
- mRecyclerView.invalidate(mInvalidateRect);
+ mInvalidateRect.set((int) mThumbPosition.getPointX() + (int) mOffset.getPointX(), (int) mOffset.getPointY(), (int) mThumbPosition.getPointX() + (int) mOffset.getPointX() + mTrackWidth, mRecyclerView.getHeight() + (int) mOffset.getPointY());
+ mThumbPosition.modify(x, y);
+ mInvalidateTmpRect.set((int) mThumbPosition.getPointX() + (int) mOffset.getPointX(), (int) mOffset.getPointY(), (int) mThumbPosition.getPointX() + (int) mOffset.getPointX() + mTrackWidth, mRecyclerView.getHeight() + (int) mOffset.getPointY());
+ Utils.rectUnion(mInvalidateRect, mInvalidateTmpRect);
+ mRecyclerView.invalidate();
}
-
public void setOffset(int x, int y) {
- if (mOffset.x == x && mOffset.y == y) {
+ if (mOffset.getPointX() == x && mOffset.getPointY() == y) {
return;
}
// do not create new objects here, this is called quite often
- mInvalidateRect.set(mThumbPosition.x + mOffset.x, mOffset.y, mThumbPosition.x + mOffset.x + mTrackWidth, mRecyclerView.getHeight() + mOffset.y);
- mOffset.set(x, y);
- mInvalidateTmpRect.set(mThumbPosition.x + mOffset.x, mOffset.y, mThumbPosition.x + mOffset.x + mTrackWidth, mRecyclerView.getHeight() + mOffset.y);
- mInvalidateRect.union(mInvalidateTmpRect);
- mRecyclerView.invalidate(mInvalidateRect);
+ mInvalidateRect.set((int) mThumbPosition.getPointX() + (int) mOffset.getPointX(), (int) mOffset.getPointY(), (int) mThumbPosition.getPointX() + (int) mOffset.getPointX() + mTrackWidth, mRecyclerView.getHeight() + (int) mOffset.getPointY());
+ mOffset.modify(x, y);
+ mInvalidateTmpRect.set((int) mThumbPosition.getPointX() + (int) mOffset.getPointX(), (int) mOffset.getPointY(), (int) mThumbPosition.getPointX() + (int) mOffset.getPointX() + mTrackWidth, mRecyclerView.getHeight() + (int) mOffset.getPointY());
+ Utils.rectUnion(mInvalidateRect, mInvalidateTmpRect);
+ mRecyclerView.invalidate();
}
- // Setter/getter for the popup alpha for animations
- @Keep
public void setOffsetX(int x) {
- setOffset(x, mOffset.y);
+ setOffset(x, (int) mOffset.getPointY());
}
- @Keep
public int getOffsetX() {
- return mOffset.x;
+ return (int) mOffset.getPointX();
}
public void show() {
- if (!mAnimatingShow) {
+ if (!mAnimatingShow && mOffset.getPointX() == getWidth()) {
if (mAutoHideAnimator != null) {
mAutoHideAnimator.cancel();
}
- mAutoHideAnimator = ObjectAnimator.ofInt(this, "offsetX", 0);
- mAutoHideAnimator.setInterpolator(new LinearOutSlowInInterpolator());
- mAutoHideAnimator.setDuration(150);
- mAutoHideAnimator.addListener(new AnimatorListenerAdapter() {
+
+ mAutoHideAnimator = new AnimatorValue();
+ mAutoHideAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
+ @Override
+ public void onUpdate(AnimatorValue animatorValue, float v) {
+ setOffsetX((int) (getWidth() - getWidth() * v));
+ }
+ });
+
+ mAutoHideAnimator.setStateChangedListener(new Animator.StateChangedListener() {
+ @Override
+ public void onStart(Animator animator) {
+
+ }
+
+ @Override
+ public void onStop(Animator animator) {
+
+ }
+
@Override
- public void onAnimationCancel(Animator animation) {
- super.onAnimationCancel(animation);
+ public void onCancel(Animator animator) {
mAnimatingShow = false;
}
@Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
+ public void onEnd(Animator animator) {
mAnimatingShow = false;
}
+
+ @Override
+ public void onPause(Animator animator) {
+
+ }
+
+ @Override
+ public void onResume(Animator animator) {
+
+ }
});
mAnimatingShow = true;
+ mAutoHideAnimator.setDuration(150);
mAutoHideAnimator.start();
}
if (mAutoHideEnabled) {
@@ -375,36 +390,37 @@ public class FastScroller {
protected void postAutoHideDelayed() {
if (mRecyclerView != null) {
cancelAutoHide();
- mRecyclerView.postDelayed(mHideRunnable, mAutoHideDelay);
+ eventHandler.removeTask(mHideRunnable);
+ eventHandler.postTask(mHideRunnable, mAutoHideDelay);
}
}
protected void cancelAutoHide() {
if (mRecyclerView != null) {
- mRecyclerView.removeCallbacks(mHideRunnable);
+ eventHandler.removeTask(mHideRunnable);
}
}
- public void setThumbColor(@ColorInt int color) {
+ public void setThumbColor(Color color) {
mThumbActiveColor = color;
mThumb.setColor(color);
- mRecyclerView.invalidate(mInvalidateRect);
+ mRecyclerView.invalidate();
}
- public void setTrackColor(@ColorInt int color) {
+ public void setTrackColor(Color color) {
mTrack.setColor(color);
- mRecyclerView.invalidate(mInvalidateRect);
+ mRecyclerView.invalidate();
}
- public void setPopupBgColor(@ColorInt int color) {
+ public void setPopupBgColor(Color color) {
mPopup.setBgColor(color);
}
- public void setPopupTextColor(@ColorInt int color) {
+ public void setPopupTextColor(Color color) {
mPopup.setTextColor(color);
}
- public void setPopupTypeface(Typeface typeface) {
+ public void setPopupTypeface(Font typeface) {
mPopup.setTypeface(typeface);
}
@@ -432,7 +448,7 @@ public class FastScroller {
mPopup.setPopupPosition(popupPosition);
}
- public void setThumbInactiveColor(@ColorInt int color) {
+ public void setThumbInactiveColor(Color color) {
mThumbInactiveColor = color;
enableThumbInactiveColor(true);
}
diff --git a/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/RecyclerView.java b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/RecyclerView.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb2692a002208fa78c294972063d2fdbdebb2939
--- /dev/null
+++ b/recyclerview_fastscroll/src/main/java/com/simplecityapps/recyclerview_fastscroll/views/RecyclerView.java
@@ -0,0 +1,66 @@
+package com.simplecityapps.recyclerview_fastscroll.views;
+
+import ohos.agp.components.*;
+import ohos.app.Context;
+
+public class RecyclerView extends ListContainer {
+
+ public RecyclerView(Context context) {
+ super(context);
+ }
+
+ public RecyclerView(Context context, AttrSet attrSet) {
+ super(context, attrSet);
+ }
+
+ public RecyclerView(Context context, AttrSet attrSet, String styleName) {
+ super(context, attrSet, styleName);
+ }
+
+ public abstract static class Adapter extends BaseItemProvider {
+
+ public abstract VH onCreateViewHolder(Component parent, int viewType);
+
+ public abstract void onBindViewHolder(ViewHolder holder, int position);
+
+ public abstract int getItemCount();
+
+ public abstract int getItemViewType(int position);
+
+ @Override
+ public int getCount() {
+ return getItemCount();
+ }
+
+ @Override
+ public Object getItem(int i) {
+ return i;
+ }
+
+ @Override
+ public long getItemId(int i) {
+ return i;
+ }
+
+ @Override
+ public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
+ ViewHolder viewHolder = onCreateViewHolder(componentContainer, getItemViewType(i));
+ viewHolder.itemView.setTag(i);
+ onBindViewHolder(viewHolder, i);
+ return viewHolder.itemView;
+ }
+ }
+
+ public static class ViewHolder {
+
+ public final Component itemView;
+
+ public ViewHolder(Component itemView) {
+ if (itemView == null) {
+ throw new IllegalArgumentException("itemView may not be null");
+ }
+ this.itemView = itemView;
+
+ }
+ }
+}
diff --git a/recyclerview_fastscroll/src/main/resources/base/element/string.json b/recyclerview_fastscroll/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..8f5c6d0864e2c0d165be7a742d1790ad06c7dd2d
--- /dev/null
+++ b/recyclerview_fastscroll/src/main/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "recyclerview_fastscroll_library",
+ "value": "recyclerview_fastscroll_library"
+ }
+ ]
+}
diff --git a/recyclerview_fastscroll/src/test/java/com/simplecityapps/recyclerview_fastscroll/ExampleTest.java b/recyclerview_fastscroll/src/test/java/com/simplecityapps/recyclerview_fastscroll/ExampleTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c8bee4f551b1c3ed884ffa0f5559fdb9c4be35d0
--- /dev/null
+++ b/recyclerview_fastscroll/src/test/java/com/simplecityapps/recyclerview_fastscroll/ExampleTest.java
@@ -0,0 +1,9 @@
+package com.simplecityapps.recyclerview_fastscroll;
+
+import org.junit.Test;
+
+public class ExampleTest {
+ @Test
+ public void onStart() {
+ }
+}
diff --git a/sample/build.gradle b/sample/build.gradle
deleted file mode 100644
index d68a45cf7238a7d69c32e15673a300c8e387228c..0000000000000000000000000000000000000000
--- a/sample/build.gradle
+++ /dev/null
@@ -1,36 +0,0 @@
-apply plugin: 'com.android.application'
-
-android {
- compileSdkVersion 28
- buildToolsVersion '28.0.3'
-
- defaultConfig {
- applicationId "com.simplecityapps.recyclerview_fastscroll.sample"
- minSdkVersion 21
- targetSdkVersion 28
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- lintOptions {
- abortOnError false
- }
-}
-
-dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
-
- //Appcompat
- implementation 'androidx.appcompat:appcompat:1.1.0'
-
- //RecyclerView
- implementation 'androidx.recyclerview:recyclerview:1.1.0'
-
- //RecyclerView-FastScroll
- implementation project(':recyclerview-fastscroll')
-}
\ No newline at end of file
diff --git a/sample/proguard-rules.pro b/sample/proguard-rules.pro
deleted file mode 100644
index 8d6084d8b32e430b9070751fac1500f1abd3ec52..0000000000000000000000000000000000000000
--- a/sample/proguard-rules.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /Users/tim/Library/Android/sdk/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml
deleted file mode 100644
index 854a2f6cf11572761298329717632f7babb756f5..0000000000000000000000000000000000000000
--- a/sample/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/activity/MainActivity.java b/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/activity/MainActivity.java
deleted file mode 100644
index e3fdbacace41ddfd739e54aa95f80a97a0cd1fef..0000000000000000000000000000000000000000
--- a/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/activity/MainActivity.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2016 Tim Malseed
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.simplecityapps.recyclerview_fastscroll.sample.activity;
-
-import android.annotation.SuppressLint;
-import android.os.Bundle;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentPagerAdapter;
-import androidx.viewpager.widget.ViewPager;
-
-import com.simplecityapps.recyclerview_fastscroll.sample.R;
-import com.simplecityapps.recyclerview_fastscroll.sample.fragment.MultiViewTypeFragment;
-import com.simplecityapps.recyclerview_fastscroll.sample.fragment.SimpleFragment;
-
-public class MainActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_main);
-
- ViewPager viewPager = findViewById(R.id.viewPager);
- viewPager.setAdapter(new PagerAdapter(getSupportFragmentManager()));
- }
-
- private static class PagerAdapter extends FragmentPagerAdapter {
-
- PagerAdapter(FragmentManager fm) {
- super(fm);
- }
-
- @Override
- public Fragment getItem(int position) {
- switch (position) {
- case 0:
- return new SimpleFragment();
- case 1:
- return new MultiViewTypeFragment();
- }
- throw new IllegalArgumentException(String.format("No fragment returned for position: %d", position));
- }
-
- @Override
- public int getCount() {
- return 2;
- }
-
- @SuppressLint("DefaultLocale")
- @Nullable
- @Override
- public CharSequence getPageTitle(int position) {
- return String.format("Page %d", position + 1);
- }
- }
-}
diff --git a/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/adapter/SimpleRecyclerAdapter.java b/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/adapter/SimpleRecyclerAdapter.java
deleted file mode 100644
index c257ef8558199a64947611053ec877adc51162f2..0000000000000000000000000000000000000000
--- a/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/adapter/SimpleRecyclerAdapter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.simplecityapps.recyclerview_fastscroll.sample.adapter;
-
-import android.annotation.SuppressLint;
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-import com.simplecityapps.recyclerview_fastscroll.sample.R;
-import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
-
-public class SimpleRecyclerAdapter extends RecyclerView.Adapter
- implements FastScrollRecyclerView.SectionedAdapter {
-
- @Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false));
- }
-
- @Override
- public int getItemViewType(int position) {
- return R.layout.list_item;
- }
-
- @SuppressLint("DefaultLocale")
- @Override
- public void onBindViewHolder(ViewHolder holder, int position) {
- holder.text.setText(getNameForItem(position));
- }
-
- @Override
- public int getItemCount() {
- return 200;
- }
-
- @SuppressLint("DefaultLocale")
- @NonNull
- @Override
- public String getSectionName(int position) {
- return String.format("%d", position + 1);
- }
-
- @SuppressLint("DefaultLocale")
- @NonNull
- private String getNameForItem(int position) {
- return String.format("Item %d", position + 1);
- }
-
- static class ViewHolder extends RecyclerView.ViewHolder {
- public TextView text;
-
- ViewHolder(View itemView) {
- super(itemView);
- text = itemView.findViewById(R.id.text);
- }
- }
-}
diff --git a/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/fragment/MultiViewTypeFragment.java b/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/fragment/MultiViewTypeFragment.java
deleted file mode 100644
index 2b21a987ce8c9e0b77235daa6ff7afd36645f185..0000000000000000000000000000000000000000
--- a/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/fragment/MultiViewTypeFragment.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.simplecityapps.recyclerview_fastscroll.sample.fragment;
-
-import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.DividerItemDecoration;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.simplecityapps.recyclerview_fastscroll.sample.R;
-import com.simplecityapps.recyclerview_fastscroll.sample.adapter.MultiViewTypeAdapter;
-import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
-
-public class MultiViewTypeFragment extends Fragment {
-
- @Nullable
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- View rootView = inflater.inflate(R.layout.fragment, container, false);
-
- FastScrollRecyclerView recyclerView = rootView.findViewById(R.id.recycler);
- recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
- recyclerView.setAdapter(new MultiViewTypeAdapter());
- DividerItemDecoration itemDecoration = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
- itemDecoration.setDrawable(getResources().getDrawable(R.drawable.list_divider));
- recyclerView.addItemDecoration(itemDecoration);
-
- return rootView;
- }
-}
diff --git a/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/fragment/SimpleFragment.java b/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/fragment/SimpleFragment.java
deleted file mode 100644
index 0463d864de4c5d21b38f5c3da7406e477bd2f662..0000000000000000000000000000000000000000
--- a/sample/src/main/java/com/simplecityapps/recyclerview_fastscroll/sample/fragment/SimpleFragment.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.simplecityapps.recyclerview_fastscroll.sample.fragment;
-
-import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.DividerItemDecoration;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.simplecityapps.recyclerview_fastscroll.sample.R;
-import com.simplecityapps.recyclerview_fastscroll.sample.adapter.SimpleRecyclerAdapter;
-import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
-
-public class SimpleFragment extends Fragment {
-
- @Nullable
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- View rootView = inflater.inflate(R.layout.fragment, container, false);
-
- FastScrollRecyclerView recyclerView = rootView.findViewById(R.id.recycler);
- recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
- recyclerView.setAdapter(new SimpleRecyclerAdapter());
- DividerItemDecoration itemDecoration = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
- itemDecoration.setDrawable(getResources().getDrawable(R.drawable.list_divider));
- recyclerView.addItemDecoration(itemDecoration);
-
- return rootView;
- }
-}
diff --git a/sample/src/main/res/drawable/ic_extension_24dp.xml b/sample/src/main/res/drawable/ic_extension_24dp.xml
deleted file mode 100644
index d41ac905e283b0b56024d701e8f9f46f66b309b3..0000000000000000000000000000000000000000
--- a/sample/src/main/res/drawable/ic_extension_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/sample/src/main/res/drawable/list_divider.xml b/sample/src/main/res/drawable/list_divider.xml
deleted file mode 100644
index 2e87117cd0eb226a0b25b3958f9d9383e5a6d276..0000000000000000000000000000000000000000
--- a/sample/src/main/res/drawable/list_divider.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml
deleted file mode 100644
index ee219fa4d2fdd3b85f9dc6dd1d07667ee23585ba..0000000000000000000000000000000000000000
--- a/sample/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/sample/src/main/res/layout/fragment.xml b/sample/src/main/res/layout/fragment.xml
deleted file mode 100644
index 8b7ab1f82e6a32f8070c9114dcd4a562d5bb4b4d..0000000000000000000000000000000000000000
--- a/sample/src/main/res/layout/fragment.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
-
-
diff --git a/sample/src/main/res/layout/list_item.xml b/sample/src/main/res/layout/list_item.xml
deleted file mode 100644
index 0d27024cb496ac4c409506785b5e1f8d661a0337..0000000000000000000000000000000000000000
--- a/sample/src/main/res/layout/list_item.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/sample/src/main/res/layout/list_item_header.xml b/sample/src/main/res/layout/list_item_header.xml
deleted file mode 100644
index 12887c1f229dad14b15e706cadfead051bf9e687..0000000000000000000000000000000000000000
--- a/sample/src/main/res/layout/list_item_header.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
diff --git a/sample/src/main/res/mipmap-hdpi/ic_launcher.png b/sample/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bcccec65160d92116f20ffce4fce0b5245c..0000000000000000000000000000000000000000
Binary files a/sample/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/sample/src/main/res/mipmap-mdpi/ic_launcher.png b/sample/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0cbd379f5af6dbf1a899a0293ca5eccfad0..0000000000000000000000000000000000000000
Binary files a/sample/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/sample/src/main/res/mipmap-xhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0e7b91d006d22352c9ff2f134e504e3c1d..0000000000000000000000000000000000000000
Binary files a/sample/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72cdd7480cb983fa1bcc7ce686e51ef87fe7..0000000000000000000000000000000000000000
Binary files a/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e138434630332d88b1680f33c4b24c70ab3..0000000000000000000000000000000000000000
Binary files a/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/sample/src/main/res/values-w820dp/dimens.xml b/sample/src/main/res/values-w820dp/dimens.xml
deleted file mode 100644
index 63fc816444614bd64f68a372d1f93211628ee51d..0000000000000000000000000000000000000000
--- a/sample/src/main/res/values-w820dp/dimens.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
- 64dp
-
diff --git a/sample/src/main/res/values/colors.xml b/sample/src/main/res/values/colors.xml
deleted file mode 100644
index 3ab3e9cbce07f7cdc941fc8ba424c05e83ed80f0..0000000000000000000000000000000000000000
--- a/sample/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
- #3F51B5
- #303F9F
- #FF4081
-
diff --git a/sample/src/main/res/values/dimens.xml b/sample/src/main/res/values/dimens.xml
deleted file mode 100644
index d31230ab364f6b22f4f8458a2e2567e313ae21ab..0000000000000000000000000000000000000000
--- a/sample/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- 16dp
- 16dp
-
- 48dp
- 92dp
-
diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml
deleted file mode 100644
index 32ad968c926a0cc4c9db942e3d31164e2d7faf0c..0000000000000000000000000000000000000000
--- a/sample/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- RecyclerView-FastScroll
-
diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml
deleted file mode 100644
index 5885930df6d10edf3d6df40d6556297d11f953da..0000000000000000000000000000000000000000
--- a/sample/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
diff --git a/screenshot.png b/screenshot.png
deleted file mode 100644
index eab8ce9f2001dd126aade9a64f304ef0df264596..0000000000000000000000000000000000000000
Binary files a/screenshot.png and /dev/null differ
diff --git a/settings.gradle b/settings.gradle
index 9c741ab2ff48dddaf5846f0b2532e15e5eedf48c..a47907071618f77ba2777442cd78b4b0fc2663f8 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':recyclerview-fastscroll', ':sample'
+include ':entry', ':recyclerview_fastscroll'