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 -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.simplecityapps/recyclerview-fastscroll/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.simplecityapps/recyclerview-fastscroll) [![API](https://img.shields.io/badge/API-14%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=14) -[![License](http://img.shields.io/badge/license-APACHE2-blue.svg)](NOTICE) -[![Build Status](https://travis-ci.org/timusus/RecyclerView-FastScroll.svg?branch=master)](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/) - -![Screenshot](https://github.com/timusus/RecyclerView-FastScroll/blob/master/screenshot.png) - - -### Gradle -`compile 'com.simplecityapps:recyclerview-fastscroll:2.0.1'` +#### 项目介绍 +- 项目名称:RecyclerView-FastScroll +- 所属系列:openharmony的第三方组件适配移植 +- 功能:一个简单的快速滚动列表控件 +- 项目移植状态:主功能完成 +- 调用差异:无 +- 开发版本:sdk6,DevEco Studio 2.2 Beta1 +- 基线版本:Release 2.0.1 + +#### 效果演示 +![效果演示](img/1.gif "效果演示.gif") +![效果演示](img/2.gif "效果演示.gif") + +#### 安装教程 + +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'