From e1e98adb6cda8dd8079777f100607a68c6c8c602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9C=E5=85=B5=E5=85=B5?= Date: Wed, 2 Jun 2021 15:38:18 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- entry/src/main/config.json | 6 +- .../sample/MainAbility.java | 33 -- .../sample/MyApplication.java | 24 - .../sample/adapter/ListAdapter.java | 69 --- .../sample/adapter/MainPagerAdapter.java | 64 --- .../sample/adapter/ViewHolder.java | 54 -- .../sample/slice/MainAbilitySlice.java | 159 ----- .../sample/utils/MyToast.java | 99 ---- .../sample/utils/ViewCreateHelper.java | 171 ------ .../main/resources/base/layout/text_item.xml | 4 +- .../base/layout/text_item_scroll_test.xml | 4 +- entry/src/ohosTest/config.json | 4 +- .../expandabletextview/ExampleOhosTest.java | 17 - .../ExpandableTextView.java | 543 ------------------ .../expandabletextview/TypedAttrUtils.java | 118 ---- 15 files changed, 9 insertions(+), 1360 deletions(-) delete mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/MainAbility.java delete mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/MyApplication.java delete mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/ListAdapter.java delete mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/MainPagerAdapter.java delete mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/ViewHolder.java delete mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/slice/MainAbilitySlice.java delete mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/utils/MyToast.java delete mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/utils/ViewCreateHelper.java delete mode 100644 entry/src/ohosTest/java/com/hos/expandabletextview/ExampleOhosTest.java delete mode 100644 lib/src/main/java/com/ms/square/ohos/expandabletextview/ExpandableTextView.java delete mode 100644 lib/src/main/java/com/ms/square/ohos/expandabletextview/TypedAttrUtils.java diff --git a/entry/src/main/config.json b/entry/src/main/config.json index f2d6d13..7e09f01 100644 --- a/entry/src/main/config.json +++ b/entry/src/main/config.json @@ -1,6 +1,6 @@ { "app": { - "bundleName": "com.ms.square.ohos.expandabletextview.sample", + "bundleName": "com.ms.square.ohos.expandabletext.sample", "vendor": "hos", "version": { "code": 1, @@ -14,7 +14,7 @@ }, "deviceConfig": {}, "module": { - "package": "com.ms.square.ohos.expandabletextview.sample", + "package": "com.ms.square.ohos.expandabletext.sample", "name": ".MyApplication", "deviceType": [ "phone" @@ -46,7 +46,7 @@ } ], "orientation": "unspecified", - "name": "com.ms.square.ohos.expandabletextview.sample.MainAbility", + "name": "com.ms.square.ohos.expandabletext.sample.MainAbility", "icon": "$media:icon", "description": "$string:mainability_description", "label": "$string:app_name", diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/MainAbility.java b/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/MainAbility.java deleted file mode 100644 index e9495de..0000000 --- a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/MainAbility.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.ms.square.ohos.expandabletextview.sample; - -import com.ms.square.ohos.expandabletextview.sample.slice.MainAbilitySlice; -import ohos.aafwk.ability.Ability; -import ohos.aafwk.content.Intent; -import ohos.agp.components.ComponentContainer; - -public class MainAbility extends Ability { - @Override - public void onStart(Intent intent) { - super.onStart(intent); - super.setMainRoute(MainAbilitySlice.class.getName()); - } - - @Override - public void setUIContent(ComponentContainer componentContainer) { - super.setUIContent(componentContainer); - } -} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/MyApplication.java b/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/MyApplication.java deleted file mode 100644 index 50c1ced..0000000 --- a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/MyApplication.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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.ms.square.ohos.expandabletextview.sample; - -import ohos.aafwk.ability.AbilityPackage; - -public class MyApplication extends AbilityPackage { - @Override - public void onInitialize() { - super.onInitialize(); - } -} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/ListAdapter.java b/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/ListAdapter.java deleted file mode 100644 index ddfb017..0000000 --- a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/ListAdapter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.ms.square.ohos.expandabletextview.sample.adapter; - -import ohos.agp.components.BaseItemProvider; -import ohos.agp.components.Component; -import ohos.agp.components.ComponentContainer; -import ohos.agp.components.LayoutScatter; -import ohos.app.Context; - -import java.util.List; - -/** - * author zhaoxudong - * Version 1.0 - * ModifiedBy - * date 2021-03-15 10:13 - * description 列表数据适配器 - */ -public abstract class ListAdapter extends BaseItemProvider { - private List data; - private Context ct; - private int itemId; - - public ListAdapter(Context ct, int itemId, List data) { - this.data = data; - this.ct = ct; - this.itemId = itemId; - } - - public abstract void convert(ViewHolder viewHolder, T item, int position); - - @Override - public int getCount() { - return data == null ? 0 : data.size(); - } - - @Override - public T getItem(int i) { - return data.get(i); - } - - @Override - public long getItemId(int i) { - return i; - } - - @Override - public Component getComponent(int i, Component component, ComponentContainer componentContainer) { - ViewHolder viewHolder; - Component itemView = LayoutScatter.getInstance(ct).parse(itemId, componentContainer, false); - viewHolder = new ViewHolder(ct, itemView, componentContainer, i); - convert(viewHolder, getItem(i), i); - return itemView; - } -} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/MainPagerAdapter.java b/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/MainPagerAdapter.java deleted file mode 100644 index 10728da..0000000 --- a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/MainPagerAdapter.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.ms.square.ohos.expandabletextview.sample.adapter; - -import ohos.agp.components.Component; -import ohos.agp.components.ComponentContainer; -import ohos.agp.components.PageSliderProvider; - -import java.util.ArrayList; -import java.util.List; - -/** - * author zhaoxudong - * Version 1.0 - * ModifiedBy - * date 2021-03-15 10:13 - * description PageSlider适配器 - */ -public class MainPagerAdapter extends PageSliderProvider { - private List pages; - - /** - * 构造函数 - * - * @param pages 页面 - */ - public MainPagerAdapter(ArrayList pages) { - this.pages = pages; - } - - @Override - public int getCount() { - return pages == null ? 0 : pages.size(); - } - - @Override - public Object createPageInContainer(ComponentContainer componentContainer, int i) { - componentContainer.addComponent(pages.get(i)); - return componentContainer; - } - - @Override - public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) { - componentContainer.removeComponent(pages.get(i)); - } - - @Override - public boolean isPageMatchToObject(Component component, Object object) { - return component == object; - } -} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/ViewHolder.java b/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/ViewHolder.java deleted file mode 100644 index ec2a77f..0000000 --- a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/adapter/ViewHolder.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.ms.square.ohos.expandabletextview.sample.adapter; - -import ohos.agp.components.Component; -import ohos.agp.components.ComponentContainer; -import ohos.app.Context; - -import java.util.HashMap; - -/** - * author zhaoxudong - * Version 1.0 - * ModifiedBy - * date 2021-03-15 10:13 - * description ViewHolder - */ -public class ViewHolder { - int position; - int layoutId; - private Component component; - private Context context; - private HashMap views; - - ViewHolder(Context context, Component itemView, ComponentContainer parent, int position) { - this.context = context; - this.component = itemView; - this.position = position; - views = new HashMap<>(0); - component.setTag(this); - } - - @SuppressWarnings("unchecked") - public T getView(int viewId) { - Component view = views.get(viewId); - if (view == null) { - view = component.findComponentById(viewId); - views.put(viewId, view); - } - return (T) view; - } -} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/slice/MainAbilitySlice.java b/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/slice/MainAbilitySlice.java deleted file mode 100644 index 9904462..0000000 --- a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/slice/MainAbilitySlice.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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.ms.square.ohos.expandabletextview.sample.slice; - -import com.ms.square.ohos.expandabletextview.sample.ResourceTable; -import com.ms.square.ohos.expandabletextview.sample.adapter.MainPagerAdapter; -import com.ms.square.ohos.expandabletextview.sample.utils.ViewCreateHelper; -import ohos.aafwk.ability.AbilitySlice; -import ohos.aafwk.content.Intent; -import ohos.agp.colors.RgbColor; -import ohos.agp.components.Component; -import ohos.agp.components.DirectionalLayout; -import ohos.agp.components.PageSlider; -import ohos.agp.components.TabList; -import ohos.agp.components.element.ShapeElement; -import ohos.agp.window.service.WindowManager; -import ohos.global.resource.NotExistException; -import ohos.global.resource.WrongTypeException; -import ohos.hiviewdfx.HiLog; -import ohos.hiviewdfx.HiLogLabel; - -import java.io.IOException; -import java.util.ArrayList; - -/** - * author zhaoxudong - * Version 1.0 - * ModifiedBy - * date 2021-03-15 10:13 - * description 主界面 - */ -public class MainAbilitySlice extends AbilitySlice implements TabList.TabSelectedListener, - PageSlider.PageChangedListener { - private static final HiLogLabel HI_LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0xFFFFF, "MainAbilitySlice"); - private static final int GRAY_COLOR = 211; - private static final int WHITE_COLOR = 0; - private TabList tabList; - private PageSlider pageSlider; - private DirectionalLayout rootLayout; - - @Override - public void onStart(Intent intent) { - // 设置状态栏颜色 - WindowManager.getInstance().getTopWindow().get().setStatusBarColor(getColor(ResourceTable.Color_purple_700)); - super.onStart(intent); - super.setUIContent(ResourceTable.Layout_ability_main); - initView(); - initData(); - } - - private void initView() { - tabList = (TabList) findComponentById(ResourceTable.Id_tab_list); - pageSlider = (PageSlider) findComponentById(ResourceTable.Id_pager); - tabList.addTabSelectedListener(this); - pageSlider.addPageChangedListener(this); - tabList.setFixedMode(true); - rootLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_root); - } - - /** - * 设置tabList - */ - private void initData() { - try { - String[] tabsTitle = getResourceManager().getElement(ResourceTable.Strarray_tab_title).getStringArray(); - for (String title : tabsTitle) { - TabList.Tab tab = tabList.new Tab(getContext()); - tab.setText(title); - ShapeElement shapeElement = new ShapeElement(); - shapeElement.setRgbColor(new RgbColor(0, 0, 0, 0)); - tab.setBackground(shapeElement); - tabList.addTab(tab); - } - tabList.selectTabAt(0); - pageSlider.setProvider(new MainPagerAdapter(initPageSliderViewData())); - pageSlider.setCurrentPage(0); - pageSlider.setReboundEffect(true); - pageSlider.setCentralScrollMode(true); - } catch (IOException | NotExistException | WrongTypeException e) { - HiLog.debug(HI_LOG_LABEL, e.getMessage()); - } - } - - private ArrayList initPageSliderViewData() { - ArrayList pages = new ArrayList<>(); - int pageSize = tabList.getTabCount(); - if (tabList == null || pageSize < 1) { - HiLog.debug(HI_LOG_LABEL, "initPageSliderViewData tabList is null"); - return pages; - } - ViewCreateHelper viewCreateHelper = new ViewCreateHelper(getContext()); - for (int tabIndex = 0; tabIndex < pageSize; tabIndex++) { - pages.add(viewCreateHelper.createView(tabList.getTabAt(tabIndex).getText(), tabIndex)); - } - return pages; - } - - @Override - public void onActive() { - super.onActive(); - } - - @Override - public void onForeground(Intent intent) { - super.onForeground(intent); - } - - @Override - public void onPageSliding(int i, float v, int i1) { - } - - @Override - public void onPageSlideStateChanged(int i) { - } - - @Override - public void onPageChosen(int i) { - if (tabList.getSelectedTab().getPosition() != i) { - tabList.selectTabAt(i); - } - if (i == 0) { - ShapeElement shapeElement = new ShapeElement(); - shapeElement.setRgbColor(new RgbColor(GRAY_COLOR, GRAY_COLOR, GRAY_COLOR, GRAY_COLOR)); - rootLayout.setBackground(shapeElement); - } else { - ShapeElement shapeElement = new ShapeElement(); - shapeElement.setRgbColor(new RgbColor(WHITE_COLOR, WHITE_COLOR, WHITE_COLOR, WHITE_COLOR)); - rootLayout.setBackground(shapeElement); - } - } - - @Override - public void onSelected(TabList.Tab tab) { - if (pageSlider.getCurrentPage() != tab.getPosition()) { - pageSlider.setCurrentPage(tab.getPosition()); - } - } - - @Override - public void onUnselected(TabList.Tab tab) { - } - - @Override - public void onReselected(TabList.Tab tab) { - } -} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/utils/MyToast.java b/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/utils/MyToast.java deleted file mode 100644 index 1cb12e6..0000000 --- a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/utils/MyToast.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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.ms.square.ohos.expandabletextview.sample.utils; - -import ohos.agp.colors.RgbColor; -import ohos.agp.components.DirectionalLayout; -import ohos.agp.components.Text; -import ohos.agp.components.element.ShapeElement; -import ohos.agp.utils.Color; -import ohos.agp.utils.LayoutAlignment; -import ohos.agp.window.dialog.ToastDialog; -import ohos.agp.window.service.DisplayAttributes; -import ohos.agp.window.service.DisplayManager; -import ohos.app.Context; - -/** - * author zhaoxudong - * Version 1.0 - * ModifiedBy - * date 2021-03-05 14:46 - * description 自定义Toast - */ -public class MyToast { - public static final int LENGTH_SHORT = 2000; - private static ToastDialog toastDialog; - - public enum ToastLayout { - CENTER, - TOP, - BOTTOM, - } - - public static void show(Context mContext, String content, ToastLayout layout) { - createTost(mContext, content, LENGTH_SHORT, layout); - } - - private static void createTost(Context mContext, String content, int duration, ToastLayout layout) { - DirectionalLayout toastLayout = new DirectionalLayout(mContext); - DirectionalLayout.LayoutConfig textConfig = new DirectionalLayout.LayoutConfig(DirectionalLayout.LayoutConfig.MATCH_CONTENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT); - Text text = new Text(mContext); - text.setText(content); - text.setTextColor(new Color(Color.getIntColor("#ffffff"))); - text.setPadding(vp2px(mContext, 16), vp2px(mContext, 10), vp2px(mContext, 16), vp2px(mContext, 10)); - text.setTextSize(vp2px(mContext, 12)); - text.setBackground(buildDrawableByColorRadius(Color.getIntColor("#70000000"), vp2px(mContext, 20))); - text.setLayoutConfig(textConfig); - text.setMarginBottom(20); - toastLayout.addComponent(text); - int mLayout = LayoutAlignment.CENTER; - switch (layout) { - case TOP: - mLayout = LayoutAlignment.TOP; - break; - case BOTTOM: - mLayout = LayoutAlignment.BOTTOM; - break; - case CENTER: - mLayout = LayoutAlignment.CENTER; - break; - } - if (toastDialog != null) { - toastDialog.cancel(); - toastDialog = null; - } - toastDialog = new ToastDialog(mContext); - toastDialog.setComponent(toastLayout); - toastDialog.setSize(DirectionalLayout.LayoutConfig.MATCH_CONTENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT); - toastDialog.setAlignment(mLayout); - toastDialog.setTransparent(true); - toastDialog.setDuration(duration); - toastDialog.show(); - } - - - private static ohos.agp.components.element.Element buildDrawableByColorRadius(int color, float radius) { - ShapeElement drawable = new ShapeElement(); - drawable.setShape(0); - drawable.setRgbColor(RgbColor.fromArgbInt(color)); - drawable.setCornerRadius(radius); - return drawable; - } - - private static int vp2px(Context context, float vp) { - DisplayAttributes attributes = DisplayManager.getInstance().getDefaultDisplay(context).get().getAttributes(); - return (int) (attributes.densityPixels * vp); - } -} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/utils/ViewCreateHelper.java b/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/utils/ViewCreateHelper.java deleted file mode 100644 index 720703c..0000000 --- a/entry/src/main/java/com/ms/square/ohos/expandabletextview/sample/utils/ViewCreateHelper.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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.ms.square.ohos.expandabletextview.sample.utils; - -import com.ms.square.ohos.expandabletextview.ExpandableTextView; -import com.ms.square.ohos.expandabletextview.sample.ResourceTable; -import com.ms.square.ohos.expandabletextview.sample.adapter.ListAdapter; -import com.ms.square.ohos.expandabletextview.sample.adapter.ViewHolder; -import ohos.agp.components.*; -import ohos.agp.render.Paint; -import ohos.app.Context; -import ohos.hiviewdfx.HiLog; -import ohos.hiviewdfx.HiLogLabel; - -import java.util.ArrayList; -import java.util.List; - -/** - * author zhaoxudong - * Version 1.0 - * ModifiedBy - * date 2021-03-15 10:13 - * description ViewCreateHelper - */ -public final class ViewCreateHelper { - private static final HiLogLabel HI_LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0xFFFFF, "ViewCreateHelper"); - /** - * 列表长度 - */ - private static final int ITEM_LEN = 10; - private static final int MAX_COLLAPSED_LINES = 4; - private static final int DEFAULT = 2; - private Context slice; - - /** - * 构造函数 - * - * @param abilitySlice Context - */ - public ViewCreateHelper(Context abilitySlice) { - slice = abilitySlice; - } - - /** - * 创建view - * - * @param title 标题 - * @param position 位置 - * @return Component - */ - public Component createView(String title, int position) { - HiLog.debug(HI_LOG_LABEL, "createView position =" + position); - Component mainComponent; - if (position == 0) { - mainComponent = - LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_pager_srcoll_item, null, false); - if (!(mainComponent instanceof ComponentContainer)) { - return mainComponent; - } - ScrollView scrollView = (ScrollView) mainComponent.findComponentById(ResourceTable.Id_scroll); - scrollView.enableScrollBar(1, true); - ComponentContainer rootLayout = (ComponentContainer) mainComponent; - DirectionalLayout root = (DirectionalLayout) rootLayout.findComponentById(ResourceTable.Id_root); - int itemCount = root.getChildCount(); - if (root != null && itemCount > 0) { - for (int index = 0; index < itemCount; index++) { - Component component = root.getComponentAt(index); - Text titleText = (Text) component.findComponentById(ResourceTable.Id_title); - titleText.setText("Sample " + (index + 1)); - ExpandableTextView expandableTextView = (ExpandableTextView) - component.findComponentById(ResourceTable.Id_expandable); - expandableTextView.setText(slice.getString(ResourceTable.String_dummy_text2)); - expandableTextView.setOnExpandStateChangeListener(new ExpandableTextView.OnExpandStateChangeListener() { - @Override - public void onExpandStateChanged(Text textView) { - - } - - @Override - public void expandStateChangedToast(boolean isExpanded) { - MyToast.show(slice, isExpanded ? "Expanded" : "Collapsed", MyToast.ToastLayout.BOTTOM); - } - }); - } - } - return rootLayout; - } else { - mainComponent = - LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_pager_item, null, false); - if (!(mainComponent instanceof ComponentContainer)) { - return mainComponent; - } - ComponentContainer rootLayout = (ComponentContainer) mainComponent; - initView(mainComponent, title); - return rootLayout; - } - } - - private int getFontHeight(int fontSize) { - Paint paint = new Paint(); - paint.setTextSize(fontSize); - Paint.FontMetrics fm = paint.getFontMetrics(); - return (int) (Math.ceil(fm.descent - fm.top) + DEFAULT) * MAX_COLLAPSED_LINES; - } - - ListAdapter listAdapter = null; - - private void initView(Component mainComponent, String title) { - // 列表 - ListContainer listContainer = (ListContainer) mainComponent.findComponentById(ResourceTable.Id_list_main); - listContainer.enableScrollBar(1, true); - listAdapter = new ListAdapter(slice, ResourceTable.Layout_text_item, getData()) { - @Override - public void convert(ViewHolder viewHolder, String item, int position) { - Text text = viewHolder.getView(ResourceTable.Id_expandable_text); - text.setTag(position + ""); - text.setHeight(getFontHeight(text.getTextSize())); - ExpandableTextView expandableTextView = viewHolder.getView(ResourceTable.Id_expandable); - expandableTextView.setText(slice.getString(ResourceTable.String_dummy_text2)); - expandableTextView.setOnExpandStateChangeListener(new ExpandableTextView.OnExpandStateChangeListener() { - @Override - public void onExpandStateChanged(Text textView) { - int position = Integer.valueOf(textView.getTag().toString()).intValue(); - listAdapter.notifyDataSetItemChanged(position + 1); - } - - @Override - public void expandStateChangedToast(boolean isExpanded) { - MyToast.show(slice, isExpanded ? "Expanded" : "Collapsed", MyToast.ToastLayout.BOTTOM); - } - }); - } - }; - listContainer.setLayoutRefreshedListener(new Component.LayoutRefreshedListener() { - @Override - public void onRefreshed(Component component) { - if (listContainer.getHeight() < ((ComponentContainer) (component.getComponentParent())).getHeight()) { - listContainer.setEnabled(false); - } else { - listContainer.setEnabled(true); - } - } - }); - listContainer.setItemProvider(listAdapter); - listContainer.setItemClickedListener(new ListContainer.ItemClickedListener() { - @Override - public void onItemClicked(ListContainer listContainer, Component component, int position, long l) { - } - }); - } - - private List getData() { - List curData = new ArrayList<>(); - for (int index = 0; index < ITEM_LEN; index++) { - curData.add("测试"); - } - return curData; - } -} diff --git a/entry/src/main/resources/base/layout/text_item.xml b/entry/src/main/resources/base/layout/text_item.xml index 3ad58a1..10dac9d 100644 --- a/entry/src/main/resources/base/layout/text_item.xml +++ b/entry/src/main/resources/base/layout/text_item.xml @@ -6,7 +6,7 @@ ohos:width="match_parent" ohos:orientation="vertical"> - - + - - + \ No newline at end of file diff --git a/entry/src/ohosTest/config.json b/entry/src/ohosTest/config.json index 7ce8620..dc716ce 100644 --- a/entry/src/ohosTest/config.json +++ b/entry/src/ohosTest/config.json @@ -1,6 +1,6 @@ { "app": { - "bundleName": "com.hos.expandabletextview", + "bundleName": "com.hos.expandabletext", "vendor": "hos", "version": { "code": 1, @@ -14,7 +14,7 @@ }, "deviceConfig": {}, "module": { - "package": "com.hos.expandabletextview", + "package": "com.hos.expandabletext", "name": "testModule", "deviceType": [ "phone" diff --git a/entry/src/ohosTest/java/com/hos/expandabletextview/ExampleOhosTest.java b/entry/src/ohosTest/java/com/hos/expandabletextview/ExampleOhosTest.java deleted file mode 100644 index d7ea0d1..0000000 --- a/entry/src/ohosTest/java/com/hos/expandabletextview/ExampleOhosTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.hos.expandabletextview; - -import ohos.aafwk.ability.delegation.AbilityDelegatorRegistry; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class ExampleOhosTest { - /** - * 全UI应用、不支持Context,不支持单元测试 - */ - @Test - public void testBundleName() { - final String actualBundleName = AbilityDelegatorRegistry.getArguments().getTestBundleName(); - assertEquals("com.hos.expandabletextview", actualBundleName); - } -} \ No newline at end of file diff --git a/lib/src/main/java/com/ms/square/ohos/expandabletextview/ExpandableTextView.java b/lib/src/main/java/com/ms/square/ohos/expandabletextview/ExpandableTextView.java deleted file mode 100644 index e6ae35b..0000000 --- a/lib/src/main/java/com/ms/square/ohos/expandabletextview/ExpandableTextView.java +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Copyright (C) 2011 The Open Source Project - * Copyright 2014 Manabu Shimobe - * - * 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.ms.square.ohos.expandabletextview; - -import ohos.agp.animation.Animator; -import ohos.agp.animation.AnimatorValue; -import ohos.agp.components.*; -import ohos.agp.components.element.PixelMapElement; -import ohos.agp.render.Canvas; -import ohos.agp.render.Paint; -import ohos.app.Context; -import ohos.hiviewdfx.HiLog; -import ohos.hiviewdfx.HiLogLabel; -import ohos.media.image.ImageSource; -import ohos.media.image.PixelMap; -import ohos.media.image.common.PixelFormat; -import ohos.media.image.common.Rect; -import ohos.media.image.common.Size; - -import java.io.InputStream; -import java.util.Map; - -/** - * author zhaoxudong - * Version 1.0 - * ModifiedBy - * date 2021-02-22 10:12 - * description 可折叠的TextView - */ -public class ExpandableTextView extends DirectionalLayout implements - Component.EstimateSizeListener, Component.ClickedListener, ComponentContainer.ArrangeListener { - private static final HiLogLabel logLabel = new HiLogLabel(HiLog.LOG_APP, 0x00101, "ExpandableTextView"); - - private static final int EXPAND_INDICATOR_IMAGE_BUTTON = 0; - - private static final int EXPAND_INDICATOR_TEXT_VIEW = 1; - - private static final int DEFAULT_TOGGLE_TYPE = EXPAND_INDICATOR_IMAGE_BUTTON; - - /* The default number of lines */ - private static final int MAX_COLLAPSED_LINES = 4; - - /* The default animation duration */ - private static final int DEFAULT_ANIM_DURATION = 300; - - /* The default alpha value when the animation starts */ - private static final float DEFAULT_ANIM_ALPHA_START = 0.7f; - - private boolean mRelayout = true; - - // Show short version as default. - private boolean mCollapsed = true; - - private int mCollapsedHeight; - - private int mTextHeightWithMaxLines; - private int singleTextHeight; - /** - * 内容展示Text - */ - private Text expandText; - - /** - * 展开,收缩图标 - * View to expand/collapse - */ - private Component expandCollapse; - - /** - * 最大展示行数 - */ - private int maxCollapsedLines; - - private int mMarginBetweenTxtAndBottom; - - /** - * 文本是否可以被点击 - */ - private boolean expandToggleOnTextClick; - - - private ExpandIndicatorController mExpandIndicatorController; - - /** - * 动画展示时长 - */ - private int animationDuration; - - /** - * 起始透明度 - */ - private float animAlphaStart = 0.7f; - - private OnExpandStateChangeListener mListener; - - /** - * 收缩状态 - */ - private Map collapsedStatus; - - private int mPosition; - private int mStartHeight; - private int expendTextHeight; - private Context context; - - /** - * 构造函数 - * - * @param context Context - */ - public ExpandableTextView(Context context) { - this(context, null); - } - - /** - * 构造函数 - * - * @param context Context - * @param attrSet AttrSet - */ - public ExpandableTextView(Context context, AttrSet attrSet) { - super(context, attrSet); - this.context = context; - init(attrSet); - } - - /** - * 构造函数 - * - * @param context Context - * @param attrSet AttrSet - * @param styleName styleName - */ - public ExpandableTextView(Context context, AttrSet attrSet, String styleName) { - super(context, attrSet, styleName); - init(attrSet); - } - - /** - * 设置布局方向(只支持竖向) - * - * @param orientation 布局方向 - */ - @Override - public void setOrientation(int orientation) { - if (Component.HORIZONTAL == orientation) { - throw new IllegalArgumentException("ExpandableTextView only supports Vertical Orientation."); - } - super.setOrientation(orientation); - } - - AnimatorValue animation = new AnimatorValue(); - - @Override - public void onClick(Component component) { - if (animation.isRunning()) { - return; - } - if (expandCollapse.getVisibility() != Component.VISIBLE) { - return; - } - - mCollapsed = !mCollapsed; - mExpandIndicatorController.changeState(mCollapsed); - - // 记录伸缩状态 - if (collapsedStatus != null) { - collapsedStatus.put(mPosition, mCollapsed); - } - - if (mStartHeight == 0) { - mStartHeight = getHeight(); - expendTextHeight = expandText.getHeight(); - expandText.setHeight(expendTextHeight); - expandText.setMaxTextLines(Integer.MAX_VALUE); - } - - // 动效 - animation.setDuration(animationDuration); - animation.setStateChangedListener(new Animator.StateChangedListener() { - @Override - public void onStart(Animator animator) { - applyAlphaAnimation(expandText, animAlphaStart); - } - - @Override - public void onStop(Animator animator) { - - } - - @Override - public void onCancel(Animator animator) { - - } - - @Override - public void onEnd(Animator animator) { - // notify the listener - mListener.expandStateChangedToast(!mCollapsed); - } - - @Override - public void onPause(Animator animator) { - - } - - @Override - public void onResume(Animator animator) { - - } - }); - animation.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() { - - @Override - public void onUpdate(AnimatorValue animatorValue, float interpolatedTime) { - final int newHeight; - if (mCollapsed) { - newHeight = (int) ((mCollapsedHeight - getHeight()) * interpolatedTime + getHeight()); - } else { - int mEndHeight = mStartHeight + singleTextHeight * 7 - expendTextHeight; - newHeight = (int) ((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight); - } - expandText.setHeight(newHeight - mMarginBetweenTxtAndBottom); - if (Float.compare(animAlphaStart, 1.0f) != 0) { - applyAlphaAnimation(expandText, animAlphaStart + interpolatedTime * (1.0f - animAlphaStart)); - } - - getContext().getUITaskDispatcher().delayDispatch(new Runnable() { - @Override - public void run() { - if (mListener != null) { - mListener.onExpandStateChanged(expandText); - } - } - }, 10); - } - }); - - animation.start(); - } - - @Override - public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) { - HiLog.debug(logLabel, "onEstimateSize"); - singleTextHeight = getFontHeight(expandText.getTextSize()); - // If no change, measure and return - if (!mRelayout || getVisibility() == Component.HIDE) { - return false; - } - mRelayout = false; - - // Setup with optimistic case - // i.e. Everything fits. No button needed - expandCollapse.setVisibility(Component.HIDE); - expandText.setMaxTextLines(Integer.MAX_VALUE); - - // Measure - super.estimateSize(widthEstimateConfig, heightEstimateConfig); - // If the text fits in collapsed mode, we are done. - if (expandText.getMaxTextLines() <= maxCollapsedLines) { - return false; - } - // Saves the text height w/ max lines - mTextHeightWithMaxLines = getRealTextViewHeight(expandText); - // Doesn't fit in collapsed mode. Collapse text view as needed. Show - // button. - if (mCollapsed) { - expandText.setMaxTextLines(maxCollapsedLines); - } - expandCollapse.setVisibility(Component.VISIBLE); - - // Re-measure with new setup - super.estimateSize(widthEstimateConfig, heightEstimateConfig); - - if (mCollapsed) { - mMarginBetweenTxtAndBottom = getHeight() - expandText.getHeight(); - // Saves the collapsed height of this ViewGroup - mCollapsedHeight = getEstimatedHeight(); - } - return false; - } - - - /** - * 获取一行的字体高度 - * - * @param fontSize 字体大小 - * @return 行高 - */ - private int getFontHeight(int fontSize) { - Paint paint = new Paint(); - paint.setTextSize(fontSize); - Paint.FontMetrics fm = paint.getFontMetrics(); - return (int) Math.ceil(fm.descent - fm.top) + 2; - } - - private void init(AttrSet attrs) { - initAttrs(attrs); - // enforces vertical orientation - setOrientation(Component.VERTICAL); - //add绘制的回调 - addDrawTask(mDrawTask); - - } - - private int getRealTextViewHeight(Text textView) { - int textHeight = textView.getHeight(); - int padding = textView.getPaddingTop() + textView.getPaddingBottom(); - return textHeight + padding; - } - - //绘制的回调 - final private DrawTask mDrawTask = new DrawTask() { - @Override - public void onDraw(Component component, Canvas canvas) { - //add测量的回调 - setEstimateSizeListener(ExpandableTextView.this); - //add布局的回调 - setArrangeListener(ExpandableTextView.this); - findViews(); - - } - }; - - - /** - * 初始化属性 - * - * @param attrSet 属性 - */ - private void initAttrs(AttrSet attrSet) { - maxCollapsedLines = TypedAttrUtils.getInteger(attrSet, "maxCollapsedLines", MAX_COLLAPSED_LINES); - animationDuration = TypedAttrUtils.getInteger(attrSet, "animDuration", DEFAULT_ANIM_DURATION); - animAlphaStart = TypedAttrUtils.getFloat(attrSet, "animAlphaStart", DEFAULT_ANIM_ALPHA_START); - expandToggleOnTextClick = TypedAttrUtils.getBoolean(attrSet, "expandToggleOnTextClick", true); - mExpandIndicatorController = setupExpandToggleController(getContext(), attrSet); - } - - private void findViews() { - int count = getChildCount(); - if (count < 1) { - return; - } - for (int i = 0; i < count; i++) { - Component component = getComponentAt(i); - if (component.getComponentDescription().toString().equals("expandable_text")) { - expandText = (Text) component; - } else if (component.getComponentDescription().toString().equals("expand_collapse")) { - expandCollapse = component; - } - } - if (expandToggleOnTextClick) { - expandText.setClickedListener(this); - } else { - expandText.setClickedListener(null); - } - expandCollapse.setClickedListener(this); - mExpandIndicatorController.setView(expandCollapse); - mExpandIndicatorController.changeState(mCollapsed); - - // enforces vertical orientation - setOrientation(Component.VERTICAL); - } - - /** - * 设置监听 - * - * @param listener 监听器 - */ - public void setOnExpandStateChangeListener(OnExpandStateChangeListener listener) { - mListener = listener; - } - - @Override - public boolean onArrange(int i, int i1, int i2, int i3) { - return false; - } - - public interface OnExpandStateChangeListener { - /** - * Called when the expand/collapse animation has been finished - * - * @param textView - TextView being expanded/collapsed - */ - void onExpandStateChanged(Text textView); - - /** - * 状态改变时的提示语 - * - * @param isExpanded 是否是展开状态 - */ - void expandStateChangedToast(boolean isExpanded); - } - - interface ExpandIndicatorController { - void changeState(boolean collapsed); - - void setView(Component toggleView); - } - - private static void applyAlphaAnimation(Component view, float alpha) { - view.setAlpha(alpha); - } - - /** - * Image图标控制器 - */ - private static class ImageButtonExpandController implements ExpandIndicatorController { - - private final PixelMap mExpandDrawable; - private final PixelMap mCollapseDrawable; - - private Image mImageButton; - - public ImageButtonExpandController(PixelMap expandDrawable, PixelMap collapseDrawable) { - mExpandDrawable = expandDrawable; - mCollapseDrawable = collapseDrawable; - } - - @Override - public void changeState(boolean collapsed) { - mImageButton.setPixelMap(collapsed ? mExpandDrawable : mCollapseDrawable); - } - - @Override - public void setView(Component toggleView) { - mImageButton = (Image) toggleView; - } - } - - /** - * Text图标控制器 - */ - static class TextViewExpandController implements ExpandIndicatorController { - - private final int mExpandText; - private final int mCollapseText; - - private Text mTextView; - - public TextViewExpandController(int expandText, int collapseText) { - mExpandText = expandText; - mCollapseText = collapseText; - } - - @Override - public void changeState(boolean collapsed) { - mTextView.setText(collapsed ? mExpandText : mCollapseText); - } - - @Override - public void setView(Component toggleView) { - mTextView = (Text) toggleView; - } - } - - private static PixelMap getPixelMap(int resId, Context context) { - InputStream drawableInputStream = null; - try { - drawableInputStream = context.getResourceManager().getResource(resId); - ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions(); - sourceOptions.formatHint = "image/png"; - ImageSource imageSource = ImageSource.create(drawableInputStream, null); - ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions(); - decodingOptions.desiredSize = new Size(0, 0); - decodingOptions.desiredRegion = new Rect(0, 0, 0, 0); - decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888; - PixelMap pixelMap = imageSource.createPixelmap(decodingOptions); - return pixelMap; - } catch (Exception e) { - HiLog.debug(logLabel, "getPixelMap" + e.getMessage()); - } finally { - try { - if (drawableInputStream != null) { - drawableInputStream.close(); - } - } catch (Exception e) { - HiLog.debug(logLabel, "getPixelMap" + e.getMessage()); - } - } - return null; - } - - private static ExpandIndicatorController setupExpandToggleController(Context context, AttrSet attrSet) { - final int expandToggleType = TypedAttrUtils.getInteger(attrSet, "expandToggleType", DEFAULT_TOGGLE_TYPE); - final ExpandIndicatorController expandIndicatorController; - switch (expandToggleType) { - case EXPAND_INDICATOR_IMAGE_BUTTON: - PixelMap expandDrawable = null; - PixelMap collapseDrawable = null; - boolean expandPresent = attrSet.getAttr("expandIndicator").isPresent(); - if (expandPresent) { - expandDrawable = ((PixelMapElement) (attrSet.getAttr("expandIndicator").get().getElement())).getPixelMap(); - } - boolean collapsePresent = attrSet.getAttr("collapseIndicator").isPresent(); - if (collapsePresent) { - collapseDrawable = ((PixelMapElement) (attrSet.getAttr("collapseIndicator").get().getElement())).getPixelMap(); - } - if (expandDrawable == null) { - expandDrawable = getPixelMap(ResourceTable.Media_ic_expand_more_black_12dp, context); - } - if (collapseDrawable == null) { - collapseDrawable = getPixelMap(ResourceTable.Media_ic_expand_less_black_12dp, context); - } - expandIndicatorController = new ImageButtonExpandController(expandDrawable, collapseDrawable); - break; - case EXPAND_INDICATOR_TEXT_VIEW: - expandIndicatorController = new TextViewExpandController(ResourceTable.String_expand_more, ResourceTable.String_expand_less); - break; - default: - throw new IllegalStateException("Must be of enum: ExpandableTextView_expandToggleType, one of EXPAND_INDICATOR_IMAGE_BUTTON or EXPAND_INDICATOR_TEXT_VIEW."); - } - - return expandIndicatorController; - } - - /** - * 设置文案 - * - * @param text 文案内容 - */ - public void setText(String text) { - mRelayout = true; - findViews(); - expandText.setText(text); - setVisibility(null == text ? Component.HIDE : Component.VISIBLE); - postLayout(); - } -} diff --git a/lib/src/main/java/com/ms/square/ohos/expandabletextview/TypedAttrUtils.java b/lib/src/main/java/com/ms/square/ohos/expandabletextview/TypedAttrUtils.java deleted file mode 100644 index cee3abc..0000000 --- a/lib/src/main/java/com/ms/square/ohos/expandabletextview/TypedAttrUtils.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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.ms.square.ohos.expandabletextview; - - -import ohos.agp.components.Attr; -import ohos.agp.components.AttrSet; -import ohos.agp.utils.Color; -import ohos.hiviewdfx.HiLog; -import ohos.hiviewdfx.HiLogLabel; - -import java.util.NoSuchElementException; - -/** - * author zhaoxudong - * Version 1.0 - * ModifiedBy - * date 2021-02-22 10:12 - * description 工具类 - */ -public final class TypedAttrUtils { - static final HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, "jiangbenfu"); - - 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(); - } - } - - public static Color getColor(AttrSet attrs, String attrName, Color defValue) { - Attr attr = attrNoSuchElement(attrs, attrName); - if (attr == null) { - return defValue; - } else { - return attr.getColorValue(); - } - } - - public static boolean getBoolean(AttrSet attrs, String attrName, boolean defValue) { - Attr attr = attrNoSuchElement(attrs, attrName); - if (attr == null) { - return defValue; - } else { - return attr.getBoolValue(); - } - } - - - public static int getInteger(AttrSet attrs, String attrName, int defValue) { - Attr attr = attrNoSuchElement(attrs, attrName); - if (attr == null) { - return defValue; - } else { - return attr.getIntegerValue(); - } - } - - public static float getFloat(AttrSet attrs, String attrName, float defValue) { - Attr attr = attrNoSuchElement(attrs, attrName); - if (attr == null) { - return defValue; - } else { - return attr.getFloatValue(); - } - } - - public static String getString(AttrSet attrs, String attrName, String defValue) { - Attr attr = attrNoSuchElement(attrs, attrName); - if (attr == null) { - return defValue; - } else { - return attr.getStringValue(); - } - } - - public static int getDimensionPixelSize(AttrSet attrs, String attrName, int defValue) { - Attr attr = attrNoSuchElement(attrs, attrName); - if (attr == null) { - return defValue; - } else { - return attr.getIntegerValue(); - } - } - - public static int getLayoutDimension(AttrSet attrs, String attrName, int defValue) { - Attr attr = attrNoSuchElement(attrs, attrName); - if (attr == null) { - return defValue; - } else { - 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; - } -} -- Gitee From 132a0fc1fff1001f723e75b5bfeb4d2538ab7e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9C=E5=85=B5=E5=85=B5?= Date: Wed, 2 Jun 2021 15:50:06 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expandabletext/sample/MainAbility.java | 33 ++ .../expandabletext/sample/MyApplication.java | 24 + .../sample/provider/ListProvider.java | 69 +++ .../provider/MainPagerSlideProvider.java | 64 +++ .../sample/provider/ViewHolder.java | 54 ++ .../sample/slice/MainAbilitySlice.java | 159 +++++ .../expandabletext/sample/utils/MyToast.java | 99 ++++ .../sample/utils/ViewCreateHelper.java | 171 ++++++ .../hos/expandabletext/ExampleOhosTest.java | 17 + .../ohos/expandabletext/ExpandableText.java | 544 ++++++++++++++++++ .../ohos/expandabletext/TypedAttrUtils.java | 118 ++++ 11 files changed, 1352 insertions(+) create mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletext/sample/MainAbility.java create mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletext/sample/MyApplication.java create mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/ListProvider.java create mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/MainPagerSlideProvider.java create mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/ViewHolder.java create mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletext/sample/slice/MainAbilitySlice.java create mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletext/sample/utils/MyToast.java create mode 100644 entry/src/main/java/com/ms/square/ohos/expandabletext/sample/utils/ViewCreateHelper.java create mode 100644 entry/src/ohosTest/java/com/hos/expandabletext/ExampleOhosTest.java create mode 100644 lib/src/main/java/com/ms/square/ohos/expandabletext/ExpandableText.java create mode 100644 lib/src/main/java/com/ms/square/ohos/expandabletext/TypedAttrUtils.java diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/MainAbility.java b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/MainAbility.java new file mode 100644 index 0000000..8dd9754 --- /dev/null +++ b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/MainAbility.java @@ -0,0 +1,33 @@ +/* + * 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.ms.square.ohos.expandabletext.sample; + +import com.ms.square.ohos.expandabletext.sample.slice.MainAbilitySlice; +import ohos.aafwk.ability.Ability; +import ohos.aafwk.content.Intent; +import ohos.agp.components.ComponentContainer; + +public class MainAbility extends Ability { + @Override + public void onStart(Intent intent) { + super.onStart(intent); + super.setMainRoute(MainAbilitySlice.class.getName()); + } + + @Override + public void setUIContent(ComponentContainer componentContainer) { + super.setUIContent(componentContainer); + } +} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/MyApplication.java b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/MyApplication.java new file mode 100644 index 0000000..446fead --- /dev/null +++ b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/MyApplication.java @@ -0,0 +1,24 @@ +/* + * 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.ms.square.ohos.expandabletext.sample; + +import ohos.aafwk.ability.AbilityPackage; + +public class MyApplication extends AbilityPackage { + @Override + public void onInitialize() { + super.onInitialize(); + } +} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/ListProvider.java b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/ListProvider.java new file mode 100644 index 0000000..9ab9998 --- /dev/null +++ b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/ListProvider.java @@ -0,0 +1,69 @@ +/* + * 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.ms.square.ohos.expandabletext.sample.provider; + +import ohos.agp.components.BaseItemProvider; +import ohos.agp.components.Component; +import ohos.agp.components.ComponentContainer; +import ohos.agp.components.LayoutScatter; +import ohos.app.Context; + +import java.util.List; + +/** + * author zhaoxudong + * Version 1.0 + * ModifiedBy + * date 2021-03-15 10:13 + * description 列表数据适配器 + */ +public abstract class ListProvider extends BaseItemProvider { + private List data; + private Context ct; + private int itemId; + + public ListProvider(Context ct, int itemId, List data) { + this.data = data; + this.ct = ct; + this.itemId = itemId; + } + + public abstract void convert(ViewHolder viewHolder, T item, int position); + + @Override + public int getCount() { + return data == null ? 0 : data.size(); + } + + @Override + public T getItem(int i) { + return data.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public Component getComponent(int i, Component component, ComponentContainer componentContainer) { + ViewHolder viewHolder; + Component itemView = LayoutScatter.getInstance(ct).parse(itemId, componentContainer, false); + viewHolder = new ViewHolder(ct, itemView, componentContainer, i); + convert(viewHolder, getItem(i), i); + return itemView; + } +} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/MainPagerSlideProvider.java b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/MainPagerSlideProvider.java new file mode 100644 index 0000000..b5ac246 --- /dev/null +++ b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/MainPagerSlideProvider.java @@ -0,0 +1,64 @@ +/* + * 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.ms.square.ohos.expandabletext.sample.provider; + +import ohos.agp.components.Component; +import ohos.agp.components.ComponentContainer; +import ohos.agp.components.PageSliderProvider; + +import java.util.ArrayList; +import java.util.List; + +/** + * author zhaoxudong + * Version 1.0 + * ModifiedBy + * date 2021-03-15 10:13 + * description PageSlider适配器 + */ +public class MainPagerSlideProvider extends PageSliderProvider { + private List pages; + + /** + * 构造函数 + * + * @param pages 页面 + */ + public MainPagerSlideProvider(ArrayList pages) { + this.pages = pages; + } + + @Override + public int getCount() { + return pages == null ? 0 : pages.size(); + } + + @Override + public Object createPageInContainer(ComponentContainer componentContainer, int i) { + componentContainer.addComponent(pages.get(i)); + return componentContainer; + } + + @Override + public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) { + componentContainer.removeComponent(pages.get(i)); + } + + @Override + public boolean isPageMatchToObject(Component component, Object object) { + return component == object; + } +} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/ViewHolder.java b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/ViewHolder.java new file mode 100644 index 0000000..de207f2 --- /dev/null +++ b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/provider/ViewHolder.java @@ -0,0 +1,54 @@ +/* + * 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.ms.square.ohos.expandabletext.sample.provider; + +import ohos.agp.components.Component; +import ohos.agp.components.ComponentContainer; +import ohos.app.Context; + +import java.util.HashMap; + +/** + * author zhaoxudong + * Version 1.0 + * ModifiedBy + * date 2021-03-15 10:13 + * description ViewHolder + */ +public class ViewHolder { + int position; + int layoutId; + private Component component; + private Context context; + private HashMap views; + + ViewHolder(Context context, Component itemView, ComponentContainer parent, int position) { + this.context = context; + this.component = itemView; + this.position = position; + views = new HashMap<>(0); + component.setTag(this); + } + + @SuppressWarnings("unchecked") + public T getView(int viewId) { + Component view = views.get(viewId); + if (view == null) { + view = component.findComponentById(viewId); + views.put(viewId, view); + } + return (T) view; + } +} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/slice/MainAbilitySlice.java b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/slice/MainAbilitySlice.java new file mode 100644 index 0000000..0610185 --- /dev/null +++ b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/slice/MainAbilitySlice.java @@ -0,0 +1,159 @@ +/* + * 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.ms.square.ohos.expandabletext.sample.slice; + +import com.ms.square.ohos.expandabletext.sample.ResourceTable; +import com.ms.square.ohos.expandabletext.sample.provider.MainPagerSlideProvider; +import com.ms.square.ohos.expandabletext.sample.utils.ViewCreateHelper; +import ohos.aafwk.ability.AbilitySlice; +import ohos.aafwk.content.Intent; +import ohos.agp.colors.RgbColor; +import ohos.agp.components.Component; +import ohos.agp.components.DirectionalLayout; +import ohos.agp.components.PageSlider; +import ohos.agp.components.TabList; +import ohos.agp.components.element.ShapeElement; +import ohos.agp.window.service.WindowManager; +import ohos.global.resource.NotExistException; +import ohos.global.resource.WrongTypeException; +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogLabel; + +import java.io.IOException; +import java.util.ArrayList; + +/** + * author zhaoxudong + * Version 1.0 + * ModifiedBy + * date 2021-03-15 10:13 + * description 主界面 + */ +public class MainAbilitySlice extends AbilitySlice implements TabList.TabSelectedListener, + PageSlider.PageChangedListener { + private static final HiLogLabel HI_LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0xFFFFF, "MainAbilitySlice"); + private static final int GRAY_COLOR = 211; + private static final int WHITE_COLOR = 0; + private TabList tabList; + private PageSlider pageSlider; + private DirectionalLayout rootLayout; + + @Override + public void onStart(Intent intent) { + // 设置状态栏颜色 + WindowManager.getInstance().getTopWindow().get().setStatusBarColor(getColor(ResourceTable.Color_purple_700)); + super.onStart(intent); + super.setUIContent(ResourceTable.Layout_ability_main); + initView(); + initData(); + } + + private void initView() { + tabList = (TabList) findComponentById(ResourceTable.Id_tab_list); + pageSlider = (PageSlider) findComponentById(ResourceTable.Id_pager); + tabList.addTabSelectedListener(this); + pageSlider.addPageChangedListener(this); + tabList.setFixedMode(true); + rootLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_root); + } + + /** + * 设置tabList + */ + private void initData() { + try { + String[] tabsTitle = getResourceManager().getElement(ResourceTable.Strarray_tab_title).getStringArray(); + for (String title : tabsTitle) { + TabList.Tab tab = tabList.new Tab(getContext()); + tab.setText(title); + ShapeElement shapeElement = new ShapeElement(); + shapeElement.setRgbColor(new RgbColor(0, 0, 0, 0)); + tab.setBackground(shapeElement); + tabList.addTab(tab); + } + tabList.selectTabAt(0); + pageSlider.setProvider(new MainPagerSlideProvider(initPageSliderViewData())); + pageSlider.setCurrentPage(0); + pageSlider.setReboundEffect(true); + pageSlider.setCentralScrollMode(true); + } catch (IOException | NotExistException | WrongTypeException e) { + HiLog.debug(HI_LOG_LABEL, e.getMessage()); + } + } + + private ArrayList initPageSliderViewData() { + ArrayList pages = new ArrayList<>(); + int pageSize = tabList.getTabCount(); + if (tabList == null || pageSize < 1) { + HiLog.debug(HI_LOG_LABEL, "initPageSliderViewData tabList is null"); + return pages; + } + ViewCreateHelper viewCreateHelper = new ViewCreateHelper(getContext()); + for (int tabIndex = 0; tabIndex < pageSize; tabIndex++) { + pages.add(viewCreateHelper.createView(tabList.getTabAt(tabIndex).getText(), tabIndex)); + } + return pages; + } + + @Override + public void onActive() { + super.onActive(); + } + + @Override + public void onForeground(Intent intent) { + super.onForeground(intent); + } + + @Override + public void onPageSliding(int i, float v, int i1) { + } + + @Override + public void onPageSlideStateChanged(int i) { + } + + @Override + public void onPageChosen(int i) { + if (tabList.getSelectedTab().getPosition() != i) { + tabList.selectTabAt(i); + } + if (i == 0) { + ShapeElement shapeElement = new ShapeElement(); + shapeElement.setRgbColor(new RgbColor(GRAY_COLOR, GRAY_COLOR, GRAY_COLOR, GRAY_COLOR)); + rootLayout.setBackground(shapeElement); + } else { + ShapeElement shapeElement = new ShapeElement(); + shapeElement.setRgbColor(new RgbColor(WHITE_COLOR, WHITE_COLOR, WHITE_COLOR, WHITE_COLOR)); + rootLayout.setBackground(shapeElement); + } + } + + @Override + public void onSelected(TabList.Tab tab) { + if (pageSlider.getCurrentPage() != tab.getPosition()) { + pageSlider.setCurrentPage(tab.getPosition()); + } + } + + @Override + public void onUnselected(TabList.Tab tab) { + } + + @Override + public void onReselected(TabList.Tab tab) { + } +} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/utils/MyToast.java b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/utils/MyToast.java new file mode 100644 index 0000000..859bc92 --- /dev/null +++ b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/utils/MyToast.java @@ -0,0 +1,99 @@ +/* + * 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.ms.square.ohos.expandabletext.sample.utils; + +import ohos.agp.colors.RgbColor; +import ohos.agp.components.DirectionalLayout; +import ohos.agp.components.Text; +import ohos.agp.components.element.ShapeElement; +import ohos.agp.utils.Color; +import ohos.agp.utils.LayoutAlignment; +import ohos.agp.window.dialog.ToastDialog; +import ohos.agp.window.service.DisplayAttributes; +import ohos.agp.window.service.DisplayManager; +import ohos.app.Context; + +/** + * author zhaoxudong + * Version 1.0 + * ModifiedBy + * date 2021-03-05 14:46 + * description 自定义Toast + */ +public class MyToast { + public static final int LENGTH_SHORT = 2000; + private static ToastDialog toastDialog; + + public enum ToastLayout { + CENTER, + TOP, + BOTTOM, + } + + public static void show(Context mContext, String content, ToastLayout layout) { + createTost(mContext, content, LENGTH_SHORT, layout); + } + + private static void createTost(Context mContext, String content, int duration, ToastLayout layout) { + DirectionalLayout toastLayout = new DirectionalLayout(mContext); + DirectionalLayout.LayoutConfig textConfig = new DirectionalLayout.LayoutConfig(DirectionalLayout.LayoutConfig.MATCH_CONTENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT); + Text text = new Text(mContext); + text.setText(content); + text.setTextColor(new Color(Color.getIntColor("#ffffff"))); + text.setPadding(vp2px(mContext, 16), vp2px(mContext, 10), vp2px(mContext, 16), vp2px(mContext, 10)); + text.setTextSize(vp2px(mContext, 12)); + text.setBackground(buildDrawableByColorRadius(Color.getIntColor("#70000000"), vp2px(mContext, 20))); + text.setLayoutConfig(textConfig); + text.setMarginBottom(20); + toastLayout.addComponent(text); + int mLayout = LayoutAlignment.CENTER; + switch (layout) { + case TOP: + mLayout = LayoutAlignment.TOP; + break; + case BOTTOM: + mLayout = LayoutAlignment.BOTTOM; + break; + case CENTER: + mLayout = LayoutAlignment.CENTER; + break; + } + if (toastDialog != null) { + toastDialog.cancel(); + toastDialog = null; + } + toastDialog = new ToastDialog(mContext); + toastDialog.setComponent(toastLayout); + toastDialog.setSize(DirectionalLayout.LayoutConfig.MATCH_CONTENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT); + toastDialog.setAlignment(mLayout); + toastDialog.setTransparent(true); + toastDialog.setDuration(duration); + toastDialog.show(); + } + + + private static ohos.agp.components.element.Element buildDrawableByColorRadius(int color, float radius) { + ShapeElement drawable = new ShapeElement(); + drawable.setShape(0); + drawable.setRgbColor(RgbColor.fromArgbInt(color)); + drawable.setCornerRadius(radius); + return drawable; + } + + private static int vp2px(Context context, float vp) { + DisplayAttributes attributes = DisplayManager.getInstance().getDefaultDisplay(context).get().getAttributes(); + return (int) (attributes.densityPixels * vp); + } +} diff --git a/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/utils/ViewCreateHelper.java b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/utils/ViewCreateHelper.java new file mode 100644 index 0000000..8a0ec4b --- /dev/null +++ b/entry/src/main/java/com/ms/square/ohos/expandabletext/sample/utils/ViewCreateHelper.java @@ -0,0 +1,171 @@ +/* + * 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.ms.square.ohos.expandabletext.sample.utils; + +import com.ms.square.ohos.expandabletext.ExpandableText; +import com.ms.square.ohos.expandabletext.sample.ResourceTable; +import com.ms.square.ohos.expandabletext.sample.provider.ListProvider; +import com.ms.square.ohos.expandabletext.sample.provider.ViewHolder; +import ohos.agp.components.*; +import ohos.agp.render.Paint; +import ohos.app.Context; +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogLabel; + +import java.util.ArrayList; +import java.util.List; + +/** + * author zhaoxudong + * Version 1.0 + * ModifiedBy + * date 2021-03-15 10:13 + * description ViewCreateHelper + */ +public final class ViewCreateHelper { + private static final HiLogLabel HI_LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0xFFFFF, "ViewCreateHelper"); + /** + * 列表长度 + */ + private static final int ITEM_LEN = 10; + private static final int MAX_COLLAPSED_LINES = 4; + private static final int DEFAULT = 2; + private Context slice; + + /** + * 构造函数 + * + * @param abilitySlice Context + */ + public ViewCreateHelper(Context abilitySlice) { + slice = abilitySlice; + } + + /** + * 创建view + * + * @param title 标题 + * @param position 位置 + * @return Component + */ + public Component createView(String title, int position) { + HiLog.debug(HI_LOG_LABEL, "createView position =" + position); + Component mainComponent; + if (position == 0) { + mainComponent = + LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_pager_srcoll_item, null, false); + if (!(mainComponent instanceof ComponentContainer)) { + return mainComponent; + } + ScrollView scrollView = (ScrollView) mainComponent.findComponentById(ResourceTable.Id_scroll); + scrollView.enableScrollBar(1, true); + ComponentContainer rootLayout = (ComponentContainer) mainComponent; + DirectionalLayout root = (DirectionalLayout) rootLayout.findComponentById(ResourceTable.Id_root); + int itemCount = root.getChildCount(); + if (root != null && itemCount > 0) { + for (int index = 0; index < itemCount; index++) { + Component component = root.getComponentAt(index); + Text titleText = (Text) component.findComponentById(ResourceTable.Id_title); + titleText.setText("Sample " + (index + 1)); + ExpandableText expandableText = (ExpandableText) + component.findComponentById(ResourceTable.Id_expandable); + expandableText.setText(slice.getString(ResourceTable.String_dummy_text2)); + expandableText.setOnExpandStateChangeListener(new ExpandableText.OnExpandStateChangeListener() { + @Override + public void onExpandStateChanged(Text textView) { + + } + + @Override + public void expandStateChangedToast(boolean isExpanded) { + MyToast.show(slice, isExpanded ? "Expanded" : "Collapsed", MyToast.ToastLayout.BOTTOM); + } + }); + } + } + return rootLayout; + } else { + mainComponent = + LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_pager_item, null, false); + if (!(mainComponent instanceof ComponentContainer)) { + return mainComponent; + } + ComponentContainer rootLayout = (ComponentContainer) mainComponent; + initView(mainComponent, title); + return rootLayout; + } + } + + private int getFontHeight(int fontSize) { + Paint paint = new Paint(); + paint.setTextSize(fontSize); + Paint.FontMetrics fm = paint.getFontMetrics(); + return (int) (Math.ceil(fm.descent - fm.top) + DEFAULT) * MAX_COLLAPSED_LINES; + } + + ListProvider listProvider = null; + + private void initView(Component mainComponent, String title) { + // 列表 + ListContainer listContainer = (ListContainer) mainComponent.findComponentById(ResourceTable.Id_list_main); + listContainer.enableScrollBar(1, true); + listProvider = new ListProvider(slice, ResourceTable.Layout_text_item, getData()) { + @Override + public void convert(ViewHolder viewHolder, String item, int position) { + Text text = viewHolder.getView(ResourceTable.Id_expandable_text); + text.setTag(position + ""); + text.setHeight(getFontHeight(text.getTextSize())); + ExpandableText expandableText = viewHolder.getView(ResourceTable.Id_expandable); + expandableText.setText(slice.getString(ResourceTable.String_dummy_text2)); + expandableText.setOnExpandStateChangeListener(new ExpandableText.OnExpandStateChangeListener() { + @Override + public void onExpandStateChanged(Text textView) { + int position = Integer.valueOf(textView.getTag().toString()).intValue(); + listProvider.notifyDataSetItemChanged(position + 1); + } + + @Override + public void expandStateChangedToast(boolean isExpanded) { + MyToast.show(slice, isExpanded ? "Expanded" : "Collapsed", MyToast.ToastLayout.BOTTOM); + } + }); + } + }; + listContainer.setLayoutRefreshedListener(new Component.LayoutRefreshedListener() { + @Override + public void onRefreshed(Component component) { + if (listContainer.getHeight() < ((ComponentContainer) (component.getComponentParent())).getHeight()) { + listContainer.setEnabled(false); + } else { + listContainer.setEnabled(true); + } + } + }); + listContainer.setItemProvider(listProvider); + listContainer.setItemClickedListener(new ListContainer.ItemClickedListener() { + @Override + public void onItemClicked(ListContainer listContainer, Component component, int position, long l) { + } + }); + } + + private List getData() { + List curData = new ArrayList<>(); + for (int index = 0; index < ITEM_LEN; index++) { + curData.add("测试"); + } + return curData; + } +} diff --git a/entry/src/ohosTest/java/com/hos/expandabletext/ExampleOhosTest.java b/entry/src/ohosTest/java/com/hos/expandabletext/ExampleOhosTest.java new file mode 100644 index 0000000..73a6de7 --- /dev/null +++ b/entry/src/ohosTest/java/com/hos/expandabletext/ExampleOhosTest.java @@ -0,0 +1,17 @@ +package com.hos.expandabletext; + +import ohos.aafwk.ability.delegation.AbilityDelegatorRegistry; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ExampleOhosTest { + /** + * 全UI应用、不支持Context,不支持单元测试 + */ + @Test + public void testBundleName() { + final String actualBundleName = AbilityDelegatorRegistry.getArguments().getTestBundleName(); + assertEquals("com.hos.expandabletext", actualBundleName); + } +} \ No newline at end of file diff --git a/lib/src/main/java/com/ms/square/ohos/expandabletext/ExpandableText.java b/lib/src/main/java/com/ms/square/ohos/expandabletext/ExpandableText.java new file mode 100644 index 0000000..bed6ef1 --- /dev/null +++ b/lib/src/main/java/com/ms/square/ohos/expandabletext/ExpandableText.java @@ -0,0 +1,544 @@ +/* + * Copyright (C) 2011 The Open Source Project + * Copyright 2014 Manabu Shimobe + * + * 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.ms.square.ohos.expandabletext; + +import com.ms.square.ohos.expandabletextview.ResourceTable; +import ohos.agp.animation.Animator; +import ohos.agp.animation.AnimatorValue; +import ohos.agp.components.*; +import ohos.agp.components.element.PixelMapElement; +import ohos.agp.render.Canvas; +import ohos.agp.render.Paint; +import ohos.app.Context; +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogLabel; +import ohos.media.image.ImageSource; +import ohos.media.image.PixelMap; +import ohos.media.image.common.PixelFormat; +import ohos.media.image.common.Rect; +import ohos.media.image.common.Size; + +import java.io.InputStream; +import java.util.Map; + +/** + * author zhaoxudong + * Version 1.0 + * ModifiedBy + * date 2021-02-22 10:12 + * description 可折叠的TextView + */ +public class ExpandableText extends DirectionalLayout implements + Component.EstimateSizeListener, Component.ClickedListener, ComponentContainer.ArrangeListener { + private static final HiLogLabel logLabel = new HiLogLabel(HiLog.LOG_APP, 0x00101, "ExpandableTextView"); + + private static final int EXPAND_INDICATOR_IMAGE_BUTTON = 0; + + private static final int EXPAND_INDICATOR_TEXT_VIEW = 1; + + private static final int DEFAULT_TOGGLE_TYPE = EXPAND_INDICATOR_IMAGE_BUTTON; + + /* The default number of lines */ + private static final int MAX_COLLAPSED_LINES = 4; + + /* The default animation duration */ + private static final int DEFAULT_ANIM_DURATION = 300; + + /* The default alpha value when the animation starts */ + private static final float DEFAULT_ANIM_ALPHA_START = 0.7f; + + private boolean mRelayout = true; + + // Show short version as default. + private boolean mCollapsed = true; + + private int mCollapsedHeight; + + private int mTextHeightWithMaxLines; + private int singleTextHeight; + /** + * 内容展示Text + */ + private Text expandText; + + /** + * 展开,收缩图标 + * View to expand/collapse + */ + private Component expandCollapse; + + /** + * 最大展示行数 + */ + private int maxCollapsedLines; + + private int mMarginBetweenTxtAndBottom; + + /** + * 文本是否可以被点击 + */ + private boolean expandToggleOnTextClick; + + + private ExpandIndicatorController mExpandIndicatorController; + + /** + * 动画展示时长 + */ + private int animationDuration; + + /** + * 起始透明度 + */ + private float animAlphaStart = 0.7f; + + private OnExpandStateChangeListener mListener; + + /** + * 收缩状态 + */ + private Map collapsedStatus; + + private int mPosition; + private int mStartHeight; + private int expendTextHeight; + private Context context; + + /** + * 构造函数 + * + * @param context Context + */ + public ExpandableText(Context context) { + this(context, null); + } + + /** + * 构造函数 + * + * @param context Context + * @param attrSet AttrSet + */ + public ExpandableText(Context context, AttrSet attrSet) { + super(context, attrSet); + this.context = context; + init(attrSet); + } + + /** + * 构造函数 + * + * @param context Context + * @param attrSet AttrSet + * @param styleName styleName + */ + public ExpandableText(Context context, AttrSet attrSet, String styleName) { + super(context, attrSet, styleName); + init(attrSet); + } + + /** + * 设置布局方向(只支持竖向) + * + * @param orientation 布局方向 + */ + @Override + public void setOrientation(int orientation) { + if (Component.HORIZONTAL == orientation) { + throw new IllegalArgumentException("ExpandableTextView only supports Vertical Orientation."); + } + super.setOrientation(orientation); + } + + AnimatorValue animation = new AnimatorValue(); + + @Override + public void onClick(Component component) { + if (animation.isRunning()) { + return; + } + if (expandCollapse.getVisibility() != Component.VISIBLE) { + return; + } + + mCollapsed = !mCollapsed; + mExpandIndicatorController.changeState(mCollapsed); + + // 记录伸缩状态 + if (collapsedStatus != null) { + collapsedStatus.put(mPosition, mCollapsed); + } + + if (mStartHeight == 0) { + mStartHeight = getHeight(); + expendTextHeight = expandText.getHeight(); + expandText.setHeight(expendTextHeight); + expandText.setMaxTextLines(Integer.MAX_VALUE); + } + + // 动效 + animation.setDuration(animationDuration); + animation.setStateChangedListener(new Animator.StateChangedListener() { + @Override + public void onStart(Animator animator) { + applyAlphaAnimation(expandText, animAlphaStart); + } + + @Override + public void onStop(Animator animator) { + + } + + @Override + public void onCancel(Animator animator) { + + } + + @Override + public void onEnd(Animator animator) { + // notify the listener + mListener.expandStateChangedToast(!mCollapsed); + } + + @Override + public void onPause(Animator animator) { + + } + + @Override + public void onResume(Animator animator) { + + } + }); + animation.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() { + + @Override + public void onUpdate(AnimatorValue animatorValue, float interpolatedTime) { + final int newHeight; + if (mCollapsed) { + newHeight = (int) ((mCollapsedHeight - getHeight()) * interpolatedTime + getHeight()); + } else { + int mEndHeight = mStartHeight + singleTextHeight * 7 - expendTextHeight; + newHeight = (int) ((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight); + } + expandText.setHeight(newHeight - mMarginBetweenTxtAndBottom); + if (Float.compare(animAlphaStart, 1.0f) != 0) { + applyAlphaAnimation(expandText, animAlphaStart + interpolatedTime * (1.0f - animAlphaStart)); + } + + getContext().getUITaskDispatcher().delayDispatch(new Runnable() { + @Override + public void run() { + if (mListener != null) { + mListener.onExpandStateChanged(expandText); + } + } + }, 10); + } + }); + + animation.start(); + } + + @Override + public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) { + HiLog.debug(logLabel, "onEstimateSize"); + singleTextHeight = getFontHeight(expandText.getTextSize()); + // If no change, measure and return + if (!mRelayout || getVisibility() == Component.HIDE) { + return false; + } + mRelayout = false; + + // Setup with optimistic case + // i.e. Everything fits. No button needed + expandCollapse.setVisibility(Component.HIDE); + expandText.setMaxTextLines(Integer.MAX_VALUE); + + // Measure + super.estimateSize(widthEstimateConfig, heightEstimateConfig); + // If the text fits in collapsed mode, we are done. + if (expandText.getMaxTextLines() <= maxCollapsedLines) { + return false; + } + // Saves the text height w/ max lines + mTextHeightWithMaxLines = getRealTextViewHeight(expandText); + // Doesn't fit in collapsed mode. Collapse text view as needed. Show + // button. + if (mCollapsed) { + expandText.setMaxTextLines(maxCollapsedLines); + } + expandCollapse.setVisibility(Component.VISIBLE); + + // Re-measure with new setup + super.estimateSize(widthEstimateConfig, heightEstimateConfig); + + if (mCollapsed) { + mMarginBetweenTxtAndBottom = getHeight() - expandText.getHeight(); + // Saves the collapsed height of this ViewGroup + mCollapsedHeight = getEstimatedHeight(); + } + return false; + } + + + /** + * 获取一行的字体高度 + * + * @param fontSize 字体大小 + * @return 行高 + */ + private int getFontHeight(int fontSize) { + Paint paint = new Paint(); + paint.setTextSize(fontSize); + Paint.FontMetrics fm = paint.getFontMetrics(); + return (int) Math.ceil(fm.descent - fm.top) + 2; + } + + private void init(AttrSet attrs) { + initAttrs(attrs); + // enforces vertical orientation + setOrientation(Component.VERTICAL); + //add绘制的回调 + addDrawTask(mDrawTask); + + } + + private int getRealTextViewHeight(Text textView) { + int textHeight = textView.getHeight(); + int padding = textView.getPaddingTop() + textView.getPaddingBottom(); + return textHeight + padding; + } + + //绘制的回调 + final private DrawTask mDrawTask = new DrawTask() { + @Override + public void onDraw(Component component, Canvas canvas) { + //add测量的回调 + setEstimateSizeListener(ExpandableText.this); + //add布局的回调 + setArrangeListener(ExpandableText.this); + findViews(); + + } + }; + + + /** + * 初始化属性 + * + * @param attrSet 属性 + */ + private void initAttrs(AttrSet attrSet) { + maxCollapsedLines = TypedAttrUtils.getInteger(attrSet, "maxCollapsedLines", MAX_COLLAPSED_LINES); + animationDuration = TypedAttrUtils.getInteger(attrSet, "animDuration", DEFAULT_ANIM_DURATION); + animAlphaStart = TypedAttrUtils.getFloat(attrSet, "animAlphaStart", DEFAULT_ANIM_ALPHA_START); + expandToggleOnTextClick = TypedAttrUtils.getBoolean(attrSet, "expandToggleOnTextClick", true); + mExpandIndicatorController = setupExpandToggleController(getContext(), attrSet); + } + + private void findViews() { + int count = getChildCount(); + if (count < 1) { + return; + } + for (int i = 0; i < count; i++) { + Component component = getComponentAt(i); + if (component.getComponentDescription().toString().equals("expandable_text")) { + expandText = (Text) component; + } else if (component.getComponentDescription().toString().equals("expand_collapse")) { + expandCollapse = component; + } + } + if (expandToggleOnTextClick) { + expandText.setClickedListener(this); + } else { + expandText.setClickedListener(null); + } + expandCollapse.setClickedListener(this); + mExpandIndicatorController.setView(expandCollapse); + mExpandIndicatorController.changeState(mCollapsed); + + // enforces vertical orientation + setOrientation(Component.VERTICAL); + } + + /** + * 设置监听 + * + * @param listener 监听器 + */ + public void setOnExpandStateChangeListener(OnExpandStateChangeListener listener) { + mListener = listener; + } + + @Override + public boolean onArrange(int i, int i1, int i2, int i3) { + return false; + } + + public interface OnExpandStateChangeListener { + /** + * Called when the expand/collapse animation has been finished + * + * @param textView - TextView being expanded/collapsed + */ + void onExpandStateChanged(Text textView); + + /** + * 状态改变时的提示语 + * + * @param isExpanded 是否是展开状态 + */ + void expandStateChangedToast(boolean isExpanded); + } + + interface ExpandIndicatorController { + void changeState(boolean collapsed); + + void setView(Component toggleView); + } + + private static void applyAlphaAnimation(Component view, float alpha) { + view.setAlpha(alpha); + } + + /** + * Image图标控制器 + */ + private static class ImageButtonExpandController implements ExpandIndicatorController { + + private final PixelMap mExpandDrawable; + private final PixelMap mCollapseDrawable; + + private Image mImageButton; + + public ImageButtonExpandController(PixelMap expandDrawable, PixelMap collapseDrawable) { + mExpandDrawable = expandDrawable; + mCollapseDrawable = collapseDrawable; + } + + @Override + public void changeState(boolean collapsed) { + mImageButton.setPixelMap(collapsed ? mExpandDrawable : mCollapseDrawable); + } + + @Override + public void setView(Component toggleView) { + mImageButton = (Image) toggleView; + } + } + + /** + * Text图标控制器 + */ + static class TextViewExpandController implements ExpandIndicatorController { + + private final int mExpandText; + private final int mCollapseText; + + private Text mTextView; + + public TextViewExpandController(int expandText, int collapseText) { + mExpandText = expandText; + mCollapseText = collapseText; + } + + @Override + public void changeState(boolean collapsed) { + mTextView.setText(collapsed ? mExpandText : mCollapseText); + } + + @Override + public void setView(Component toggleView) { + mTextView = (Text) toggleView; + } + } + + private static PixelMap getPixelMap(int resId, Context context) { + InputStream drawableInputStream = null; + try { + drawableInputStream = context.getResourceManager().getResource(resId); + ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions(); + sourceOptions.formatHint = "image/png"; + ImageSource imageSource = ImageSource.create(drawableInputStream, null); + ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions(); + decodingOptions.desiredSize = new Size(0, 0); + decodingOptions.desiredRegion = new Rect(0, 0, 0, 0); + decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888; + PixelMap pixelMap = imageSource.createPixelmap(decodingOptions); + return pixelMap; + } catch (Exception e) { + HiLog.debug(logLabel, "getPixelMap" + e.getMessage()); + } finally { + try { + if (drawableInputStream != null) { + drawableInputStream.close(); + } + } catch (Exception e) { + HiLog.debug(logLabel, "getPixelMap" + e.getMessage()); + } + } + return null; + } + + private static ExpandIndicatorController setupExpandToggleController(Context context, AttrSet attrSet) { + final int expandToggleType = TypedAttrUtils.getInteger(attrSet, "expandToggleType", DEFAULT_TOGGLE_TYPE); + final ExpandIndicatorController expandIndicatorController; + switch (expandToggleType) { + case EXPAND_INDICATOR_IMAGE_BUTTON: + PixelMap expandDrawable = null; + PixelMap collapseDrawable = null; + boolean expandPresent = attrSet.getAttr("expandIndicator").isPresent(); + if (expandPresent) { + expandDrawable = ((PixelMapElement) (attrSet.getAttr("expandIndicator").get().getElement())).getPixelMap(); + } + boolean collapsePresent = attrSet.getAttr("collapseIndicator").isPresent(); + if (collapsePresent) { + collapseDrawable = ((PixelMapElement) (attrSet.getAttr("collapseIndicator").get().getElement())).getPixelMap(); + } + if (expandDrawable == null) { + expandDrawable = getPixelMap(ResourceTable.Media_ic_expand_more_black_12dp, context); + } + if (collapseDrawable == null) { + collapseDrawable = getPixelMap(ResourceTable.Media_ic_expand_less_black_12dp, context); + } + expandIndicatorController = new ImageButtonExpandController(expandDrawable, collapseDrawable); + break; + case EXPAND_INDICATOR_TEXT_VIEW: + expandIndicatorController = new TextViewExpandController(ResourceTable.String_expand_more, ResourceTable.String_expand_less); + break; + default: + throw new IllegalStateException("Must be of enum: ExpandableTextView_expandToggleType, one of EXPAND_INDICATOR_IMAGE_BUTTON or EXPAND_INDICATOR_TEXT_VIEW."); + } + + return expandIndicatorController; + } + + /** + * 设置文案 + * + * @param text 文案内容 + */ + public void setText(String text) { + mRelayout = true; + findViews(); + expandText.setText(text); + setVisibility(null == text ? Component.HIDE : Component.VISIBLE); + postLayout(); + } +} diff --git a/lib/src/main/java/com/ms/square/ohos/expandabletext/TypedAttrUtils.java b/lib/src/main/java/com/ms/square/ohos/expandabletext/TypedAttrUtils.java new file mode 100644 index 0000000..8286748 --- /dev/null +++ b/lib/src/main/java/com/ms/square/ohos/expandabletext/TypedAttrUtils.java @@ -0,0 +1,118 @@ +/* + * 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.ms.square.ohos.expandabletext; + + +import ohos.agp.components.Attr; +import ohos.agp.components.AttrSet; +import ohos.agp.utils.Color; +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogLabel; + +import java.util.NoSuchElementException; + +/** + * author zhaoxudong + * Version 1.0 + * ModifiedBy + * date 2021-02-22 10:12 + * description 工具类 + */ +public final class TypedAttrUtils { + static final HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, "jiangbenfu"); + + 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(); + } + } + + public static Color getColor(AttrSet attrs, String attrName, Color defValue) { + Attr attr = attrNoSuchElement(attrs, attrName); + if (attr == null) { + return defValue; + } else { + return attr.getColorValue(); + } + } + + public static boolean getBoolean(AttrSet attrs, String attrName, boolean defValue) { + Attr attr = attrNoSuchElement(attrs, attrName); + if (attr == null) { + return defValue; + } else { + return attr.getBoolValue(); + } + } + + + public static int getInteger(AttrSet attrs, String attrName, int defValue) { + Attr attr = attrNoSuchElement(attrs, attrName); + if (attr == null) { + return defValue; + } else { + return attr.getIntegerValue(); + } + } + + public static float getFloat(AttrSet attrs, String attrName, float defValue) { + Attr attr = attrNoSuchElement(attrs, attrName); + if (attr == null) { + return defValue; + } else { + return attr.getFloatValue(); + } + } + + public static String getString(AttrSet attrs, String attrName, String defValue) { + Attr attr = attrNoSuchElement(attrs, attrName); + if (attr == null) { + return defValue; + } else { + return attr.getStringValue(); + } + } + + public static int getDimensionPixelSize(AttrSet attrs, String attrName, int defValue) { + Attr attr = attrNoSuchElement(attrs, attrName); + if (attr == null) { + return defValue; + } else { + return attr.getIntegerValue(); + } + } + + public static int getLayoutDimension(AttrSet attrs, String attrName, int defValue) { + Attr attr = attrNoSuchElement(attrs, attrName); + if (attr == null) { + return defValue; + } else { + 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; + } +} -- Gitee