From 61f5951db558480cdb1ead838eca7e4f4df597a0 Mon Sep 17 00:00:00 2001 From: JiangJun <2680104782@qq.com> Date: Tue, 17 Aug 2021 14:55:45 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E3=80=90=E4=BF=AE=E6=94=B9=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E3=80=91=EF=BC=9Aadd=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 + README.OPENSOURCE | 10 + README.md | 1 + entry/.gitignore | 1 + entry/build.gradle | 30 ++ entry/src/main/config.json | 77 +++ .../fls/swipestacksample/MainAbility.java | 19 + .../fls/swipestacksample/MyApplication.java | 30 ++ .../slice/MainAbilitySlice.java | 248 ++++++++++ .../fls/swipestacksample/snackbar/Snack.java | 170 +++++++ .../swipestacksample/snackbar/SnackBar.java | 458 +++++++++++++++++ .../snackbar/SnackContainer.java | 371 ++++++++++++++ .../util/BaseDirectionalLayout.java | 153 ++++++ .../swipestacksample/util/FastClickUtil.java | 45 ++ .../util/FinalStaticBean.java | 276 +++++++++++ .../util/TinderDirectionalCard.java | 104 ++++ .../main/resources/base/element/color.json | 72 +++ .../main/resources/base/element/string.json | 48 ++ .../base/graphic/background_ability_main.xml | 6 + .../base/graphic/background_button.xml | 8 + .../resources/base/graphic/tinder_card_bg.xml | 19 + .../resources/base/layout/ability_main.xml | 93 ++++ .../main/resources/base/layout/card_item.xml | 17 + ...form_image_with_information_widget_2_2.xml | 44 ++ .../main/resources/base/layout/popu_item.xml | 24 + .../main/resources/base/layout/sb__snack.xml | 42 ++ .../base/layout/sb__snack_container.xml | 20 + .../base/layout/tinder_card_view.xml | 71 +++ ...ith_information_widget_default_image_2.png | Bin 0 -> 6244 bytes entry/src/main/resources/base/media/icon.png | Bin 0 -> 6790 bytes entry/src/main/resources/base/media/more.png | Bin 0 -> 503 bytes entry/src/main/resources/base/media/small.png | Bin 0 -> 487 bytes .../src/main/resources/en/element/string.json | 16 + .../src/main/resources/zh/element/string.json | 16 + .../link/fls/swipestack/ExampleOhosTest.java | 15 + .../java/link/fls/swipestack/ExampleTest.java | 9 + library/src/main/config.json | 23 + .../link/fls/swipestack/BaseSwipeCard.java | 72 +++ .../swipestack/CardTouchEventListener.java | 190 +++++++ .../java/link/fls/swipestack/SwipeDecor.java | 66 +++ .../fls/swipestack/SwipeDirectionalView.java | 468 ++++++++++++++++++ .../link/fls/swipestack/impl/ICardState.java | 54 ++ .../swipestack/impl/ItemRemovedListener.java | 30 ++ .../main/resources/base/element/string.json | 8 + .../java/link/fls/swipestack/ExampleTest.java | 9 + 45 files changed, 3438 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 README.OPENSOURCE create mode 100644 entry/.gitignore create mode 100644 entry/build.gradle create mode 100644 entry/src/main/config.json create mode 100644 entry/src/main/java/link/fls/swipestacksample/MainAbility.java create mode 100644 entry/src/main/java/link/fls/swipestacksample/MyApplication.java create mode 100644 entry/src/main/java/link/fls/swipestacksample/slice/MainAbilitySlice.java create mode 100644 entry/src/main/java/link/fls/swipestacksample/snackbar/Snack.java create mode 100644 entry/src/main/java/link/fls/swipestacksample/snackbar/SnackBar.java create mode 100644 entry/src/main/java/link/fls/swipestacksample/snackbar/SnackContainer.java create mode 100644 entry/src/main/java/link/fls/swipestacksample/util/BaseDirectionalLayout.java create mode 100644 entry/src/main/java/link/fls/swipestacksample/util/FastClickUtil.java create mode 100644 entry/src/main/java/link/fls/swipestacksample/util/FinalStaticBean.java create mode 100644 entry/src/main/java/link/fls/swipestacksample/util/TinderDirectionalCard.java create mode 100644 entry/src/main/resources/base/element/color.json create mode 100644 entry/src/main/resources/base/element/string.json create mode 100644 entry/src/main/resources/base/graphic/background_ability_main.xml create mode 100644 entry/src/main/resources/base/graphic/background_button.xml create mode 100644 entry/src/main/resources/base/graphic/tinder_card_bg.xml create mode 100644 entry/src/main/resources/base/layout/ability_main.xml create mode 100644 entry/src/main/resources/base/layout/card_item.xml create mode 100644 entry/src/main/resources/base/layout/form_image_with_information_widget_2_2.xml create mode 100644 entry/src/main/resources/base/layout/popu_item.xml create mode 100644 entry/src/main/resources/base/layout/sb__snack.xml create mode 100644 entry/src/main/resources/base/layout/sb__snack_container.xml create mode 100644 entry/src/main/resources/base/layout/tinder_card_view.xml create mode 100644 entry/src/main/resources/base/media/form_image_with_information_widget_default_image_2.png create mode 100644 entry/src/main/resources/base/media/icon.png create mode 100644 entry/src/main/resources/base/media/more.png create mode 100644 entry/src/main/resources/base/media/small.png create mode 100644 entry/src/main/resources/en/element/string.json create mode 100644 entry/src/main/resources/zh/element/string.json create mode 100644 entry/src/ohosTest/java/link/fls/swipestack/ExampleOhosTest.java create mode 100644 entry/src/test/java/link/fls/swipestack/ExampleTest.java create mode 100644 library/src/main/config.json create mode 100644 library/src/main/java/link/fls/swipestack/BaseSwipeCard.java create mode 100644 library/src/main/java/link/fls/swipestack/CardTouchEventListener.java create mode 100644 library/src/main/java/link/fls/swipestack/SwipeDecor.java create mode 100644 library/src/main/java/link/fls/swipestack/SwipeDirectionalView.java create mode 100644 library/src/main/java/link/fls/swipestack/impl/ICardState.java create mode 100644 library/src/main/java/link/fls/swipestack/impl/ItemRemovedListener.java create mode 100644 library/src/main/resources/base/element/string.json create mode 100644 library/src/test/java/link/fls/swipestack/ExampleTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9dd968a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +## 0.0.1-SNAPSHOT +- ohos 第一个版本,完整实现了原库的全部 api + + + diff --git a/README.OPENSOURCE b/README.OPENSOURCE new file mode 100644 index 0000000..fdf4f95 --- /dev/null +++ b/README.OPENSOURCE @@ -0,0 +1,10 @@ +[ + { + "Name": "SwipeStack", + "License": "Apache License", + "License File": "LICENSE", + "Version Number": "0.3.0", + "Upstream URL": "https://github.com/flschweiger/SwipeStack", + "Description": "A simple, customizable and easy to use swipeable view stack for Android." + } +] \ No newline at end of file diff --git a/README.md b/README.md index 13b79f7..72b4ed2 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ #### 效果演示 +![输入图片说明](https://images.gitee.com/uploads/images/2021/0817/144309_498e5273_5356950.gif "3.gif") #### 安装教程 diff --git a/entry/.gitignore b/entry/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/entry/.gitignore @@ -0,0 +1 @@ +/build diff --git a/entry/build.gradle b/entry/build.gradle new file mode 100644 index 0000000..6a4d284 --- /dev/null +++ b/entry/build.gradle @@ -0,0 +1,30 @@ +apply plugin: 'com.huawei.ohos.hap' +apply plugin: 'com.huawei.ohos.decctest' +//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 + } + showInServiceCenter true + buildTypes { + release { + proguardOpt { + proguardEnabled false + rulesFiles 'proguard-rules.pro' + } + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar', '*.har']) + implementation project(path: ':library') + testImplementation 'junit:junit:4.13' + implementation project(path: ':library') + ohosTestImplementation 'com.huawei.ohos.testkit:runner:1.0.0.200' +} +decc { + supportType = ['html','xml'] +} diff --git a/entry/src/main/config.json b/entry/src/main/config.json new file mode 100644 index 0000000..085adc2 --- /dev/null +++ b/entry/src/main/config.json @@ -0,0 +1,77 @@ +{ + "app": { + "bundleName": "link.fls.swipestacksample", + "vendor": "fls", + "version": { + "code": 1000000, + "name": "1.0.0" + } + }, + "deviceConfig": {}, + "module": { + "package": "link.fls.swipestacksample", + "name": ".MyApplication", + "mainAbility": "link.fls.swipestacksample.MainAbility", + "deviceType": [ + "phone" + ], + "metaData": { + "customizeData": [ + { + "name": "hwc-theme", + "value": "androidhwext:style/Theme.Emui.NoTitleBar" + } + ] + }, + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry", + "installationFree": false + }, + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "orientation": "unspecified", + "name": "link.fls.swipestacksample.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "formsEnabled": true, + "label": "$string:entry_MainAbility", + "type": "page", + "forms": [ + { + "landscapeLayouts": [ + "$layout:form_image_with_information_widget_2_2" + ], + "isDefault": true, + "scheduledUpdateTime": "10:30", + "defaultDimension": "2*2", + "name": "widget", + "description": "This is a service widget", + "colorMode": "auto", + "type": "Java", + "supportDimensions": [ + "2*2" + ], + "portraitLayouts": [ + "$layout:form_image_with_information_widget_2_2" + ], + "updateEnabled": true, + "updateDuration": 1 + } + ], + "launchType": "standard" + } + ] + } +} \ No newline at end of file diff --git a/entry/src/main/java/link/fls/swipestacksample/MainAbility.java b/entry/src/main/java/link/fls/swipestacksample/MainAbility.java new file mode 100644 index 0000000..0da9b8b --- /dev/null +++ b/entry/src/main/java/link/fls/swipestacksample/MainAbility.java @@ -0,0 +1,19 @@ +package link.fls.swipestacksample; + +import link.fls.swipestacksample.slice.MainAbilitySlice; +import ohos.aafwk.ability.Ability; +import ohos.aafwk.content.Intent; + +/** + * MainAbility + * + * @since 2021-08-10 + */ +public class MainAbility extends Ability { + + @Override + public void onStart(Intent intent) { + super.onStart(intent); + super.setMainRoute(MainAbilitySlice.class.getName()); + } +} diff --git a/entry/src/main/java/link/fls/swipestacksample/MyApplication.java b/entry/src/main/java/link/fls/swipestacksample/MyApplication.java new file mode 100644 index 0000000..200d0d3 --- /dev/null +++ b/entry/src/main/java/link/fls/swipestacksample/MyApplication.java @@ -0,0 +1,30 @@ +/* + * 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 link.fls.swipestacksample; + +import ohos.aafwk.ability.AbilityPackage; + +/** + * MyApplication + * + * @since 2021-08-10 + */ +public class MyApplication extends AbilityPackage { + @Override + public void onInitialize() { + super.onInitialize(); + } +} diff --git a/entry/src/main/java/link/fls/swipestacksample/slice/MainAbilitySlice.java b/entry/src/main/java/link/fls/swipestacksample/slice/MainAbilitySlice.java new file mode 100644 index 0000000..1e80947 --- /dev/null +++ b/entry/src/main/java/link/fls/swipestacksample/slice/MainAbilitySlice.java @@ -0,0 +1,248 @@ +package link.fls.swipestacksample.slice; + +import link.fls.swipestack.SwipeDirectionalView; +import link.fls.swipestacksample.ResourceTable; +import link.fls.swipestacksample.snackbar.SnackBar; +import link.fls.swipestacksample.util.FastClickUtil; +import link.fls.swipestacksample.util.TinderDirectionalCard; +import ohos.aafwk.ability.AbilitySlice; +import ohos.aafwk.content.Intent; +import ohos.aafwk.content.Operation; +import ohos.agp.components.*; +import ohos.agp.text.Font; +import ohos.agp.utils.Color; +import ohos.agp.utils.LayoutAlignment; +import ohos.agp.window.dialog.PopupDialog; +import ohos.agp.window.dialog.ToastDialog; +import ohos.agp.window.service.WindowManager; +import ohos.utils.IntentConstants; +import ohos.utils.net.Uri; + +import java.security.SecureRandom; + +/** + * MainAbilitySlice + * + * @since 2021-08-10 + */ +public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener, SnackBar.OnVisibilityChangeListener, SwipeDirectionalView.SwipeStackListener { + private Button mButtonLeft, mButtonRight; + private Image mFab; + private Image loadMore; + private Text tvTitle; + private int mCount = 1; + private SwipeDirectionalView mSwipeStack; + private Component button; + private SnackBar stackReset; + private SecureRandom random = new SecureRandom(); + private boolean isViewSwipedToLeft = true; + private boolean isViewSwipedToRight = true; + private int addCardNum; + private int itemAllNum = 1; + + @Override + public void onStart(Intent intent) { + super.onStart(intent); + super.setUIContent(ResourceTable.Layout_ability_main); + WindowManager.getInstance().getTopWindow().get().setStatusBarColor(Color.getIntColor("#2E409F")); + mSwipeStack = (SwipeDirectionalView) findComponentById(ResourceTable.Id_swipeStack); + mButtonLeft = (Button) findComponentById(ResourceTable.Id_buttonSwipeLeft); + mButtonRight = (Button) findComponentById(ResourceTable.Id_buttonSwipeRight); + mFab = (Image) findComponentById(ResourceTable.Id_fabAdd); + button = findComponentById(ResourceTable.Id_layout_button); + mButtonLeft.setClickedListener(this); + mButtonRight.setClickedListener(this); + mFab.setClickedListener(this); + mSwipeStack.setSwipeStackListener(this); + addStack(); + addCardNum = 0; + loadMore = (Image) findComponentById(ResourceTable.Id_iv_load_more); + tvTitle = (Text) findComponentById(ResourceTable.Id_tv_title); + tvTitle.setFont(Font.DEFAULT_BOLD); + + loadMore.setClickedListener(new Component.ClickedListener() { + @Override + public void onClick(Component component) { + PopupDialog dialog = new PopupDialog(MainAbilitySlice.this, null); + Component parse = LayoutScatter.getInstance(MainAbilitySlice.this).parse(ResourceTable.Layout_popu_item, null, false); + dialog.setCustomComponent(parse); + dialog.setAlignment(LayoutAlignment.RIGHT | LayoutAlignment.TOP); + dialog.setAutoClosable(true); + dialog.show(); + Component settings = parse.findComponentById(ResourceTable.Id_reset); + settings.setClickedListener(new Component.ClickedListener() { + @Override + public void onClick(Component component) { + short time = 3000; + mSwipeStack.clearComponentList(); + mCount = 1; + mSwipeStack.undoLastSwipe(); + dialog.remove(); + stackReset = new SnackBar.Builder(MainAbilitySlice.this, button) + .withVisibilityChangeListener(MainAbilitySlice.this) + .withMessage("Stack reset") + .withBackgroundColorId(Color.getIntColor("#3C3F41")) + .withDuration(time) + .withTypeFace(Font.DEFAULT) + .show(); + addStack(); + itemAllNum = 1; + if (addCardNum > 0) { + for (int i = 0; i < addCardNum; i++) { + mSwipeStack.addView(makeCard("Fab Test"), random.nextInt(20) - 10); + } + } + } + }); + parse.findComponentById(ResourceTable.Id_view).setClickedListener(new Component.ClickedListener() { + @Override + public void onClick(Component component) { + initWeb(getString(ResourceTable.String_main_url_value)); + } + }); + } + }); + } + + private void addStack() { + for (int i = 0; i < 5; i++) { + mSwipeStack.addView(makeCard("Test " + mCount++), random.nextInt(10) - 5); + } + } + + /** + * TinderDirectionalCard + * + * @param cardName + * @return tinderDirectionalCard + */ + private TinderDirectionalCard makeCard(String cardName) { + TinderDirectionalCard tinderDirectionalCard = new TinderDirectionalCard(getContext()); + tinderDirectionalCard.setNameText(cardName); + return tinderDirectionalCard; + } + + @Override + public void onActive() { + super.onActive(); + } + + @Override + public void onForeground(Intent intent) { + super.onForeground(intent); + } + + @Override + public void onClick(Component component) { + switch (component.getId()) { + case ResourceTable.Id_buttonSwipeLeft: + if (FastClickUtil.isFastClick()) { + return; + } + isViewSwipedToLeft = true; + mSwipeStack.doSwipe(false); + break; + case ResourceTable.Id_buttonSwipeRight: + if (FastClickUtil.isFastClick()) { + return; + } + isViewSwipedToRight = true; + mSwipeStack.doSwipe(true); + break; + case ResourceTable.Id_fabAdd: + mSwipeStack.addView(makeCard("Fab Test"), random.nextInt(20) - 10); + addCardNum++; + break; + default: + break; + } + } + + @Override + public void onViewSwipedToLeft(int position) { + itemAllNum++; + if (itemAllNum <= 6) { + toast("Test " + getString(ResourceTable.String_view_swiped_left, position)); + } else { + toast("Fab Test swiped to left "); + } + isViewSwipedToLeft = false; + } + + @Override + public void onViewSwipedToRight(int position) { + itemAllNum++; + if (itemAllNum <= 6) { + toast("Test " + getString(ResourceTable.String_view_swiped_right, position)); + } else { + toast("Fab Test swiped to right"); + } + isViewSwipedToRight = false; + } + + /** + * getIntCount + * + * @return itemAllNum + */ + public int getIntCount() { + return itemAllNum; + } + + @Override + public void onStackEmpty() { + toast("Card stack empty!"); + } + + /** + * toast + * + * @param msg + */ + private void toast(String msg) { + new ToastDialog(this) + .setText(msg) + .show(); + } + + /** + * initWeb + * + * @param urlString urlString + */ + private void initWeb(String urlString) { + Intent intents = new Intent(); + Operation operation = new Intent.OperationBuilder() + .withUri(Uri.parse(urlString)) + .withAction(IntentConstants.ACTION_SEARCH) + .build(); + intents.setOperation(operation); + startAbility(intents); + } + + + /** + * onShow + * + * @param stackSize the number of messages left to show + */ + @Override + public void onShow(int stackSize) { + mFab.setMarginBottom(180); + + mButtonLeft.setVisibility(Component.HIDE); + mButtonRight.setVisibility(Component.HIDE); + } + + /** + * onHide + * + * @param stackSize the number of messages left to show + */ + @Override + public void onHide(int stackSize) { + mFab.setMarginBottom(40); + mButtonLeft.setVisibility(Component.VISIBLE); + mButtonRight.setVisibility(Component.VISIBLE); + } +} diff --git a/entry/src/main/java/link/fls/swipestacksample/snackbar/Snack.java b/entry/src/main/java/link/fls/swipestacksample/snackbar/Snack.java new file mode 100644 index 0000000..e18e40c --- /dev/null +++ b/entry/src/main/java/link/fls/swipestacksample/snackbar/Snack.java @@ -0,0 +1,170 @@ +/* + * Copyright 2014 MrEngineer13 + * Copyright 2021 Institute of Software Chinese Academy of Sciences, ISRC + + * 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 link.fls.swipestacksample.snackbar; + +import ohos.agp.text.Font; +import ohos.utils.Parcel; +import ohos.utils.Sequenceable; + +/** + * Snack + * + * @since 2021-08-10 + */ +public class Snack implements Sequenceable { + /** + * mMessage + */ + public final String mMessage; + /** + * mActionMessage + */ + public final String mActionMessage; + /** + * mActionIcon + */ + private final int mActionIcon; + /** + * mToken + */ + public final Sequenceable mToken; + /** + * mDuration + */ + public final short mDuration; + /** + * mBtnTextColor + */ + public final int mBtnTextColor; + /** + * mBackgroundColor + */ + public final int mBackgroundColor; + /** + * mHeight + */ + public final int mHeight; + /** + * mTypeface + */ + public Font mTypeface; + + /** + * Snack + * + * @param message + * @param actionMessage + * @param actionIcon + * @param token + * @param duration + * @param textColor + * @param backgroundColor + * @param height + * @param typeFace + */ + public Snack(String message, String actionMessage, int actionIcon, + Sequenceable token, short duration, int textColor, int backgroundColor, int height, Font typeFace) { + mMessage = message; + mActionMessage = actionMessage; + mActionIcon = actionIcon; + mToken = token; + mDuration = duration; + mBtnTextColor = textColor; + mBackgroundColor = backgroundColor; + mHeight = height; + mTypeface = typeFace; + } + + /** + * Snack + * + * @param p + */ + public Snack(Parcel p) { + mMessage = p.readString(); + mActionMessage = p.readString(); + mActionIcon = p.readInt(); + mToken = p.readSequenceableList(Sequenceable.class).get(0); + mDuration = (short) p.readInt(); + mBtnTextColor = p.readInt(); + mBackgroundColor = p.readInt(); + mHeight = p.readInt(); + mTypeface = (Font) p.readValue(); + } + + /** + * writeToParcel + * + * @param out + * @param flags + */ + public void writeToParcel(Parcel out, int flags) { + out.writeString(mMessage); + out.writeString(mActionMessage); + out.writeInt(mActionIcon); + out.writeSequenceable(mToken); + out.writeInt((int) mDuration); + out.writeInt(mBtnTextColor); + out.writeInt(mBackgroundColor); + out.writeInt(mHeight); + out.writeValue(mTypeface); + } + + /** + * describeContents + * + * @return 0 + */ + public int describeContents() { + return 0; + } + + /** + * creates snack array + */ + public static final Producer CREATOR = new Producer() { + public Snack createFromParcel(Parcel in) { + return new Snack(in); + } + + public Snack[] newArray(int size) { + return new Snack[size]; + } + }; + + /** + * marshalling + * + * @param parcel + * @return false + */ + @Override + public boolean marshalling(Parcel parcel) { + return false; + } + + /** + * unmarshalling + * + * @param parcel + * @return false + */ + @Override + public boolean unmarshalling(Parcel parcel) { + return false; + } +} diff --git a/entry/src/main/java/link/fls/swipestacksample/snackbar/SnackBar.java b/entry/src/main/java/link/fls/swipestacksample/snackbar/SnackBar.java new file mode 100644 index 0000000..1cc1eac --- /dev/null +++ b/entry/src/main/java/link/fls/swipestacksample/snackbar/SnackBar.java @@ -0,0 +1,458 @@ +/* + * Copyright 2014 MrEngineer13 + * Copyright 2021 Institute of Software Chinese Academy of Sciences, ISRC + + * 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 link.fls.swipestacksample.snackbar; + +import link.fls.swipestacksample.ResourceTable; +import ohos.aafwk.ability.Ability; +import ohos.aafwk.content.Intent; +import ohos.agp.components.Component; +import ohos.agp.components.ComponentContainer; +import ohos.agp.components.LayoutScatter; +import ohos.agp.components.Text; +import ohos.agp.text.Font; +import ohos.agp.utils.Color; +import ohos.app.Context; +import ohos.global.resource.NotExistException; +import ohos.global.resource.WrongTypeException; +import ohos.utils.Sequenceable; + +import java.io.IOException; + +/** + * SnackBar + * + * @since 2021-08-10 + */ +public class SnackBar { + /** + * MED_SNACK + */ + public static final short MED_SNACK = 3500; + private SnackContainer mSnackContainer; + private Component mParentView; + private OnMessageClickListener mClickListener; + private OnVisibilityChangeListener mVisibilityChangeListener; + + /** + * OnMessageClickListener + */ + public interface OnMessageClickListener { + void onMessageClick(Sequenceable token); + } + + /** + * OnVisibilityChangeListener + */ + public interface OnVisibilityChangeListener { + + /** + * Gets called when a message is shown + * + * @param stackSize the number of messages left to show + */ + void onShow(int stackSize); + + /** + * Gets called when a message is hidden + * + * @param stackSize the number of messages left to show + */ + void onHide(int stackSize); + } + + /** + * SnackBar + * + * @param ability + * @param component + */ + public SnackBar(Ability ability, Component component) { + Context context = ability.getContext(); + LayoutScatter scatter = LayoutScatter.getInstance(context); + ComponentContainer container = (ComponentContainer) component.getComponentParent(); + scatter.parse(ResourceTable.Layout_sb__snack_container, container, true); + Component v = scatter.parse(ResourceTable.Layout_sb__snack, container, false); + init(container, v); + } + + /** + * SnackBar + * + * @param context + * @param v + */ + public SnackBar(Context context, Component v) { + LayoutScatter scatter = LayoutScatter.getInstance(context); + Component snackLayout = scatter.parse(ResourceTable.Layout_sb__snack, (ComponentContainer) v, false); + init((ComponentContainer) v, snackLayout); + } + + /** + * init + * + * @param container + * @param v + */ + private void init(ComponentContainer container, Component v) { + mSnackContainer = (SnackContainer) container.findComponentById(ResourceTable.Id_snackContainer); + if (mSnackContainer == null) { + mSnackContainer = new SnackContainer(container); + } + mParentView = v; + Text snackBtn = (Text) v.findComponentById(ResourceTable.Id_snackButton); + snackBtn.setClickedListener(mButtonListener); + } + + /** + * Builder + */ + public static class Builder { + private SnackBar mSnackBar; + private Context mContext; + private String mMessage; + private String mActionMessage; + private int mActionIcon = 0; + private Sequenceable mToken; + private short mDuration = MED_SNACK; + private int mTextColor; + private int mBackgroundColor; + private int mHeight; + private boolean mClear; + private boolean mAnimateClear; + private Font mTypeFace; + + /** + * Builder + * + * @param ability + * @param component + */ + public Builder(Ability ability, Component component) { + mContext = ability.getApplicationContext(); + mSnackBar = new SnackBar(ability, component); + } + + /** + * Constructs a new SnackBar + * + * @param context the context used to obtain resources + * @param v the view to inflate the SnackBar into + */ + public Builder(Context context, Component v) { + mContext = context; + mSnackBar = new SnackBar(context, v); + } + + /** + * Sets the message to display on the SnackBar + * + * @param message the literal string to display + * @return this builder + */ + public Builder withMessage(String message) { + mMessage = message; + return this; + } + + /** + * Sets the message to display on the SnackBar + * + * @param messageId the resource id of the string to display + * @return this builder + */ + public Builder withMessageId(int messageId) throws NotExistException, WrongTypeException, IOException { + mMessage = mContext.getResourceManager().getSolidXml(messageId).getRoot().getStringValue(); + return this; + } + + /** + * Sets the message to display as the action message + * + * @param actionMessage the literal string to display + * @return this builder + */ + public Builder withActionMessage(String actionMessage) { + mActionMessage = actionMessage; + return this; + } + + /** + * Sets the message to display as the action message + * + * @param actionMessageResId the resource id of the string to display + * @return this builder + */ + public Builder withActionMessageId(int actionMessageResId) throws NotExistException, WrongTypeException, IOException { + if (actionMessageResId > 0) { + mActionMessage = mContext.getResourceManager().getSolidXml(actionMessageResId).getRoot().getStringValue(); + } + return this; + } + + /** + * Sets the action icon + * + * @param id the resource id of the icon to display + * @return this builder + */ + public Builder withActionIconId(int id) { + mActionIcon = id; + return this; + } + + /** + * withStyle + * + * @param color + * @return + */ + public Builder withStyle(int color) { + mTextColor = color; + return this; + } + + /** + * The token used to restore the SnackBar state + * + * @param token the parcelable containing the saved SnackBar + * @return this builder + */ + public Builder withToken(Sequenceable token) { + mToken = token; + return this; + } + + /** + * Sets the duration to show the message + * + * @param duration the number of milliseconds to show the message + * @return this builder + */ + public Builder withDuration(Short duration) { + mDuration = duration; + return this; + } + + /** + * withTextColorId + * + * @param colorId + * @return this + * @throws NotExistException + * @throws WrongTypeException + * @throws IOException + */ + public Builder withTextColorId(int colorId) throws NotExistException, WrongTypeException, IOException { + mTextColor = colorId; + return this; + } + + /** + * withBackgroundColorId + * + * @param colorId + * @return this + */ + public Builder withBackgroundColorId(int colorId) { + mBackgroundColor = colorId; + return this; + } + + /** + * Sets the height for SnackBar + * + * @param height the height of SnackBar + * @return this builder + */ + public Builder withSnackBarHeight(int height) { + mHeight = height; + return this; + } + + /** + * Sets the OnClickListener for the action button + * + * @param onClickListener the listener to inform of click events + * @return this builder + */ + public Builder withOnClickListener(OnMessageClickListener onClickListener) { + mSnackBar.setOnClickListener(onClickListener); + return this; + } + + /** + * Sets the visibilityChangeListener for the SnackBar + * + * @param visibilityChangeListener the listener to inform of visibility changes + * @return this builder + */ + public Builder withVisibilityChangeListener(OnVisibilityChangeListener visibilityChangeListener) { + mSnackBar.setOnVisibilityChangeListener(visibilityChangeListener); + return this; + } + + /** + * Clears all of the queued SnackBars, animates the message being hidden + * + * @return this builder + */ + public Builder withClearQueued() { + return withClearQueued(true); + } + + /** + * Clears all of the queued SnackBars + * + * @param animate whether or not to animate the messages being hidden + * @return this builder + */ + public Builder withClearQueued(boolean animate) { + mAnimateClear = animate; + mClear = true; + return this; + } + + /** + * Sets the Typeface for the SnackBar + * + * @param typeFace the typeface to apply to the SnackBar + * @return this builder + */ + public Builder withTypeFace(Font typeFace) { + mTypeFace = typeFace; + return this; + } + + /** + * Shows the first message in the SnackBar + * + * @return the SnackBar + */ + public SnackBar show() { + Snack message = new Snack(mMessage, + (mActionMessage != null ? mActionMessage.toUpperCase() : null), + mActionIcon, + mToken, + mDuration, + mTextColor != 100 ? mTextColor : Color.WHITE.getValue(), + mBackgroundColor != 100 ? mBackgroundColor : Color.WHITE.getValue(), + mHeight != 0 ? mHeight : 0, + mTypeFace); + + if (mClear) { + mSnackBar.clear(mAnimateClear); + } + + mSnackBar.showMessage(message); + + return mSnackBar; + } + } + + /** + * showMessage + * + * @param message + */ + private void showMessage(Snack message) { + mSnackContainer.showSnack(message, mParentView, mVisibilityChangeListener); + } + + /** + * Getter for the SnackBars parent view + * + * @return the parent view + */ + public Component getContainerView() { + return mParentView; + } + + /** + * mButtonListener + */ + private final Component.ClickedListener mButtonListener = new Component.ClickedListener() { + @Override + public void onClick(Component component) { + if (mClickListener != null && mSnackContainer.isShowing()) { + mClickListener.onMessageClick(mSnackContainer.peek().mToken); + } + mSnackContainer.hide(); + } + }; + + /** + * setOnClickListener + * @param listener + * @return this + */ + private SnackBar setOnClickListener(OnMessageClickListener listener) { + mClickListener = listener; + return this; + } + + /** + * setOnVisibilityChangeListener + * @param listener + * @return this + */ + private SnackBar setOnVisibilityChangeListener(OnVisibilityChangeListener listener) { + mVisibilityChangeListener = listener; + return this; + } + + /** + * Clears all of the queued messages + * + * @param animate whether or not to animate the messages being hidden + */ + public void clear(boolean animate) { + mSnackContainer.clearSnacks(animate); + } + + /** + * Clears all of the queued messages + */ + public void clear() { + clear(true); + } + + /** + * Hides all snacks + */ + public void hide() { + mSnackContainer.hide(); + clear(); + } + + /** + * All snacks will be restored using the view from this Snackbar + * + * @param state + */ + public void onRestoreInstanceState(Intent state) { + mSnackContainer.restoreState(state, mParentView); + } + + /** + * onSaveInstanceState + * @return onSaveInstanceState + */ + public Intent onSaveInstanceState() { + return mSnackContainer.saveState(); + } +} diff --git a/entry/src/main/java/link/fls/swipestacksample/snackbar/SnackContainer.java b/entry/src/main/java/link/fls/swipestacksample/snackbar/SnackContainer.java new file mode 100644 index 0000000..25bcefd --- /dev/null +++ b/entry/src/main/java/link/fls/swipestacksample/snackbar/SnackContainer.java @@ -0,0 +1,371 @@ +/* + * Copyright 2014 MrEngineer13 + * Copyright 2021 Institute of Software Chinese Academy of Sciences, ISRC + + * 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 link.fls.swipestacksample.snackbar; + +import link.fls.swipestacksample.ResourceTable; +import ohos.aafwk.content.Intent; +import ohos.agp.animation.Animator; +import ohos.agp.animation.AnimatorGroup; +import ohos.agp.animation.AnimatorProperty; +import ohos.agp.colors.RgbColor; +import ohos.agp.components.*; +import ohos.agp.components.element.ShapeElement; +import ohos.agp.utils.Color; +import ohos.app.Context; +import ohos.eventhandler.EventHandler; +import ohos.eventhandler.EventRunner; +import ohos.utils.Sequenceable; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * SnackContainer + * + * @since 2021-08-10 + */ +public class SnackContainer extends StackLayout { + private static final int ANIMATION_DURATION = 300; + private static final String SAVED_MSGS = "SAVED_MSGS"; + private Queue mSnacks = new LinkedList(); + private AnimatorGroup mOutAnimationSet; + private AnimatorProperty mSlideInAnimation; + private AnimatorProperty mSlideOutAnimation; + private EventHandler handler; + + /** + * SnackContainer + * + * @param context + */ + public SnackContainer(Context context) { + super(context); + init(); + } + + /** + * SnackContainer + * + * @param context + * @param attrs + */ + public SnackContainer(Context context, AttrSet attrs) { + super(context, attrs); + init(); + } + + /** + * SnackContainer + * + * @param container + */ + public SnackContainer(ComponentContainer container) { + super(container.getContext()); + container.addComponent(this, new ComponentContainer.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT)); + setVisibility(Component.HIDE); + setId(ResourceTable.Id_snackContainer); + init(); + } + + /** + * init + */ + private void init() { + mSlideInAnimation = new AnimatorProperty(); + mSlideInAnimation.alpha(0.9f).moveFromX(0.0f).moveToX(0.0f).moveFromY(1.0f).moveToY(0.0f); + mOutAnimationSet = new AnimatorGroup(); + mSlideOutAnimation = new AnimatorProperty(); + mSlideOutAnimation.alpha(0.1f).moveFromX(0.0f).moveToX(0.0f).moveFromY(0.0f).moveToY(1.0f); + mSlideOutAnimation.setDuration(ANIMATION_DURATION); + mSlideOutAnimation.setStateChangedListener(new Animator.StateChangedListener() { + @Override + public void onStart(Animator animator) { + mOutAnimationSet.end(); + } + + @Override + public void onStop(Animator animator) { + + } + + @Override + public void onCancel(Animator animator) { + + } + + @Override + public void onEnd(Animator animator) { + removeAllComponents(); + + if (!mSnacks.isEmpty()) { + sendOnHide(mSnacks.poll()); + } + + if (!isEmpty()) { + showSnack(mSnacks.peek()); + } else { + setVisibility(Component.HIDE); + } + } + + @Override + public void onPause(Animator animator) { + + } + + @Override + public void onResume(Animator animator) { + + } + }); + } + + /** + * isEmpty + * + * @return isEmpty + */ + public boolean isEmpty() { + return mSnacks.isEmpty(); + } + + /** + * peek + * + * @return peek + */ + public Snack peek() { + return mSnacks.peek().snack; + } + + /** + * pollSnack + * + * @return pollSnack + */ + public Snack pollSnack() { + return mSnacks.poll().snack; + } + + /** + * clearSnacks + * + * @param animate + */ + public void clearSnacks(boolean animate) { + mSnacks.clear(); + handler = new EventHandler(EventRunner.create()); + handler.removeTask(mHideRunnable); + if (animate) mHideRunnable.run(); + } + + /** + * isShowing + * + * @returnisShowing + */ + public boolean isShowing() { + return !mSnacks.isEmpty(); + } + + /** + * hide + */ + public void hide() { + handler = new EventHandler(EventRunner.create()); + handler.removeTask(mHideRunnable); + mHideRunnable.run(); + } + + /** + * showSnack + * + * @param snack + * @param snackView + * @param listener + */ + public void showSnack(Snack snack, Component snackView, SnackBar.OnVisibilityChangeListener listener) { + showSnack(snack, snackView, listener, false); + } + + /** + * showSnack + * + * @param snack + * @param snackView + * @param listener + * @param immediately + */ + public void showSnack(Snack snack, Component snackView, SnackBar.OnVisibilityChangeListener listener, boolean immediately) { + if (snackView.getComponentParent() != null && snackView.getComponentParent() != this) { + snackView.getComponentParent().removeComponent(snackView); + } + SnackHolder holder = new SnackHolder(snack, snackView, listener); + mSnacks.offer(holder); + if (mSnacks.size() == 1) showSnack(holder, immediately); + } + + /** + * showSnack + * + * @param holder + */ + private void showSnack(final SnackHolder holder) { + showSnack(holder, false); + } + + /** + * showSnack + * + * @param holder + * @param showImmediately + */ + private void showSnack(final SnackHolder holder, boolean showImmediately) { + setVisibility(Component.VISIBLE); + sendOnShow(holder); + addComponent(holder.snackView); + holder.messageView.setText(holder.snack.mMessage); + if (holder.snack.mActionMessage != null) { + holder.button.setVisibility(Component.VISIBLE); + holder.button.setText(holder.snack.mActionMessage); + } else { + holder.button.setVisibility(Component.HIDE); + } + holder.button.setFont(holder.snack.mTypeface); + holder.messageView.setFont(holder.snack.mTypeface); + Color color1 = new Color(holder.snack.mBtnTextColor); + holder.button.setTextColor(color1); + RgbColor rgbColor = RgbColor.fromArgbInt(holder.snack.mBackgroundColor); + ShapeElement element = new ShapeElement(); + element.setRgbColor(rgbColor); + holder.snackView.setBackground(element); + if (holder.snack.mHeight > 0) + holder.snackView.getLayoutConfig().height = this.getPxFromDp(holder.snack.mHeight); + + if (showImmediately) { + mSlideInAnimation.setDuration(0); + } else { + mSlideInAnimation.setDuration(ANIMATION_DURATION); + } + mSlideInAnimation.setTarget(holder.snackView); + mSlideOutAnimation.setTarget(holder.snackView); + mSlideInAnimation.start(); + if (holder.snack.mDuration > 0) { + handler = new EventHandler(EventRunner.getMainEventRunner()); + handler.postTask(mHideRunnable, holder.snack.mDuration); + } + } + + /** + * sendOnHide + * + * @param snackHolder + */ + private void sendOnHide(SnackHolder snackHolder) { + if (snackHolder.visListener != null) { + snackHolder.visListener.onHide(mSnacks.size()); + } + } + + /** + * sendOnShow + * + * @param snackHolder + */ + private void sendOnShow(SnackHolder snackHolder) { + if (snackHolder.visListener != null) { + snackHolder.visListener.onShow(mSnacks.size()); + } + } + + /** + * mHideRunnable + */ + private final Runnable mHideRunnable = new Runnable() { + @Override + public void run() { + if (Component.VISIBLE == getVisibility()) { + mSlideOutAnimation.start(); + } + } + }; + + /** + * restoreState + * + * @param state + * @param v + */ + public void restoreState(Intent state, Component v) { + Sequenceable[] messages = state.getParcelableArrayParam(SAVED_MSGS); + boolean showImmediately = true; + + for (Sequenceable message : messages) { + showSnack((Snack) message, v, null, showImmediately); + showImmediately = false; + } + } + + /** + * saveState + * + * @return saveState + */ + public Intent saveState() { + Intent outState = new Intent(); + final int count = mSnacks.size(); + final Snack[] snacks = new Snack[count]; + int i = 0; + for (SnackHolder holder : mSnacks) { + snacks[i++] = holder.snack; + } + outState.setParam(SAVED_MSGS, snacks); + return outState; + } + + /** + * SnackHolder + */ + private static class SnackHolder { + final Component snackView; + final Text messageView; + final Text button; + final Snack snack; + final SnackBar.OnVisibilityChangeListener visListener; + + private SnackHolder(Snack snack, Component snackView, SnackBar.OnVisibilityChangeListener listener) { + this.snackView = snackView; + button = (Text) snackView.findComponentById(ResourceTable.Id_snackButton); + messageView = (Text) snackView.findComponentById(ResourceTable.Id_snackMessage); + + this.snack = snack; + visListener = listener; + } + } + + /** + * getPxFromDp + * + * @param dp + * @return getPxFromDp + */ + private int getPxFromDp(int dp) { + int pxConverter = 2; + int px = pxConverter * dp; + return px; + } +} diff --git a/entry/src/main/java/link/fls/swipestacksample/util/BaseDirectionalLayout.java b/entry/src/main/java/link/fls/swipestacksample/util/BaseDirectionalLayout.java new file mode 100644 index 0000000..d106659 --- /dev/null +++ b/entry/src/main/java/link/fls/swipestacksample/util/BaseDirectionalLayout.java @@ -0,0 +1,153 @@ +/* + * 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 link.fls.swipestacksample.util; + +import ohos.agp.colors.RgbColor; +import ohos.agp.components.AttrSet; +import ohos.agp.components.Component; +import ohos.agp.components.element.ShapeElement; +import ohos.app.Context; +import ohos.multimodalinput.event.TouchEvent; + +/** + * 自定义线性布局,实现点击背景变成深色的效果 + * + * @since 2021-08-21 + */ +public class BaseDirectionalLayout extends ohos.agp.components.DirectionalLayout + implements Component.TouchEventListener, Component.ClickedListener, Component.LongClickedListener { + private ShapeElement mGrayShapeElement = new ShapeElement(); + private ShapeElement mWhiteShapeElement = new ShapeElement(); + private float oldContentY = 0; + private float oldContentX = 0; + private boolean isEnable = true; + private boolean isNeedBack = false; + + /** + * BaseDirectionalLayout的构造方法,在Java类中new时调用 + * + * @param context + */ + public BaseDirectionalLayout(Context context) { + super(context); + initShapeElement(); + } + + /** + * BaseDirectionalLayout的构造方法,在xml布局中 + * + * @param context + * @param attrSet + */ + public BaseDirectionalLayout(Context context, AttrSet attrSet) { + super(context, attrSet); + initShapeElement(); + } + + /** + * BaseDirectionalLayout的构造方法,在xml布局且加Style时调用 + * + * @param context + * @param attrSet + * @param styleName + */ + public BaseDirectionalLayout(Context context, AttrSet attrSet, String styleName) { + super(context, attrSet, styleName); + initShapeElement(); + } + + /** + * setEnable + * + * @param enable isEnable + */ + public void setEnable(boolean enable) { + this.isEnable = enable; + } + + /** + * setNeedBack + * + * @param isBack isBack + */ + public void setNeedBack(boolean isBack) { + this.isNeedBack = isBack; + } + + private void initShapeElement() { + setLongClickedListener(this::onLongClicked); + setClickedListener(this::onClick); + setTouchEventListener(this::onTouchEvent); + mGrayShapeElement.setRgbColor(new RgbColor(FinalStaticBean.NUM_120, + FinalStaticBean.NUM_126, + FinalStaticBean.NUM_130)); + mWhiteShapeElement.setRgbColor(new RgbColor(FinalStaticBean.NUM_255, + FinalStaticBean.NUM_255, + FinalStaticBean.NUM_255)); + } + + @Override + public void onClick(Component component) { + + } + + /** + * onTouchEvent + * + * @param component component + * @param touchEvent touchEvent + * @return onTouchEvent + */ + @Override + public boolean onTouchEvent(Component component, TouchEvent touchEvent) { + int action = touchEvent.getAction(); + switch (action) { + case TouchEvent.PRIMARY_POINT_DOWN: + setBackground(mGrayShapeElement); + setAlpha(FinalStaticBean.NUM_HALF); + oldContentX = getContentPositionX(); + oldContentY = getContentPositionY(); + break; + case TouchEvent.POINT_MOVE: + setBackground(mWhiteShapeElement); + setAlpha(1); + break; + case TouchEvent.PRIMARY_POINT_UP: + if (isNeedBack && isEnable) { + setContentPosition(oldContentX, oldContentY); + } + setBackground(mWhiteShapeElement); + setAlpha(1); + break; + case TouchEvent.CANCEL: + setBackground(mWhiteShapeElement); + setAlpha(1); + break; + default: + break; + } + return true; + } + + /** + * onLongClicked + * + * @param component component + */ + @Override + public void onLongClicked(Component component) { + } +} diff --git a/entry/src/main/java/link/fls/swipestacksample/util/FastClickUtil.java b/entry/src/main/java/link/fls/swipestacksample/util/FastClickUtil.java new file mode 100644 index 0000000..a71b8a5 --- /dev/null +++ b/entry/src/main/java/link/fls/swipestacksample/util/FastClickUtil.java @@ -0,0 +1,45 @@ +/* + * 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 link.fls.swipestacksample.util; + +/** + * FastClickUtil + * + * @since 2021-08-21 + */ +public class FastClickUtil { + /** + * 两次点击按钮之间的点击间隔不能少于1000毫秒 + */ + private static final int MIN_CLICK_DELAY_TIME =800; + private static long lastClickTime = -1; + + /** + * 是否为快速点击 + * + * @return 快速点击 + */ + public static boolean isFastClick() { + boolean isFlag; + long curClickTime = System.currentTimeMillis(); + if (curClickTime - lastClickTime > MIN_CLICK_DELAY_TIME) { + isFlag = false; + } else { + isFlag = true; + } + lastClickTime = curClickTime; + return isFlag; + } +} diff --git a/entry/src/main/java/link/fls/swipestacksample/util/FinalStaticBean.java b/entry/src/main/java/link/fls/swipestacksample/util/FinalStaticBean.java new file mode 100644 index 0000000..8110a36 --- /dev/null +++ b/entry/src/main/java/link/fls/swipestacksample/util/FinalStaticBean.java @@ -0,0 +1,276 @@ + +/* + * 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 link.fls.swipestacksample.util; + +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogLabel; + +/** + * FinalStaticBean 常数标志类 + * + * @since 2021-08-21 + */ +public abstract class FinalStaticBean { + /** + * 表示横向网格布局 + */ + public static final int GRIDLAYOUTHORIZONTALTYPE = 1; + /** + * 表示纵向网格布局 + */ + public static final int GRIDLAYOUTVERTICALTYPE = 2; + /** + * 表示列表布局 + */ + public static final int LINEARLAYOUTTYPE = 3; + /** + * 统一HiLogLabel + */ + public static final HiLogLabel DRAGLISTVIEW = new HiLogLabel(HiLog.LOG_APP, 0x00201, "DragListView"); + /** + * 表示弧度边框 + */ + public static final int RANDIUBORDER = 0; + /** + * 无边框 + */ + public static final int NOBORDER = 1; + /** + * 添加布局 + */ + public static final int ADDCOLUMN = 200; + /** + * 删除布局 + */ + public static final int REMOVECOLUMN = 410; + /** + * 横向列表布局 + */ + public static final int HORIZONTALLISTLAYOUT = 12; + /** + * 横向网格布局 + */ + public static final int HORIZONTALGRIDLAYOUT = 18; + /** + * 清除所有item + */ + public static final int CLEARBOARD = 1019; + /** + * 横向滑动布局的宽度为屏幕的0.85 + */ + public static final double DISPLAYWIDTH = 0.85; + /** + * 左滑标志 + */ + public static final int LEFTMOVE = 4; + /** + * 右滑标志 + */ + public static final int RIGHTMOVE = 5; + /** + * 允许滑动标志 + */ + public static final int ENABLEDRAG = 6; + /** + * 禁止滑动标志 + */ + public static final int DISABLEDRAG = 7; + /** + * 上滑标志 + */ + public static final int UPMOVE = 8; + /** + * 下滑标志 + */ + public static final int DOWNMOVE = 8; + /** + * 代替常数0 + */ + public static final int NUM_0 = 0; + /** + * 代替常数1 + */ + public static final int NUM_1 = 1; + /** + * 代替常数2 + */ + public static final int NUM_2 = 2; + /** + * 代替常数3 + */ + public static final int NUM_3 = 3; + /** + * 代替常数4 + */ + public static final int NUM_4 = 4; + /** + * 代替常数5 + */ + public static final int NUM_5 = 5; + /** + * 代替常数7 + */ + public static final int NUM_7 = 7; + /** + * 代替常数12 + */ + public static final int NUM_12 = 12; + /** + * 代替常数15 + */ + public static final int NUM_15 = 15; + /** + * 代替常数16 + */ + public static final int NUM_16 = 16; + /** + * 代替常数20 + */ + public static final int NUM_20 = 20; + /** + * 代替常数40 + */ + public static final int NUM_40 = 40; + /** + * 代替常数50 + */ + public static final int NUM_50 = 50; + /** + * 代替常数58 + */ + public static final int NUM_58 = 58; + /** + * 代替常数100 + */ + public static final int NUM_100 = 100; + /** + * 代替常数120 + */ + public static final int NUM_120 = 120; + /** + * 代替常数120 + */ + public static final int NUM_126 = 126; + /** + * 代替常数120 + */ + public static final int NUM_130 = 130; + /** + * 代替常数150 + */ + public static final int NUM_150 = 150; + /** + * 代替常数198 + */ + public static final int NUM_198 = 198; + /** + * 代替常数200 + */ + public static final int NUM_200 = 200; + /** + * 代替常数255 + */ + public static final int NUM_255 = 255; + /** + * 代替常数400 + */ + public static final int NUM_400 = 400; + /** + * 代替常数500 + */ + public static final int NUM_500 = 500; + /** + * 代替常数840 + */ + public static final int NUM_840 = 840; + /** + * 代替常数1000 + */ + public static final int NUM_1000 = 1000; + /** + * 代替常数1800 + */ + public static final int NUM_1800 = 1800; + /** + * 代替常数1400 + */ + public static final int NUM_4000 = 4000; + /** + * 代替常数5000 + */ + public static final int NUM_5000 = 5000; + /** + * 代替常数0.5f + */ + public static final float NUM_HALF = 0.5f; + /** + * 代替常数0.8f + */ + public static final float NUM_ZERO_EIGHT = 0.8f; + /** + * 代替常数0.9f + */ + public static final float NUM_ZERO_NINE = 0.9f; + /** + * 代替常数1f + */ + public static final float NUM_ONE_FLOAT = 1f; + /** + * 代替字符串0 + */ + public static final String ZERO_STRING = "0"; + /** + * 代替字符串Item + */ + public static final String ITEM = "Item "; + /** + * 代替字符串Test + */ + public static final String TEST = "Test "; + /** + * 代替字符串Test board + */ + public static final String TEST_LIST = "Test lists"; + /** + * 代替字符串Disable drag + */ + public static final String DISABLEDRAG_STRING = "Disable drag"; + /** + * 代替字符串Grid layout + */ + public static final String GRIDLAYOUT = "Grid layout"; + /** + * 代替字符串Add column + */ + public static final String ADDCOLUMN_STRING = "Add column"; + /** + * 代替字符串Remove column + */ + public static final String REMOVECOLUMN_STRING = "Remove column"; + /** + * 代替字符串Clear board + */ + public static final String CLEARBOARD_STRING = "Clear board"; + /** + * Rgb中灰色值 + */ + public static final int GRAY = 198; + /** + * Rgb中白色值 + */ + public static final int WHITE = 255; +} diff --git a/entry/src/main/java/link/fls/swipestacksample/util/TinderDirectionalCard.java b/entry/src/main/java/link/fls/swipestacksample/util/TinderDirectionalCard.java new file mode 100644 index 0000000..ebb7baf --- /dev/null +++ b/entry/src/main/java/link/fls/swipestacksample/util/TinderDirectionalCard.java @@ -0,0 +1,104 @@ +/* + * 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 link.fls.swipestacksample.util; + +import link.fls.swipestack.BaseSwipeCard; +import link.fls.swipestacksample.ResourceTable; +import ohos.agp.components.AttrSet; +import ohos.agp.components.Component; +import ohos.agp.components.LayoutScatter; +import ohos.agp.components.Text; +import ohos.app.Context; + +/** + * TinderDirectionalCard + * + * @since 2021-08-17 + */ +public class TinderDirectionalCard extends BaseSwipeCard { + private Text nameText; + private Component accept; + private Component reject; + + @Override + public void showAccept() { + } + + @Override + public void showReject() { + } + + @Override + public void hideAllTips() { + accept.setVisibility(HIDE); + reject.setVisibility(HIDE); + } + + /** + * 构造函数 + * + * @param context 上下文 + */ + public TinderDirectionalCard(Context context) { + this(context, null); + } + + /** + * 构造函数 + * + * @param context 上下文 + * @param attrSet 属性 + */ + public TinderDirectionalCard(Context context, AttrSet attrSet) { + this(context, attrSet, null); + } + + /** + * 构造函数 + * + * @param context 上下文 + * @param attrSet 属性 + * @param styleName 样式名 + */ + public TinderDirectionalCard(Context context, AttrSet attrSet, String styleName) { + super(context, attrSet, styleName); + Component component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_tinder_card_view, null, true); + component.setHeight(1280); + component.setWidth(720); + nameText = (Text) component.findComponentById(ResourceTable.Id_nameAgeTxt); + accept = component.findComponentById(ResourceTable.Id_tvAccept); + reject = component.findComponentById(ResourceTable.Id_tvReject); + addComponent(component); + } + + /** + * 设置姓名 + * + * @param text 姓名集合 + */ + public void setNameText(String text) { + nameText.setText(text); + } + + /** + * getNameText + * + * @return getNameText + */ + public String getNameText() { + return nameText.getText(); + } +} diff --git a/entry/src/main/resources/base/element/color.json b/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000..9edba79 --- /dev/null +++ b/entry/src/main/resources/base/element/color.json @@ -0,0 +1,72 @@ +{ + "color": [ + { + "name": "colorPrimary", + "value": "#000000" + }, + { + "name": "colorPrimaryDark", + "value": "#000000" + }, + { + "name": "colorAccent", + "value": "#FF4081" + }, + { + "name": "white", + "value": "#FFFFFF" + }, + { + "name": "black", + "value": "#000000" + }, + { + "name": "bg_color", + "value": "#e8edf3" + }, + { + "name": "red", + "value": "#FFFF0000" + }, + { + "name": "blue", + "value": "#22264b" + }, + { + "name": "yellow", + "value": "#f2b632" + }, + { + "name": "yellow1", + "value": "#f2b632" + }, + { + "name": "shadow", + "value": "#77BBBBBB" + }, + { + "name": "grey", + "value": "#e5e5e5" + }, + { + "name": "gainsboro", + "value": "#DCDCDC" + }, + { + "name": "seashell", + "value": "#8B8682" + }, + { + "name": "midnightBlue", + "value": "#22264b" + }, + { + "name": "sb__snack_bkgnd", + "value": "#323232" + }, + { + "name": "sb__snack_alert_bkgnd", + "value": "#FF070F" + } + ] +} 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 0000000..9d373f1 --- /dev/null +++ b/entry/src/main/resources/base/element/string.json @@ -0,0 +1,48 @@ +{ + "string": [ + { + "name": "entry_MainAbility", + "value": "SwipeStack" + }, + { + "name": "mainability_description", + "value": "Java_Empty Ability" + }, + { + "name": "mainability_HelloWorld", + "value": "Hello World" + }, + { + "name": "widget_ability_description", + "value": "This is a WidgetAbility" + }, + { + "name": "widget_title", + "value": "Title" + }, + { + "name": "widget_introduction", + "value": "Introduction" + }, + { + "name": "view_swiped_left", + "value": "%1$s swiped to left!" + }, + { + "name": "view_swiped_right", + "value": "%1$s swiped to right!" + }, + { + "name": "dummy_text", + "value": "Test" + }, + { + "name": "dummy_fab", + "value": "Fab Test" + }, + { + "name": "main_url_value", + "value": "https://gitee.com/chinasoft4_ohos/SwipeStack" + } + ] +} \ 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 0000000..c0c0a3d --- /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/graphic/background_button.xml b/entry/src/main/resources/base/graphic/background_button.xml new file mode 100644 index 0000000..7310da1 --- /dev/null +++ b/entry/src/main/resources/base/graphic/background_button.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/graphic/tinder_card_bg.xml b/entry/src/main/resources/base/graphic/tinder_card_bg.xml new file mode 100644 index 0000000..9d591d7 --- /dev/null +++ b/entry/src/main/resources/base/graphic/tinder_card_bg.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + \ 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 0000000..f49971d --- /dev/null +++ b/entry/src/main/resources/base/layout/ability_main.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + +