chips) {
- System.out.println("Number of contacts: " + chips.size());
- mChipsInput.setFilterableChipList(chips);
- }
-
- @Override
- protected void onContactsReset() {}
-
- @Override
- public void onContactClicked(ContactChip chip) {}
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tylersuehr/chipexample/MyApplication.java b/app/src/main/java/com/tylersuehr/chipexample/MyApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a40d77716ace15517e3ba9af9d44320b2476e99
--- /dev/null
+++ b/app/src/main/java/com/tylersuehr/chipexample/MyApplication.java
@@ -0,0 +1,10 @@
+package com.tylersuehr.chipexample;
+
+import ohos.aafwk.ability.AbilityPackage;
+
+public class MyApplication extends AbilityPackage {
+ @Override
+ public void onInitialize() {
+ super.onInitialize();
+ }
+}
diff --git a/app/src/main/java/com/tylersuehr/chipexample/slice/MainAbilitySlice.java b/app/src/main/java/com/tylersuehr/chipexample/slice/MainAbilitySlice.java
new file mode 100644
index 0000000000000000000000000000000000000000..8fbf27109efb58f34ef895e79d0d8c4e39b22e2b
--- /dev/null
+++ b/app/src/main/java/com/tylersuehr/chipexample/slice/MainAbilitySlice.java
@@ -0,0 +1,211 @@
+/**
+ * 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.tylersuehr.chipexample.slice;
+
+import com.tylersuehr.chipexample.ResourceTable;
+import com.tylersuehr.chipexample.utils.KeyboardVisibilityEvent;
+import com.tylersuehr.chipexample.utils.KeyboardVisibilityEventListener;
+import com.tylersuehr.chipexample.utils.Unregistrar;
+import com.tylersuehr.chips.ChipDetailsView;
+import com.tylersuehr.chips.FlowLayout;
+import ohos.aafwk.ability.AbilitySlice;
+import ohos.aafwk.content.Intent;
+import ohos.agp.colors.RgbColor;
+import ohos.agp.components.*;
+import ohos.agp.components.element.ShapeElement;
+import ohos.agp.utils.Color;
+import ohos.agp.window.service.Display;
+import ohos.agp.window.service.DisplayManager;
+import ohos.agp.window.service.WindowManager;
+import ohos.app.Context;
+import ohos.multimodalinput.event.KeyEvent;
+
+/**
+ * MainAbilitySlice
+ *
+ * @since 2021-06-22
+ */
+public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {
+ private StackLayout rootLayout;
+ private FlowLayout mFirstFlowLayout;
+ private Image mImage;
+ private int id = 0;
+ private Component component;
+ private ChipDetailsView chipDetailsView;
+ private Text mTextTitle;
+ private Text mTextName;
+ private Component view;
+ private ScrollView mScrollView;
+ private Component component2;
+ private TextField mTextField;
+ private KeyboardVisibilityEvent mKeyboardVisibilityEvent;
+
+ @Override
+ public void onStart(Intent intent) {
+ super.onStart(intent);
+ super.setUIContent(ResourceTable.Layout_ability_main);
+ WindowManager.getInstance().getTopWindow().get().setStatusBarColor(Color.BLUE.getValue());
+ getWindow().setStatusBarColor(Color.getIntColor("#008BA3"));
+ mScrollView = (ScrollView) findComponentById(ResourceTable.Id_id_scrollview);
+ rootLayout = (StackLayout) findComponentById(ResourceTable.Id_root);
+ rootLayout.setClickedListener(this);
+ mFirstFlowLayout = (FlowLayout) findComponentById(ResourceTable.Id_id_first_flowlayout);
+ mFirstFlowLayout.setListener(this);
+ ShapeElement shapeElement = new ShapeElement();
+ shapeElement.setRgbColor(new RgbColor(0, 0, 0));
+ ComponentContainer.LayoutConfig scrollConfig = new ComponentContainer.LayoutConfig(
+ DirectionalLayout.LayoutConfig.MATCH_PARENT, DirectionalLayout.LayoutConfig.MATCH_PARENT);
+ mScrollView.setLayoutConfig(scrollConfig);
+ mScrollView.enableScrollBar(1, true);
+ rootLayout.setClickedListener(new Component.ClickedListener() {
+ @Override
+ public void onClick(Component component) {
+ System.out.println(Math.floor(Math.random() * 10));
+ }
+ });
+ component2 = LayoutScatter.getInstance(MainAbilitySlice.this).parse(ResourceTable.Layout_layout_textField, null, false);
+ mTextField = (TextField) component2.findComponentById(ResourceTable.Id_item_TextField);
+ mTextField.setCursorElement(shapeElement);
+ mFirstFlowLayout.addComponent(component2);
+
+ mTextField.setKeyEventListener(new Component.KeyEventListener() {
+ @Override
+ public boolean onKeyEvent(Component components, KeyEvent keyEvent) {
+ component = LayoutScatter.getInstance(MainAbilitySlice.this).parse(ResourceTable.Layout_layout_text, null, false);
+ mTextTitle = (Text) component.findComponentById(ResourceTable.Id_txt_user_title);
+ mTextName = (Text) component.findComponentById(ResourceTable.Id_txt_user_name);
+ mImage = (Image) component.findComponentById(ResourceTable.Id_txt_user_fork);
+
+ ShapeElement background = new ShapeElement();
+ background.setCornerRadius(100);
+ double num = Math.floor(Math.random() * 8);
+ if (num == 0) {
+ background.setRgbColor(new RgbColor(249, 164, 61));
+ mTextName.setTag(num);
+ } else if (num == 1) {
+ background.setRgbColor(new RgbColor(241, 99, 101));
+ mTextName.setTag(num);
+ } else if (num == 2) {
+ background.setRgbColor(new RgbColor(34, 147, 205));
+ mTextName.setTag(num);
+ } else if (num == 3) {
+ background.setRgbColor(new RgbColor(228, 198, 46));
+ mTextName.setTag(num);
+ } else if (num == 4) {
+ background.setRgbColor(new RgbColor(173, 98, 167));
+ mTextName.setTag(num);
+ } else if (num == 5) {
+ background.setRgbColor(new RgbColor(123, 113, 206));
+ mTextName.setTag(num);
+ } else if (num == 6) {
+ background.setRgbColor(new RgbColor(123, 113, 206));
+ mTextName.setTag(num);
+ } else if (num == 7) {
+ background.setRgbColor(new RgbColor(123, 113, 19));
+ mTextName.setTag(num);
+ } else {
+ background.setRgbColor(new RgbColor(21, 255, 236));
+ mTextName.setTag(num);
+ }
+ mTextTitle.setBackground(background);
+
+ mImage.setClickedListener(new Component.ClickedListener() {
+ @Override
+ public void onClick(Component component) {
+ mFirstFlowLayout.removeComponent((Component) component.getComponentParent());
+ }
+ });
+ if (keyEvent.isKeyDown() && keyEvent.getKeyCode() == keyEvent.KEY_ENTER) {
+ String s = mTextField.getText();
+ if (!"".equals(s)) {
+ mTextTitle.setText(s.substring(0, 1).toUpperCase());
+ mTextName.setText(s);
+ mTextField.setText("");
+ mFirstFlowLayout.addComponent(component);
+ mFirstFlowLayout.removeComponent(component2);
+ mFirstFlowLayout.addComponent(component2);
+ }
+ }
+ return false;
+ }
+ });
+
+ mKeyboardVisibilityEvent = new KeyboardVisibilityEvent();
+ mKeyboardVisibilityEvent.setAbilitySliceRoot(rootLayout);
+ }
+
+ @Override
+ public void onActive() {
+ super.onActive();
+ }
+
+ @Override
+ public void onForeground(Intent intent) {
+ super.onForeground(intent);
+ }
+
+ @Override
+ public void onClick(Component component) {
+ switch (component.getId()) {
+ case ResourceTable.Id_root:
+ rootLayout.removeComponent(component);
+ break;
+ case ResourceTable.Id_button_delete:
+ rootLayout.removeComponent(chipDetailsView);
+ mFirstFlowLayout.removeComponent(view);
+ break;
+ case ResourceTable.Id_container:
+ rootLayout.removeComponent(chipDetailsView);
+ mFirstFlowLayout.postLayout();
+ break;
+ default:
+ showDetailedChipView(component);
+ view = component;
+ break;
+ }
+ }
+
+ private void showDetailedChipView(Component component) {
+ Text text = (Text) component.findComponentById(ResourceTable.Id_txt_user_name);
+
+ if (chipDetailsView != null) {
+ rootLayout.removeComponent(chipDetailsView);
+ }
+ if (text.getTag() != null) {
+ chipDetailsView = new ChipDetailsView(getContext(), text.getText(), (Double) text.getTag());
+ DirectionalLayout.LayoutConfig config = new DirectionalLayout.LayoutConfig(DirectionalLayout.LayoutConfig.MATCH_PARENT,
+ DirectionalLayout.LayoutConfig.MATCH_PARENT);
+ if (component.getContentPositionX() > getDisplayWidthInPx(this) - 900) {
+ config.setMargins(getDisplayWidthInPx(this) - 900, (int) component.getContentPositionY() + 200, 0, 0);
+ } else {
+ config.setMargins((int) component.getContentPositionX(), (int) component.getContentPositionY() + 200, 0, 0);
+ }
+ rootLayout.addComponent(chipDetailsView, config);
+ }
+
+ chipDetailsView.setOnDeleteClicked(this);
+ }
+
+ /**
+ * 获取屏幕宽度
+ *
+ * @return 屏幕宽度
+ */
+ public static int getDisplayWidthInPx(Context context) {
+ Display display = DisplayManager.getInstance().getDefaultDisplay(context).get();
+ return display.getAttributes().width;
+ }
+}
diff --git a/app/src/main/java/com/tylersuehr/chipexample/utils/KeyboardVisibilityEvent.java b/app/src/main/java/com/tylersuehr/chipexample/utils/KeyboardVisibilityEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..183088328ceb46ce2ac72206e93827880807056a
--- /dev/null
+++ b/app/src/main/java/com/tylersuehr/chipexample/utils/KeyboardVisibilityEvent.java
@@ -0,0 +1,138 @@
+/**
+ * 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.tylersuehr.chipexample.utils;
+
+import ohos.aafwk.ability.AbilitySlice;
+import ohos.aafwk.ability.LifecycleObserver;
+import ohos.agp.components.Component;
+import ohos.agp.utils.Point;
+import ohos.agp.utils.Rect;
+import ohos.agp.window.service.DisplayManager;
+import ohos.app.Context;
+
+public class KeyboardVisibilityEvent {
+ private static final double KEYBOARD_MIN_HEIGHT_RATIO = 0.15;
+ private Component mRootView;
+ private LifecycleObserver mLifecycleObserver = null;
+ private static KeyboardVisibilityEvent keyboardVisibilityEvent;
+
+ public static KeyboardVisibilityEvent getInstance() {
+ if (keyboardVisibilityEvent == null) {
+ keyboardVisibilityEvent = new KeyboardVisibilityEvent();
+ }
+ return keyboardVisibilityEvent;
+ }
+
+ /**
+ * Set keyboard visibility change event listener.
+ * This automatically remove registered event listener when the Activity is destroyed
+ *
+ * @param abilitySlice Activity
+ */
+ public void setEventListener(AbilitySlice abilitySlice, KeyboardVisibilityEventListener listener) {
+ Unregistrar unregistrar = registerEventListener(abilitySlice, listener);
+ //需要生命周期的监听 ILifecycleObserver
+ mLifecycleObserver = new LifecycleObserver() {
+ @Override
+ public void onStop() {
+ super.onStop();
+ abilitySlice.getLifecycle().removeObserver(this);
+ unregistrar.unregister(mRootView);
+ }
+ };
+ abilitySlice.getLifecycle().addObserver(mLifecycleObserver);
+ }
+
+ /**
+ * Set keyboard visibility change event listener.
+ * This automatically remove registered event listener when the Activity is destroyed
+ *
+ * @param abilitySlice Activity
+ */
+ public Unregistrar registerEventListener(
+ AbilitySlice abilitySlice,
+ KeyboardVisibilityEventListener listener) {
+ if (abilitySlice == null) {
+ throw new NullPointerException("Parameter:AbilitySlice must not be null");
+ }
+ if (listener == null) {
+ throw new NullPointerException("Parameter:listener must not be null");
+ }
+ if (mRootView == null) {
+ throw new NullPointerException("mRootView:listener must not be null");
+ }
+
+ Component.LayoutRefreshedListener layoutListener = new Component.LayoutRefreshedListener() {
+ private boolean isWasOpened = false;
+
+ @Override
+ public void onRefreshed(Component component) {
+ boolean isOpen = isKeyboardVisible(abilitySlice);
+
+ if (isOpen != isWasOpened) {
+ // keyboard state has not changed
+
+ isWasOpened = isOpen;
+ listener.onVisibilityChanged(isOpen);
+ }
+ }
+ };
+ mRootView.setLayoutRefreshedListener(layoutListener);
+ return new SimpleUnregistrar(abilitySlice, layoutListener);
+ }
+
+ /**
+ * Determine if keyboard is visible
+ *
+ * @param abilitySlice Activity
+ * @return Whether keyboard is visible or not
+ */
+ public boolean isKeyboardVisible(AbilitySlice abilitySlice) {
+ Rect rect = new Rect();
+
+ mRootView.getSelfVisibleRect(rect);
+
+ int[] location = mRootView.getLocationOnScreen();
+
+ int screenHeight = (int) getRealHeight(abilitySlice.getContext());
+ int heightDiff = screenHeight - rect.getHeight() - location[1];
+
+ if (location[1] == 0) {
+ return false;
+ } else {
+ return heightDiff > screenHeight * KEYBOARD_MIN_HEIGHT_RATIO;
+ }
+ }
+
+ //获取根界面进行传入
+ public void setAbilitySliceRoot(Component RootView) {
+ this.mRootView = RootView;
+ }
+
+ public Component getAbilitySliceRoot() {
+ if (mRootView == null) {
+ throw new NullPointerException("mRootView:listener must not be null");
+ } else {
+ return mRootView;
+ }
+ }
+
+ public static float getRealHeight(Context context) {
+ Point point = new Point();
+ DisplayManager.getInstance().getDefaultDisplay(context).get().getRealSize(point);
+ return point.getPointY();
+ }
+}
diff --git a/app/src/main/java/com/tylersuehr/chipexample/utils/KeyboardVisibilityEventListener.java b/app/src/main/java/com/tylersuehr/chipexample/utils/KeyboardVisibilityEventListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b3c9fa3da6b7c20c61e9ea294ec932c49e7f4ff
--- /dev/null
+++ b/app/src/main/java/com/tylersuehr/chipexample/utils/KeyboardVisibilityEventListener.java
@@ -0,0 +1,23 @@
+/**
+ * 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.tylersuehr.chipexample.utils;
+
+/**
+ * Created by yshrsmz on 15/03/17.
+ */
+public interface KeyboardVisibilityEventListener {
+ void onVisibilityChanged(boolean isOpen);
+}
diff --git a/app/src/main/java/com/tylersuehr/chipexample/utils/SimpleUnregistrar.java b/app/src/main/java/com/tylersuehr/chipexample/utils/SimpleUnregistrar.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a81e6b5dee3e227e5f306ba7076095f1bfc1392
--- /dev/null
+++ b/app/src/main/java/com/tylersuehr/chipexample/utils/SimpleUnregistrar.java
@@ -0,0 +1,47 @@
+/**
+ * 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.tylersuehr.chipexample.utils;
+
+import ohos.aafwk.ability.AbilitySlice;
+import ohos.agp.components.Component;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * @author Anoop S S
+ * anoopvvs@gmail.com
+ * on 28/02/2017
+ */
+public class SimpleUnregistrar implements Unregistrar {
+ private WeakReference activityWeakReference;
+ private WeakReference onGlobalLayoutListenerWeakReference;
+
+ public SimpleUnregistrar(AbilitySlice abilitySlice, Component.LayoutRefreshedListener globalLayoutListener) {
+ activityWeakReference = new WeakReference(abilitySlice);
+ onGlobalLayoutListenerWeakReference = new WeakReference(globalLayoutListener);
+ }
+
+ @Override
+ public void unregister(Component rootview) {
+ AbilitySlice abilitySlice=activityWeakReference.get();
+ Component.LayoutRefreshedListener layoutRefreshedListener=onGlobalLayoutListenerWeakReference.get();
+ if (null!=abilitySlice&&null!=layoutRefreshedListener){
+ rootview.setLayoutRefreshedListener(null);
+ }
+ activityWeakReference.clear();
+ onGlobalLayoutListenerWeakReference.clear();
+ }
+}
diff --git a/app/src/main/java/com/tylersuehr/chipexample/utils/Unregistrar.java b/app/src/main/java/com/tylersuehr/chipexample/utils/Unregistrar.java
new file mode 100644
index 0000000000000000000000000000000000000000..417beb8fea40b7b2cdc9b716676e3f550316a277
--- /dev/null
+++ b/app/src/main/java/com/tylersuehr/chipexample/utils/Unregistrar.java
@@ -0,0 +1,27 @@
+/**
+ * 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.tylersuehr.chipexample.utils;
+
+import ohos.agp.components.Component;
+
+/**
+ * @author Anoop S S
+ * anoopvvs@gmail.com
+ * on 28/02/2017
+ */
+public interface Unregistrar {
+ void unregister(Component RootView);
+}
diff --git a/app/src/main/res/drawable/ic_clear_black_24dp.xml b/app/src/main/res/drawable/ic_clear_black_24dp.xml
deleted file mode 100644
index ede4b7108d5ea6fc2112c160f13589f7f21c42fc..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_clear_black_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/layout/activity_chips_input_test.xml b/app/src/main/res/layout/activity_chips_input_test.xml
deleted file mode 100644
index f63a1cec6edba7b9b9dabec8df3f75ff94285581..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/activity_chips_input_test.xml
+++ /dev/null
@@ -1,169 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_example_chips.xml b/app/src/main/res/layout/activity_example_chips.xml
deleted file mode 100644
index b0b4d107dc1c15b3b748efed46610ced0e476e11..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/activity_example_chips.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index f68e6b189a1d0ae5b643eb339a8544b00ad4fc84..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bcccec65160d92116f20ffce4fce0b5245c..0000000000000000000000000000000000000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index 9a078e3e1a42d474c78470a73c7987cf7ac5d9a0..0000000000000000000000000000000000000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0cbd379f5af6dbf1a899a0293ca5eccfad0..0000000000000000000000000000000000000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index efc028a636dd690a51db5a525cf781a5a7daba68..0000000000000000000000000000000000000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0e7b91d006d22352c9ff2f134e504e3c1d..0000000000000000000000000000000000000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
deleted file mode 100644
index 3af2608a4492ef9ae63a77ec3305aedda89594cb..0000000000000000000000000000000000000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72cdd7480cb983fa1bcc7ce686e51ef87fe7..0000000000000000000000000000000000000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
deleted file mode 100644
index 9bec2e623103ac9713b00cad8502a057c1efda61..0000000000000000000000000000000000000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e138434630332d88b1680f33c4b24c70ab3..0000000000000000000000000000000000000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
deleted file mode 100644
index 34947cd6bbf9c729be83edc96ad08a1d42b82bc9..0000000000000000000000000000000000000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
deleted file mode 100644
index 5eb48e7b11bc24ad0676bc19f5dec08be45ee9c3..0000000000000000000000000000000000000000
--- a/app/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- #00bcd4
- #008ba3
- #004c4c
- #ff9e80
-
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
deleted file mode 100644
index 6a08a083eedecea289381b9266f006e10d09a925..0000000000000000000000000000000000000000
--- a/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- chips
-
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
deleted file mode 100644
index d93c47877eb8ef9fbbd61ad06a62282afbbc8645..0000000000000000000000000000000000000000
--- a/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/resources/base/element/string.json b/app/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..2e924cf01eb94a2db0dd9b4fef178136d3524755
--- /dev/null
+++ b/app/src/main/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "chips"
+ },
+ {
+ "name": "mainability_description",
+ "value": "Java_Phone_Empty Feature Ability"
+ },
+ {
+ "name": "mainability_HelloWorld",
+ "value": "Hello World"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/src/main/resources/base/graphic/background_ability_main.xml b/app/src/main/resources/base/graphic/background_ability_main.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c0c0a3df480fa387a452b9c40ca191cc918a3fc0
--- /dev/null
+++ b/app/src/main/resources/base/graphic/background_ability_main.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/resources/base/graphic/chip_default.xml b/app/src/main/resources/base/graphic/chip_default.xml
new file mode 100644
index 0000000000000000000000000000000000000000..10d52bd642913af5708d4cff031725a25d00152a
--- /dev/null
+++ b/app/src/main/resources/base/graphic/chip_default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/resources/base/graphic/chip_defaults.xml b/app/src/main/resources/base/graphic/chip_defaults.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6505957abbe40e60e0cdda3524ae0670a71998e7
--- /dev/null
+++ b/app/src/main/resources/base/graphic/chip_defaults.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/resources/base/layout/ability_main.xml b/app/src/main/resources/base/layout/ability_main.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eb1f2a99e239303f9a94b833342edc7b1d022886
--- /dev/null
+++ b/app/src/main/resources/base/layout/ability_main.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/resources/base/layout/layout_text.xml b/app/src/main/resources/base/layout/layout_text.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9f46ae68da2dbdb225f7718d042420b4299a7c48
--- /dev/null
+++ b/app/src/main/resources/base/layout/layout_text.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/resources/base/layout/layout_textField.xml b/app/src/main/resources/base/layout/layout_textField.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4d408835ae51fcb23cfcfd3e31a9220e6143a830
--- /dev/null
+++ b/app/src/main/resources/base/layout/layout_textField.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/resources/base/layout/layout_titlebar.xml b/app/src/main/resources/base/layout/layout_titlebar.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9f46ae68da2dbdb225f7718d042420b4299a7c48
--- /dev/null
+++ b/app/src/main/resources/base/layout/layout_titlebar.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/resources/base/media/fork.png b/app/src/main/resources/base/media/fork.png
new file mode 100644
index 0000000000000000000000000000000000000000..216b8d4ac360ef6d204b5d376b785c4f9c79f613
Binary files /dev/null and b/app/src/main/resources/base/media/fork.png differ
diff --git a/app/src/main/resources/base/media/icon.png b/app/src/main/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/app/src/main/resources/base/media/icon.png differ
diff --git a/app/src/ohosTest/config.json b/app/src/ohosTest/config.json
new file mode 100644
index 0000000000000000000000000000000000000000..1a4be0eb877b3feeb1ea9d16ebbee90d8af54920
--- /dev/null
+++ b/app/src/ohosTest/config.json
@@ -0,0 +1,41 @@
+{
+ "app": {
+ "bundleName": "com.tylersuehr.chipexample",
+ "vendor": "tylersuehr",
+ "version": {
+ "code": 1000000,
+ "name": "1.0.0"
+ },
+ "apiVersion": {
+ "compatible": 5,
+ "target": 5,
+ "releaseType": "Release"
+ }
+ },
+ "deviceConfig": {},
+ "module": {
+ "package": "com.tylersuehr.chipexample",
+ "name": "testModule",
+ "deviceType": [
+ "phone"
+ ],
+ "distro": {
+ "deliveryWithInstall": true,
+ "moduleName": "entry_test",
+ "moduleType": "feature",
+ "installationFree": true
+ },
+ "abilities": [
+ {
+ "name": "decc.testkit.runner.EntryAbility",
+ "description": "Test Entry Ability",
+ "icon": "$media:icon",
+ "label": "$string:app_name",
+ "launchType": "standard",
+ "orientation": "landscape",
+ "visible": true,
+ "type": "page"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/ohosTest/java/com/tylersuehr/chipexample/ExampleOhosTest.java b/app/src/ohosTest/java/com/tylersuehr/chipexample/ExampleOhosTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..163bad6701b8918a50bf537ecc9345bc39eab941
--- /dev/null
+++ b/app/src/ohosTest/java/com/tylersuehr/chipexample/ExampleOhosTest.java
@@ -0,0 +1,14 @@
+package com.tylersuehr.chipexample;
+
+import ohos.aafwk.ability.delegation.AbilityDelegatorRegistry;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ExampleOhosTest {
+ @Test
+ public void testBundleName() {
+ final String actualBundleName = AbilityDelegatorRegistry.getArguments().getTestBundleName();
+ assertEquals("com.tylersuehr.chipexample", actualBundleName);
+ }
+}
\ No newline at end of file
diff --git a/app/src/test/java/com/tylersuehr/chipexample/ExampleTest.java b/app/src/test/java/com/tylersuehr/chipexample/ExampleTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6878196ec8db3116bfeb3e3dc24e27db1905e899
--- /dev/null
+++ b/app/src/test/java/com/tylersuehr/chipexample/ExampleTest.java
@@ -0,0 +1,9 @@
+package com.tylersuehr.chipexample;
+
+import org.junit.Test;
+
+public class ExampleTest {
+ @Test
+ public void onStart() {
+ }
+}
diff --git a/app/src/test/java/com/tylersuehr/chipexample/ExampleUnitTest.java b/app/src/test/java/com/tylersuehr/chipexample/ExampleUnitTest.java
deleted file mode 100644
index 130ea3242b3754ac5530f79e5ca4eb25c2065586..0000000000000000000000000000000000000000
--- a/app/src/test/java/com/tylersuehr/chipexample/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.tylersuehr.chipexample;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see Testing documentation
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() throws Exception {
- assertEquals(4, 2 + 2);
- }
-}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 192b6800fd51b70546481f64d826b86ebb2ed6fd..b65c473a9409461f0814f6ba9dd95462705f3c9f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,26 +1,48 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
+apply plugin: 'com.huawei.ohos.app'
+
+ohos {
+ signingConfigs {
+ debug {
+ storeFile file('D:\\svn\\hongmeng\\trunk\\keyStore\\ActivityRouter\\root_1.p12')
+ storePassword '00000020879452DAE791DF7810337911EE7122AA0B49D38A2E275CBBF4F1D13E0C5974281CB0E8A4673968BE2E58EECC'
+ keyAlias = 'hos_platform_os'
+ keyPassword '00000020FE8A6B86A90DC31747CA6E81C9777F878066C8B13311831C3A8A3290DED9B8D2F369FCC063E2A575AC863020'
+ signAlg = 'SHA256withECDSA'
+ profile file('D:\\svn\\hongmeng\\trunk\\签名文件\\六月份组件签名\\chips-input-layoutDebug.p7b')
+ certpath file('D:\\svn\\hongmeng\\trunk\\keyStore\\ActivityRouter\\root.cer')
+ }
+ }
+ compileSdkVersion 5
+ defaultConfig {
+ compatibleSdkVersion 5
+ }
+}
buildscript {
repositories {
+ maven {
+ url 'https://repo.huaweicloud.com/repository/maven/'
+ }
+ maven {
+ url 'https://developer.huawei.com/repo/'
+ }
jcenter()
- google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.1.4'
- classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
+ classpath 'com.huawei.ohos:hap:2.4.4.2'
+ classpath 'com.huawei.ohos:decctest:1.0.0.7'
}
}
allprojects {
repositories {
+ maven {
+ url 'https://repo.huaweicloud.com/repository/maven/'
+ }
+ maven {
+ url 'https://developer.huawei.com/repo/'
+ }
jcenter()
- google()
}
}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
diff --git a/docs/Google Pixel XL.psd b/docs/Google Pixel XL.psd
deleted file mode 100644
index 145756c20e0158ed84c535cfe2763b28c1a6d906..0000000000000000000000000000000000000000
Binary files a/docs/Google Pixel XL.psd and /dev/null differ
diff --git a/docs/screen_chip_details.png b/docs/screen_chip_details.png
deleted file mode 100644
index 82e251f277b28a3f6595262e47f4ddf0afe68f1e..0000000000000000000000000000000000000000
Binary files a/docs/screen_chip_details.png and /dev/null differ
diff --git a/docs/screen_chips_multiple.png b/docs/screen_chips_multiple.png
deleted file mode 100644
index 32a204875872d7dc85b481757c248f036e085447..0000000000000000000000000000000000000000
Binary files a/docs/screen_chips_multiple.png and /dev/null differ
diff --git a/docs/screen_contact_chip_details.png b/docs/screen_contact_chip_details.png
deleted file mode 100644
index 1f1eb02f983f9955e52ff4d383dd9e8421a05738..0000000000000000000000000000000000000000
Binary files a/docs/screen_contact_chip_details.png and /dev/null differ
diff --git a/docs/screen_contact_chip_multiple.png b/docs/screen_contact_chip_multiple.png
deleted file mode 100644
index b9e09387d1f515224f8a941855e2208d364a3145..0000000000000000000000000000000000000000
Binary files a/docs/screen_contact_chip_multiple.png and /dev/null differ
diff --git a/docs/screen_contact_chip_single.png b/docs/screen_contact_chip_single.png
deleted file mode 100644
index dfa0b37fafcd5bf86126c8515df152680b75d27d..0000000000000000000000000000000000000000
Binary files a/docs/screen_contact_chip_single.png and /dev/null differ
diff --git a/docs/screen_filterable_list.png b/docs/screen_filterable_list.png
deleted file mode 100644
index 898d6d46c642ec486e1cda4f4145d0ebc5ba4e4f..0000000000000000000000000000000000000000
Binary files a/docs/screen_filterable_list.png and /dev/null differ
diff --git a/gradle.properties b/gradle.properties
index aac7c9b4614ccfde6c721f24994cf30885a791d0..0daf1830fbdef07e50a44d74210c8c82f1b66278 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,17 +1,10 @@
# Project-wide Gradle settings.
-
-# IDE (e.g. Android Studio) users:
+# IDE (e.g. DevEco Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
-
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
-
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx1536m
-
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
+# If the Chinese output is garbled, please configure the following parameter.
+# org.gradle.jvmargs=-Dfile.encoding=GBK
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 13372aef5e24af05341d49695ee84e5f9b594659..490fda8577df6c95960ba7077c43220e5bb2c0d9 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f11adc1eb57d4946d6a1e2c0f2a3ab2f49d2f677..f59159e865d4b59feb1b8c44b001f62fc5d58df4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Sun May 13 14:36:53 KRAT 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://repo.huaweicloud.com/gradle/gradle-6.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/gradlew b/gradlew
index d1c75a26cca7b99d15cd51ee76cb0d25fc0fb8a1..2fe81a7d95e4f9ad2c9b2a046707d36ceb3980b3 100644
--- a/gradlew
+++ b/gradlew
@@ -1,4 +1,20 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
##############################################################################
##
@@ -6,20 +22,38 @@
##
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
-warn ( ) {
+warn () {
echo "$*"
}
-die ( ) {
+die () {
echo
echo "$*"
echo
@@ -30,6 +64,7 @@ die ( ) {
cygwin=false
msys=false
darwin=false
+nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
@@ -40,26 +75,11 @@ case "`uname`" in
MINGW* )
msys=true
;;
+ NONSTOP* )
+ nonstop=true
+ ;;
esac
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -85,7 +105,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -105,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
@@ -134,27 +154,30 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
- i=$((i+1))
+ i=`expr $i + 1`
done
case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
\ No newline at end of file
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 8a0b282aa6885fb573c106b3551f7275c5f17e8e..62bd9b9ccefea2b65ae41e5d9a545e2021b90a1d 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -8,14 +24,17 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +65,9 @@ echo location of your Java installation.
goto fail
:init
-@rem Get command-line arguments, handling Windowz variants
+@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +78,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
diff --git a/img/demo.gif b/img/demo.gif
new file mode 100644
index 0000000000000000000000000000000000000000..a7bafd212195755b4aad0115040609adb858d24b
Binary files /dev/null and b/img/demo.gif differ
diff --git a/library/.gitignore b/library/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..796b96d1c402326528b4ba3c12ee9d92d0e212e9
--- /dev/null
+++ b/library/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/library/build.gradle b/library/build.gradle
index 841a5407d014ba9735c0e1505c19b3809b7e88a8..e1c0b274a6c5cb35b197a177a17684addf760676 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -1,38 +1,21 @@
-apply plugin: 'com.android.library'
-
-android {
-
- compileSdkVersion 28
- buildToolsVersion "28.0.2"
-
+apply plugin: 'com.huawei.ohos.library'
+ohos {
+ compileSdkVersion 5
defaultConfig {
- minSdkVersion 16
- targetSdkVersion 28
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-
+ compatibleSdkVersion 4
}
buildTypes {
release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ proguardOpt {
+ proguardEnabled false
+ rulesFiles 'proguard-rules.pro'
+ }
}
}
+
}
dependencies {
-
- implementation fileTree(include: ['*.jar'], dir: 'libs')
- androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
- exclude group: 'com.android.support', module: 'support-annotations'
- })
- implementation 'com.android.support:appcompat-v7:28.0.0-rc01'
- implementation 'com.android.support:recyclerview-v7:28.0.0-rc01'
- implementation 'com.android.support.constraint:constraint-layout:1.1.2'
- implementation 'com.beloo.widget:ChipsLayoutManager:0.3.7@aar'
- testImplementation 'junit:junit:4.12'
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ testImplementation 'junit:junit:4.13'
}
-
-apply plugin: 'com.github.dcendents.android-maven'
-group='com.github.tylersuehr7'
\ No newline at end of file
diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f7666e47561d514b2a76d5a7dfbb43ede86da92a
--- /dev/null
+++ b/library/proguard-rules.pro
@@ -0,0 +1 @@
+# config module specific ProGuard rules here.
\ No newline at end of file
diff --git a/library/src/androidTest/java/com/tylersuehr/chips/ExampleAndroidTest.java b/library/src/androidTest/java/com/tylersuehr/chips/ExampleAndroidTest.java
deleted file mode 100644
index 25e3e631f4769354da2403e7608e05204140c5c1..0000000000000000000000000000000000000000
--- a/library/src/androidTest/java/com/tylersuehr/chips/ExampleAndroidTest.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.tylersuehr.chips;
-
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.runner.RunWith;
-
-/**
- * Copyright © 2017 Tyler Suehr
- *
- * @author Tyler Suehr
- * @version 1.0
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleAndroidTest {
-}
\ No newline at end of file
diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml
deleted file mode 100644
index 1c1d713085e682edb8546e00a9bcb7a0e6bbd74f..0000000000000000000000000000000000000000
--- a/library/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/library/src/main/config.json b/library/src/main/config.json
new file mode 100644
index 0000000000000000000000000000000000000000..bdb08641a6b7372d2982217cedc95ffe374e45c6
--- /dev/null
+++ b/library/src/main/config.json
@@ -0,0 +1,28 @@
+{
+ "app": {
+ "bundleName": "com.tylersuehr.chips",
+ "vendor": "tylersuehr",
+ "version": {
+ "code": 1000000,
+ "name": "1.0.0"
+ },
+ "apiVersion": {
+ "compatible": 4,
+ "target": 5,
+ "releaseType": "Release"
+ }
+ },
+ "deviceConfig": {
+ },
+ "module": {
+ "package": "com.tylersuehr.chips",
+ "deviceType": [
+ "phone"
+ ],
+ "distro": {
+ "deliveryWithInstall": true,
+ "moduleName": "library",
+ "moduleType": "har"
+ }
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/tylersuehr/chips/Chip.java b/library/src/main/java/com/tylersuehr/chips/Chip.java
index 327a4d198a7276e3453c63ae806029ee76b76210..ae70e8ce93eea8851be1f43ec523f6a903ef050b 100644
--- a/library/src/main/java/com/tylersuehr/chips/Chip.java
+++ b/library/src/main/java/com/tylersuehr/chips/Chip.java
@@ -1,9 +1,7 @@
package com.tylersuehr.chips;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import ohos.agp.components.element.Element;
+import ohos.utils.net.Uri;
import java.text.Collator;
import java.util.Comparator;
@@ -25,23 +23,17 @@ public abstract class Chip {
/* Any king of extra data that might be used */
private Object mTag;
/* Specifies if this Chip can be filtered or not */
- private boolean mFilterable;
+ private boolean isFilterable;
-
- @Nullable
public abstract Object getId();
- @NonNull
public abstract String getTitle();
- @Nullable
public abstract String getSubtitle();
- @Nullable
public abstract Uri getAvatarUri();
- @Nullable
- public abstract Drawable getAvatarDrawable();
+ public abstract Element getAvatarDrawable();
/**
* Lazy loads a comparator to compare chips to each other.
@@ -70,11 +62,11 @@ public abstract class Chip {
this.mTag = tag;
}
- public void setFilterable(boolean value) {
- this.mFilterable = value;
+ public void setFilterable(boolean isValue) {
+ this.isFilterable = isValue;
}
public boolean isFilterable() {
- return mFilterable;
+ return isFilterable;
}
}
\ No newline at end of file
diff --git a/library/src/main/java/com/tylersuehr/chips/ChipDataSource.java b/library/src/main/java/com/tylersuehr/chips/ChipDataSource.java
index e71adea81932c258d8bf6d0be2835c10ad33888c..cb0086d32d111b9e062d115f03e657e5f7d71284 100644
--- a/library/src/main/java/com/tylersuehr/chips/ChipDataSource.java
+++ b/library/src/main/java/com/tylersuehr/chips/ChipDataSource.java
@@ -1,4 +1,5 @@
package com.tylersuehr.chips;
+
import java.util.List;
/**
@@ -34,39 +35,28 @@ public interface ChipDataSource {
List getSelectedChips();
List getFilteredChips();
List getOriginalChips();
-
Chip getFilteredChip(int position);
Chip getSelectedChip(int position);
-
void setFilterableChips(List extends Chip> chips);
-
void takeChip(Chip chip);
void takeChip(int position);
-
void replaceChip(Chip chip);
void replaceChip(int position);
-
void addFilteredChip(Chip chip);
void addSelectedChip(Chip chip);
-
void clearFilteredChips();
void clearSelectedChips();
-
boolean existsInFiltered(Chip chip);
boolean existsInSelected(Chip chip);
boolean existsInDataSource(Chip chip);
-
void addSelectionObserver(SelectionObserver observer);
void removeSelectionObserver(SelectionObserver observer);
void removeAllSelectionObservers();
-
void addChangedObserver(ChangeObserver observer);
void removeChangedObserver(ChangeObserver observer);
void removeAllChangedObservers();
-
void cloneObservers(ChipDataSource to);
-
/**
* Defines an observer that wants to watch for any kind of overall
* change to this data source.
diff --git a/library/src/main/java/com/tylersuehr/chips/ChipDetailsView.java b/library/src/main/java/com/tylersuehr/chips/ChipDetailsView.java
index addf4fb146811b50a41f358959bb795fd3c618c8..4f4dbd617d97e097fe607792b7026c3f1cb57db1 100644
--- a/library/src/main/java/com/tylersuehr/chips/ChipDetailsView.java
+++ b/library/src/main/java/com/tylersuehr/chips/ChipDetailsView.java
@@ -1,99 +1,127 @@
+/**
+ * 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.tylersuehr.chips;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.constraint.ConstraintLayout;
-import android.support.v4.content.ContextCompat;
-import android.view.View;
-import android.view.animation.AlphaAnimation;
-import android.widget.FrameLayout;
-import android.widget.ImageButton;
-import android.widget.TextView;
+
+import ohos.agp.colors.RgbColor;
+import ohos.agp.components.*;
+import ohos.agp.components.element.ShapeElement;
+import ohos.agp.utils.Color;
+import ohos.app.Context;
/**
* Copyright © 2017 Tyler Suehr
- *
+ *
* This view displays the details of a chip (specified in Google Material Design Guide).
*
* @author Tyler Suehr
* @version 1.0
*/
-public class ChipDetailsView extends FrameLayout implements ChipComponent {
+public class ChipDetailsView extends StackLayout implements ChipComponent {
private ChipImageRenderer mImageRenderer;
+ private Text mTitleView;
+ private Text mText;
+ private Text mLabelView;
+ private Button mButtonDelete;
+ private Image mAvatarView;
+ private DependentLayout mContentLayout;
+ private final StackLayout mheader;
- private TextView mTitleView;
- private TextView mLabelView;
- private ImageButton mButtonDelete;
- private CircleImageView mAvatarView;
- private ConstraintLayout mContentLayout;
-
-
- ChipDetailsView(@NonNull Context context) {
+ /**
+ * ChipDetailsView
+ *
+ * @param context context
+ * @param text text
+ * @param tag tag
+ */
+ public ChipDetailsView(Context context, String text, Double tag) {
super(context);
- View v = inflate(context, R.layout.chip_view_detailed, this);
- mContentLayout = v.findViewById(R.id.container);
- mAvatarView = v.findViewById(R.id.avatar);
- mTitleView = v.findViewById(R.id.title);
- mLabelView = v.findViewById(R.id.subtitle);
- mButtonDelete = v.findViewById(R.id.button_delete);
-
- setVisibility(GONE);
-
+ Component component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_chip_view_detailed, null, false);
+ addComponent(component);
+ mheader = (StackLayout) component.findComponentById(ResourceTable.Id_header);
+ mContentLayout = (DependentLayout) component.findComponentById(ResourceTable.Id_container);
+ mAvatarView = (Image) component.findComponentById(ResourceTable.Id_avatar);
+ mText = (Text) component.findComponentById(ResourceTable.Id_text);
+ mTitleView = (Text) component.findComponentById(ResourceTable.Id_title);
+ mLabelView = (Text) component.findComponentById(ResourceTable.Id_subtitle);
+ mButtonDelete = (Button) component.findComponentById(ResourceTable.Id_button_delete);
// Hide the view on touch outside of it by making it focusable.
- setFocusable(true);
- setFocusableInTouchMode(true);
+ mText.setText(text.substring(0, 1));
+ mTitleView.setText(text);
+ ShapeElement background = new ShapeElement();
+ background.setCornerRadius(100);
+ if (0 == tag) {
+ background.setRgbColor(new RgbColor(249, 164, 61));
+ } else if (1 == tag) {
+ background.setRgbColor(new RgbColor(241, 99, 101));
+ } else if (2 == tag) {
+ background.setRgbColor(new RgbColor(34, 147, 205));
+ } else if (3 == tag) {
+ background.setRgbColor(new RgbColor(228, 198, 46));
+ } else if (4 == tag) {
+ background.setRgbColor(new RgbColor(173, 98, 167));
+ } else if (5 == tag) {
+ background.setRgbColor(new RgbColor(123, 113, 206));
+ } else if (6 == tag) {
+ background.setRgbColor(new RgbColor(123, 113, 206));
+ } else if (7 == tag) {
+ background.setRgbColor(new RgbColor(123, 113, 19));
+ } else {
+ background.setRgbColor(new RgbColor(21, 255, 236));
+ }
+ mheader.setBackground(background);
+ setFocusable(FOCUS_ENABLE);
setClickable(true);
}
@Override
public void setChipOptions(ChipOptions options) {
- // Set background color, if possible
if (options.mDetailsChipBackgroundColor != null) {
- mContentLayout.getBackground().setColorFilter(
- options.mDetailsChipBackgroundColor.getDefaultColor(),
- PorterDuff.Mode.SRC_ATOP);
}
- // Set an available text color
if (options.mDetailsChipTextColor != null) {
- mTitleView.setTextColor(options.mDetailsChipTextColor);
- mLabelView.setTextColor(options.mDetailsChipTextColor);
- } else if (Utils.isColorDark(getBackgroundColor())) {
- mTitleView.setTextColor(ColorStateList.valueOf(Color.WHITE));
- mLabelView.setTextColor(ColorStateList.valueOf(Color.WHITE));
+ mTitleView.setTextColor(new Color(Color.getIntColor("#757575")));
+ mLabelView.setTextColor(new Color(Color.getIntColor("#757575")));
} else {
- mTitleView.setTextColor(ColorStateList.valueOf(Color.BLACK));
- mLabelView.setTextColor(ColorStateList.valueOf(Color.BLACK));
+ mTitleView.setTextColor(Color.BLACK);
+ mLabelView.setTextColor(Color.BLACK);
}
+ ShapeElement shapeElement = new ShapeElement();
+ shapeElement.setRgbColor(RgbColor.fromRgbaInt(255));
// Set an available delete icon
if (options.mChipDeleteIcon != null) {
- mButtonDelete.setImageDrawable(options.mChipDeleteIcon);
- } else if (Utils.isColorDark(getBackgroundColor())) {
- mButtonDelete.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
+ mButtonDelete.setBackground(shapeElement);
} else {
- mButtonDelete.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_ATOP);
+ mTitleView.setTextColor(Color.BLACK);
+ mLabelView.setTextColor(Color.BLACK);
}
- mTitleView.setTypeface(options.mTypeface);
- mLabelView.setTypeface(options.mTypeface);
-
mImageRenderer = options.mImageRenderer;
}
/**
* Displays the information stored in the given chip object.
+ *
* @param chip {@link Chip}
*/
public void inflateWithChip(Chip chip) {
// Set the title and subtitle
mTitleView.setText(chip.getTitle());
if (chip.getSubtitle() == null) {
- mLabelView.setVisibility(GONE);
+ mLabelView.setVisibility(HIDE);
} else {
mLabelView.setText(chip.getSubtitle());
}
@@ -105,66 +133,8 @@ public class ChipDetailsView extends FrameLayout implements ChipComponent {
mImageRenderer.renderAvatar(mAvatarView, chip);
}
- /**
- * Fades this view in using alpha animation.
- */
- public void fadeIn() {
- AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
- anim.setDuration(200);
- startAnimation(anim);
- setVisibility(VISIBLE);
-
- // Force this view to hide when it loses focus
- setOnFocusChangeListener(new OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (!hasFocus) {
- fadeOut();
- setOnFocusChangeListener(null);
- }
- }
- });
-
- requestFocus();
- }
-
- /**
- * Fades this view out using alpha animation.
- */
- public void fadeOut() {
- AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f);
- anim.setDuration(200);
- startAnimation(anim);
- setVisibility(GONE);
-
- // Fix onClick issue
- clearFocus();
- setClickable(false);
- }
-
- public void alignLeft() {
- LayoutParams params = (LayoutParams)mContentLayout.getLayoutParams();
- params.leftMargin = 0;
- mContentLayout.setLayoutParams(params);
- }
-
- public void alignRight() {
- LayoutParams params = (LayoutParams)mContentLayout.getLayoutParams();
- params.rightMargin = 0;
- mContentLayout.setLayoutParams(params);
- }
-
- public void setOnDeleteClicked(OnClickListener onClickListener) {
- mButtonDelete.setOnClickListener(onClickListener);
- }
-
- private int getBackgroundColor() {
- final Drawable dr = mContentLayout.getBackground();
- if (dr == null || !(dr instanceof ColorDrawable)) {
- return ContextCompat.getColor(getContext(),
- R.color.chip_details_background);
- } else {
- return ((ColorDrawable)dr).getColor();
- }
+ public void setOnDeleteClicked(ClickedListener onClickListener) {
+ mButtonDelete.setClickedListener(onClickListener);
+ mContentLayout.setClickedListener(onClickListener);
}
}
\ No newline at end of file
diff --git a/library/src/main/java/com/tylersuehr/chips/ChipImageRenderer.java b/library/src/main/java/com/tylersuehr/chips/ChipImageRenderer.java
index 731629b6d354a4f68b5162fc38898cf7bee5431e..f52eb60d6a81840f5de703be6c929424b54e9537 100644
--- a/library/src/main/java/com/tylersuehr/chips/ChipImageRenderer.java
+++ b/library/src/main/java/com/tylersuehr/chips/ChipImageRenderer.java
@@ -1,12 +1,12 @@
package com.tylersuehr.chips;
-import android.widget.ImageView;
+import ohos.agp.components.Image;
/**
* Copyright © 2017 Tyler Suehr
- *
+ *
* Defines a renderer for chip avatar images.
- *
+ *
* Implementations of this can used to do things like using libraries,
* such as Picasso or Glide, to load the image for you.
*
@@ -14,5 +14,5 @@ import android.widget.ImageView;
* @version 1.0
*/
public interface ChipImageRenderer {
- void renderAvatar(ImageView imageView, Chip chip);
+ void renderAvatar(Image imageView, Chip chip);
}
\ No newline at end of file
diff --git a/library/src/main/java/com/tylersuehr/chips/ChipOptions.java b/library/src/main/java/com/tylersuehr/chips/ChipOptions.java
index 9d266de00c322c9324194a6ef083374771c044ac..c0f695a67aed1c4bd5b55431ac27d02d67c20f90 100644
--- a/library/src/main/java/com/tylersuehr/chips/ChipOptions.java
+++ b/library/src/main/java/com/tylersuehr/chips/ChipOptions.java
@@ -1,103 +1,44 @@
package com.tylersuehr.chips;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.util.AttributeSet;
+
+import ohos.agp.components.AttrSet;
+import ohos.agp.components.element.Element;
+import ohos.agp.components.element.StateElement;
+import ohos.app.Context;
/**
* Copyright © 2017 Tyler Suehr
- *
+ *
* Contains all the mutable properties for this library.
*
* @author Tyler Suehr
* @version 1.0
*/
final class ChipOptions {
- /* Properties pertaining to ChipsEditText */
- ColorStateList mTextColorHint;
- ColorStateList mTextColor;
+ StateElement mTextColorHint;
+ StateElement mTextColor;
CharSequence mHint;
-
- /* Properties pertaining to ChipView */
- Drawable mChipDeleteIcon;
- ColorStateList mChipDeleteIconColor;
- ColorStateList mChipBackgroundColor;
- ColorStateList mChipTextColor;
+ Element mChipDeleteIcon;
+ StateElement mChipDeleteIconColor;
+ StateElement mChipBackgroundColor;
+ StateElement mChipTextColor;
boolean mShowAvatar;
boolean mShowDetails;
boolean mShowDelete;
-
- /* Properties pertaining to ChipDetailsView */
- ColorStateList mDetailsChipDeleteIconColor;
- ColorStateList mDetailsChipBackgroundColor;
- ColorStateList mDetailsChipTextColor;
-
- /* Properties pertaining to FilterableRecyclerView */
- ColorStateList mFilterableListBackgroundColor;
- ColorStateList mFilterableListTextColor;
+ StateElement mDetailsChipDeleteIconColor;
+ StateElement mDetailsChipBackgroundColor;
+ StateElement mDetailsChipTextColor;
+ StateElement mFilterableListBackgroundColor;
+ StateElement mFilterableListTextColor;
float mFilterableListElevation;
-
int mTextAppearanceIdRes;
-
- /* Properties pertaining to the ChipsInputLayout itself */
- Typeface mTypeface = Typeface.DEFAULT;
boolean mAllowCustomChips;
boolean mHideKeyboardOnChipClick;
int mMaxRows;
String mDelimiter;
boolean mDelimiterRegex;
-
- @NonNull
ChipImageRenderer mImageRenderer;
-
- ChipOptions(Context c, AttributeSet attrs, int defStyleAttr) {
- // Set defaults
+ ChipOptions(Context c, AttrSet attrSet, int defStyleAttr) {
mImageRenderer = new DefaultImageRenderer();
-
- // Set the XML attributes
- TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ChipsInputLayout);
-
- // Setup the properties for the ChipEditText
- mTextColorHint = a.getColorStateList(R.styleable.ChipsInputLayout_android_textColorHint);
- mTextColor = a.getColorStateList(R.styleable.ChipsInputLayout_android_textColor);
- mHint = a.getString(R.styleable.ChipsInputLayout_android_hint);
-
- // Setup the properties for the ChipView
- mShowDetails = a.getBoolean(R.styleable.ChipsInputLayout_chip_showDetails, true);
- mShowAvatar = a.getBoolean(R.styleable.ChipsInputLayout_chip_showAvatar, true);
- mShowDelete = a.getBoolean(R.styleable.ChipsInputLayout_chip_showDelete, true);
- mChipDeleteIcon = a.getDrawable(R.styleable.ChipsInputLayout_chip_deleteIcon);
- mChipDeleteIconColor = a.getColorStateList(R.styleable.ChipsInputLayout_chip_deleteIconColor);
- mChipBackgroundColor = a.getColorStateList(R.styleable.ChipsInputLayout_chip_backgroundColor);
- mChipTextColor = a.getColorStateList(R.styleable.ChipsInputLayout_chip_textColor);
-
- // Setup the properties for the DetailedChipView
- mDetailsChipDeleteIconColor = a.getColorStateList(R.styleable.ChipsInputLayout_details_deleteIconColor);
- mDetailsChipBackgroundColor = a.getColorStateList(R.styleable.ChipsInputLayout_chip_backgroundColor);
- mDetailsChipTextColor = a.getColorStateList(R.styleable.ChipsInputLayout_details_textColor);
-
- // Setup the properties for the FilterableRecyclerView
- mFilterableListElevation = a.getDimension(R.styleable.ChipsInputLayout_filter_elevation, R.dimen.chip_open_elevation);
- mFilterableListBackgroundColor = a.getColorStateList(R.styleable.ChipsInputLayout_filter_backgroundColor);
- mFilterableListTextColor = a.getColorStateList(R.styleable.ChipsInputLayout_filter_textColor);
-
- // Setup the properties for the ChipsInput itself
- mAllowCustomChips = a.getBoolean(R.styleable.ChipsInputLayout_allowCustomChips, true);
- mHideKeyboardOnChipClick = a.getBoolean(R.styleable.ChipsInputLayout_hideKeyboardOnChipClick, true);
- mMaxRows = a.getInt(R.styleable.ChipsInputLayout_maxRows, 3);
- mDelimiter = a.getString(R.styleable.ChipsInputLayout_delimiter);
- mDelimiterRegex = a.getBoolean(R.styleable.ChipsInputLayout_delimiterRegex, false);
-
- a.recycle();
-
- // Set the styleable attributes
- final int[] styleable = new int[] { android.R.attr.textAppearance };
- a = c.obtainStyledAttributes(attrs, styleable, defStyleAttr, 0);
- mTextAppearanceIdRes = a.getResourceId(0, android.R.attr.textAppearanceMedium);
- a.recycle();
}
}
diff --git a/library/src/main/java/com/tylersuehr/chips/ChipView.java b/library/src/main/java/com/tylersuehr/chips/ChipView.java
index 86b48623df3af69a0173181f4c01822558d162d7..55be0bfb643e35772d0e734aa28ec13677f901ab 100644
--- a/library/src/main/java/com/tylersuehr/chips/ChipView.java
+++ b/library/src/main/java/com/tylersuehr/chips/ChipView.java
@@ -1,12 +1,7 @@
package com.tylersuehr.chips;
-import android.content.Context;
-import android.graphics.PorterDuff;
-import android.support.annotation.NonNull;
-import android.support.constraint.ConstraintLayout;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageButton;
-import android.widget.TextView;
+
+import ohos.agp.components.*;
+import ohos.app.Context;
/**
* Copyright © 2017 Tyler Suehr
@@ -16,21 +11,20 @@ import android.widget.TextView;
* @author Tyler Suehr
* @version 1.0
*/
-public class ChipView extends FrameLayout implements ChipComponent {
+public class ChipView extends StackLayout implements ChipComponent {
private ChipImageRenderer mImageRenderer;
-
private CircleImageView mAvatarView;
- private ImageButton mButtonDelete;
- private TextView mLabelView;
+ private Button mButtonDelete;
+ private Text mLabelView;
private Chip mChip;
-
- ChipView(@NonNull Context context) {
+ public ChipView(Context context) {
super(context);
- inflate(context, R.layout.chip_view, this);
- mAvatarView = findViewById(R.id.avatar);
- mLabelView = findViewById(R.id.label);
- mButtonDelete = findViewById(R.id.button_delete);
+ Component component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_chip_view, null, false);
+ addComponent(component);
+ mAvatarView = (CircleImageView) component.findComponentById(ResourceTable.Id_avatar);
+ mLabelView = (Text) component.findComponentById(ResourceTable.Id_label);
+ mButtonDelete = (Button) component.findComponentById(ResourceTable.Id_button_delete);
}
@Override
@@ -38,43 +32,20 @@ public class ChipView extends FrameLayout implements ChipComponent {
// Options will permit showing/hiding avatar
if (!options.mShowAvatar) {
// Hide the avatar image
- mAvatarView.setVisibility(GONE);
-
- // Adjust left label margins according to the
- // Google Material Design Guide.
- ConstraintLayout.LayoutParams lp = (ConstraintLayout
- .LayoutParams)mLabelView.getLayoutParams();
- lp.leftMargin = (int)(12f * getResources().getDisplayMetrics().density);
+ mAvatarView.setVisibility(HIDE);
+ LayoutConfig config = (LayoutConfig) mLabelView.getLayoutConfig();
}
// Options will permit showing/hiding delete button
if (!options.mShowDelete) {
// Hide the delete button
- mButtonDelete.setVisibility(GONE);
+ mButtonDelete.setVisibility(HIDE);
// Adjust right label margins according to the
// Google Material Design Guide.
- ConstraintLayout.LayoutParams lp = (ConstraintLayout
- .LayoutParams)mLabelView.getLayoutParams();
- lp.rightMargin = (int)(12f * getResources().getDisplayMetrics().density);
+ LayoutConfig config = (LayoutConfig) mLabelView.getLayoutConfig();
}
- // Set other options
- if (options.mChipDeleteIcon != null) {
- mButtonDelete.setImageDrawable(options.mChipDeleteIcon);
- }
- if (options.mChipBackgroundColor != null) {
- setBackgroundColor(options.mChipBackgroundColor.getDefaultColor());
- }
- if (options.mChipDeleteIconColor != null) {
- mButtonDelete.setColorFilter(options.mChipDeleteIconColor
- .getDefaultColor(), PorterDuff.Mode.SRC_ATOP);
- }
- if (options.mChipTextColor != null) {
- mLabelView.setTextColor(options.mChipTextColor);
- }
- mLabelView.setTypeface(options.mTypeface);
-
mImageRenderer = options.mImageRenderer;
}
@@ -101,13 +72,13 @@ public class ChipView extends FrameLayout implements ChipComponent {
* @param listener {@link OnChipClickListener}
*/
public void setOnChipClicked(final OnChipClickListener listener) {
- final View child = getChildAt(0);
+ final Component child = getComponentAt(0);
if (listener == null) {
- child.setOnClickListener(null);
+ child.setClickedListener(null);
} else {
- child.setOnClickListener(new OnClickListener() {
+ child.setClickedListener(new ClickedListener() {
@Override
- public void onClick(View v) {
+ public void onClick(Component component) {
listener.onChipClicked(ChipView.this);
}
});
@@ -119,15 +90,14 @@ public class ChipView extends FrameLayout implements ChipComponent {
* @param listener {@link OnChipDeleteListener}
*/
public void setOnDeleteClicked(final OnChipDeleteListener listener) {
- mButtonDelete.setOnClickListener(new OnClickListener() {
+ mButtonDelete.setClickedListener(new ClickedListener() {
@Override
- public void onClick(View v) {
+ public void onClick(Component component) {
listener.onChipDeleted(ChipView.this);
}
});
}
-
/**
* Defines callbacks for chip click events.
*/
diff --git a/library/src/main/java/com/tylersuehr/chips/ChipsAdapter.java b/library/src/main/java/com/tylersuehr/chips/ChipsAdapter.java
deleted file mode 100644
index 9286f9cae4760c2fa91717ec01d9a657ca8fc102..0000000000000000000000000000000000000000
--- a/library/src/main/java/com/tylersuehr/chips/ChipsAdapter.java
+++ /dev/null
@@ -1,253 +0,0 @@
-package com.tylersuehr.chips;
-import android.support.v7.widget.RecyclerView;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.RelativeLayout;
-
-/**
- * Copyright © 2017 Tyler Suehr
- *
- * Subclass of {@link RecyclerView.Adapter} to adapt the selected chips into views
- * and display an input (EditText) to allow the user to type text in for chips.
- *
- * This adapter should afford the following abilities/features:
- * (1) Allow user to create custom chips, if the options permit it.
- * (2) Allow user to remove any chip by pressing delete on an empty input.
- * (3) Allow the user to see chip details, if the options permit it.
- *
- * This observes changes to {@link ChipDataSource} to update the UI accordingly.
- *
- * @author Tyler Suehr
- * @version 1.0
- */
-class ChipsAdapter
- extends RecyclerView.Adapter
- implements ChipsEditText.OnKeyboardListener, ChipDataSource.ChangeObserver {
- private static final int CHIP = 0;
- private static final int INPUT = 1;
-
- private final ChipDataSource mDataSource;
- private final ChipOptions mOptions;
- private final ChipsEditText mEditText;
-
-
- ChipsAdapter(ChipDataSource dataSource,
- ChipsEditText editText,
- ChipOptions options) {
- mDataSource = dataSource;
- mEditText = editText;
- mOptions = options;
- mEditText.setKeyboardListener(this);
-
- // Register an observer on the chip data source
- mDataSource.addChangedObserver(this);
- }
-
- @Override
- public int getItemViewType(int position) {
- return position < mDataSource
- .getSelectedChips().size() ? CHIP : INPUT;
- }
-
- @Override
- public int getItemCount() {
- // Plus 1 for the edit text
- return mDataSource.getSelectedChips().size() + 1;
- }
-
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return viewType == CHIP
- ? new ChipHolder(new ChipView(parent.getContext()))
- : new RecyclerView.ViewHolder(mEditText) {};
- }
-
- @Override
- public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
- if (getItemViewType(position) == CHIP) { // Chips
- // Display the chip information on the chip view
- final ChipHolder ch = (ChipHolder)holder;
- ch.chipView.inflateFromChip(mDataSource.getSelectedChip(position));
- } else { // EditText
- if (mDataSource.getSelectedChips().size() == 0) {
- mEditText.setHint(mOptions.mHint);
- }
-
- // Resize the edit text to fit in recycler
- autoFitEditText();
- }
- }
-
- /**
- * Called when the IME_ACTION_DONE option is pressed on a software or
- * physical keyboard.
- *
- * @param text Current text in the EditText
- */
- @Override
- public void onKeyboardActionDone(String text) {
- if (TextUtils.isEmpty(text) || !mOptions.mAllowCustomChips) { return; }
-
- // Clear the input before taking chip so we don't need to update UI twice
- mEditText.setText("");
-
- // This will trigger callback, which calls notifyDataSetChanged()
- mDataSource.addSelectedChip(new DefaultCustomChip(text));
- }
-
- /**
- * Called when the backspace (KEYCODE_DEL) is pressed on a software or
- * physical keyboard.
- */
- @Override
- public void onKeyboardBackspace() {
- // Only remove the last chip if the input was empty
- if (mDataSource.getSelectedChips().size() > 0
- && mEditText.getText().length() == 0) {
- // Will trigger notifyDataSetChanged()
- mDataSource.replaceChip(mDataSource.getSelectedChips().size() - 1);
- }
- }
-
- @Override
- public void onChipDataSourceChanged() {
- notifyDataSetChanged();
- }
-
- private void autoFitEditText() {
- // Set the EditText to a minimum width of its hint length
- ViewGroup.LayoutParams lp = mEditText.getLayoutParams();
- lp.width = (int)mEditText.calculateTextWidth();
- mEditText.setLayoutParams(lp);
-
- // Listen to changes in the tree
- mEditText.getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- // Get right of recycler and left of edit text
- final View parent = (View)mEditText.getParent();
- int right = parent.getRight();
- int left = mEditText.getLeft();
-
- // Calculate the available space left to draw the EditText,
- // and only readjust the EditText when the available space
- // is larger than the needed space.
- //
- // This will allow the full text hint to always be visible
- // by ensuring the EditText gets wrapped to the next line
- // if it can't fit in the available space.
- final int available = (right - left - Utils.dp(8));
- ViewGroup.LayoutParams lp = mEditText.getLayoutParams();
- if (lp.width < available) {
- lp.width = available;
- mEditText.setLayoutParams(lp);
- }
-
- // Request focus
- mEditText.requestFocus();
- mEditText.setFocusableInTouchMode(true);
- // Remove the tree listener
- mEditText.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- }
- });
- }
-
- private void showDetailedChipView(ChipView view, Chip chip, final int position) {
- // Get chip view's location
- int[] coord = new int[2];
- view.getLocationInWindow(coord);
-
- // Create a detailed chip view to show
- final ChipDetailsView detailedChipView = new ChipDetailsView(view.getContext());
- detailedChipView.setChipOptions(mOptions);
- detailedChipView.inflateWithChip(chip);
-
- // Setup the location in window of the detailed chip
- setDetailedChipViewPosition(detailedChipView, coord);
-
- // Remove the detailed chip when delete button is pressed
- detailedChipView.setOnDeleteClicked(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // Will trigger notifyDataSetChanged()
- mDataSource.replaceChip(position);
- detailedChipView.fadeOut();
- }
- });
- }
-
- private void setDetailedChipViewPosition(final ChipDetailsView detailedChipView, int[] coord) {
- // Window width
- final ViewGroup rootView = (ViewGroup)mEditText.getRootView();
- int windowWidth = Utils.getWindowWidth(rootView.getContext());
-
- // Chip size
- RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
- Utils.dp(300),
- Utils.dp(100)
- );
- lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
- lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
-
- // Determine the detailed chip's alignment inside the window
- if (coord[0] <= 0) { // Left align
- lp.leftMargin = 0;
- lp.topMargin = coord[1] - Utils.dp(13);
- detailedChipView.alignLeft();
- } else if (coord[0] + Utils.dp(300) > windowWidth + Utils.dp(13)) { // Right align
- lp.leftMargin = windowWidth - Utils.dp(300);
- lp.topMargin = coord[1] - Utils.dp(13);
- detailedChipView.alignRight();
- } else { // Same position as chip
- lp.leftMargin = coord[0] - Utils.dp(13);
- lp.topMargin = coord[1] - Utils.dp(13);
- }
-
- // Show the detailed chip view
- rootView.addView(detailedChipView, lp);
- detailedChipView.fadeIn();
- }
-
-
- /**
- * Nested inner-subclass of {@link RecyclerView.ViewHolder} that stores
- * reference to the a chip view.
- */
- private class ChipHolder extends RecyclerView.ViewHolder implements
- ChipView.OnChipClickListener, ChipView.OnChipDeleteListener {
- ChipView chipView;
-
- ChipHolder(ChipView chipView) {
- super(chipView);
- this.chipView = chipView;
- this.chipView.setChipOptions(mOptions);
- this.chipView.setOnDeleteClicked(this);
- if (mOptions.mShowDetails) {
- this.chipView.setOnChipClicked(this);
- } else {
- this.chipView.setOnChipClicked(null);
- }
- }
-
- @Override
- public void onChipClicked(ChipView v) {
- final int position = getAdapterPosition();
- if (position > -1) {
- final Chip chip = mDataSource.getSelectedChip(position);
- showDetailedChipView(v, chip, position);
- }
- }
-
- @Override
- public void onChipDeleted(ChipView v) {
- // Will trigger notifyDataSetChanged()
- final int position = getAdapterPosition();
- if (position > -1){
- mDataSource.replaceChip(position);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/library/src/main/java/com/tylersuehr/chips/ChipsEditText.java b/library/src/main/java/com/tylersuehr/chips/ChipsEditText.java
deleted file mode 100644
index 9f3c518319f6eb7c1ab494f29cc8e087e3195d47..0000000000000000000000000000000000000000
--- a/library/src/main/java/com/tylersuehr/chips/ChipsEditText.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.tylersuehr.chips;
-import android.content.Context;
-import android.graphics.Paint;
-import android.support.v7.widget.AppCompatEditText;
-import android.text.InputType;
-import android.view.KeyEvent;
-import android.view.ViewGroup;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputConnectionWrapper;
-import android.widget.RelativeLayout;
-
-/**
- * Copyright © 2017 Tyler Suehr
- *
- * Subclass of {@link AppCompatEditText} that provides a solution for detecting both
- * the IME_ACTION_DONE and backspace key press on software keyboards.
- *
- * Setting onKeyEventListener doesn't work on software keyboards (IME) :(
- *
- * TODO: Also try to simplify text watcher crap with this as well
- *
- * @author Tyler Suehr
- * @version 1.0
- */
-public class ChipsEditText extends AppCompatEditText implements ChipComponent {
- private OnKeyboardListener mKeyboardListener;
-
-
- ChipsEditText(Context c) {
- super(c);
- setBackgroundResource(android.R.color.transparent);
- setLayoutParams(new RelativeLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- ));
-
- int padding = Utils.dp(8);
- setPadding(padding, padding, padding, padding);
-
- // Prevent fullscreen on landscape
- setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI
- |EditorInfo.IME_ACTION_DONE);
- setPrivateImeOptions("nm");
-
- // No suggestions
- setInputType(InputType.TYPE_TEXT_VARIATION_FILTER
- |InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
- }
-
- /**
- * Used to detect IME option press on any type of input method.
- */
- @Override
- public void onEditorAction(int actionCode) {
- if (mKeyboardListener != null && actionCode == EditorInfo.IME_ACTION_DONE) {
- this.mKeyboardListener.onKeyboardActionDone(getText().toString());
- }
- super.onEditorAction(actionCode);
- }
-
- @Override
- public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
- return new ChipsInputConnection(super.onCreateInputConnection(outAttrs));
- }
-
- @Override
- public void setChipOptions(ChipOptions options) {
- if (options.mTextColorHint != null) {
- setHintTextColor(options.mTextColorHint);
- }
- if (options.mTextColor != null) {
- setTextColor(options.mTextColor);
- }
- setHint(options.mHint);
- setTypeface(options.mTypeface);
- setTextAppearance(getContext(), options.mTextAppearanceIdRes);
- }
-
- float calculateTextWidth() {
- final Paint paint = getPaint();
- final String hint = getHint().toString();
- return paint.measureText(hint);
- }
-
- void setKeyboardListener(OnKeyboardListener listener) {
- mKeyboardListener = listener;
- }
-
- OnKeyboardListener getKeyboardListener() {
- return mKeyboardListener;
- }
-
-
- /**
- * Callbacks for simplified keyboard action events.
- */
- interface OnKeyboardListener {
- void onKeyboardBackspace();
- void onKeyboardActionDone(String text);
- }
-
-
- /**
- * Since we cannot detect software keyboard backspace (KEYCODE_DEL) events using
- * onKeyEventListener, we will use this wrapper for {@link InputConnection} to do
- * so for software keyboards.
- *
- * In the latest Android version, deleteSurroundingText(1, 0), will be called for
- * backspace. So, we just emulate a backspace key press if that method is called
- * by manually calling {@link #sendKeyEvent(KeyEvent)}.
- */
- private final class ChipsInputConnection extends InputConnectionWrapper {
- private ChipsInputConnection(InputConnection target) {
- super(target, true);
- }
-
- @Override
- public boolean sendKeyEvent(KeyEvent event) {
- if (mKeyboardListener != null) {
- if (event.getAction() == KeyEvent.ACTION_DOWN
- && event.getKeyCode() == KeyEvent.KEYCODE_DEL) { // Backspace key
- mKeyboardListener.onKeyboardBackspace();
- }
- }
- return super.sendKeyEvent(event);
- }
-
- @Override
- public boolean deleteSurroundingText(int beforeLength, int afterLength) {
- if (beforeLength == 1 && afterLength == 0) { // Backspace key
- return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
- && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
- }
- return super.deleteSurroundingText(beforeLength, afterLength);
- }
- }
-}
diff --git a/library/src/main/java/com/tylersuehr/chips/ChipsInputLayout.java b/library/src/main/java/com/tylersuehr/chips/ChipsInputLayout.java
deleted file mode 100644
index 2ae6c30318c7a4a0dde0c0828a376d68d1e31e61..0000000000000000000000000000000000000000
--- a/library/src/main/java/com/tylersuehr/chips/ChipsInputLayout.java
+++ /dev/null
@@ -1,728 +0,0 @@
-package com.tylersuehr.chips;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.support.annotation.DrawableRes;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.widget.RecyclerView;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.util.AttributeSet;
-import android.view.ViewGroup;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.RelativeLayout;
-import com.beloo.widget.chipslayoutmanager.ChipsLayoutManager;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * Copyright © 2017 Tyler Suehr
- *
- * Chips are a design concept specified in the Google Material Design Guide.
- *
- * The purpose of this view, and this library, is for displaying chips in a flowing
- * layout, and allowing the user to input to filter any filterable chips or to create
- * custom chips.
- *
- * Notes: by default, the chip data source is {@link ListChipDataSource}.
- *
- * @author Tyler Suehr
- * @version 1.0
- */
-public class ChipsInputLayout extends MaxHeightScrollView
- implements FilterableChipsAdapter.OnFilteredChipClickListener {
- /* Stores mutable properties for our library */
- private final ChipOptions mOptions;
- /* Stores the source of all the chips */
- private ChipDataSource mDataSource;
-
- public ChipsEditText getmChipsInput() {
- return mChipsInput;
- }
-
- /* Stores reference to the user input */
- public ChipsEditText mChipsInput;
-
- /* Displays selected chips and chips EditText */
- private final RecyclerView mChipsRecycler;
- private final ChipsAdapter mChipsAdapter;
-
- /* Displays filtered chips */
- private FilterableRecyclerView mFilteredRecycler;
- private FilterableChipsAdapter mFilteredAdapter;
-
- /* Stores reference to callback for text changed events */
- private OnChipsInputTextChangedListener mTextChangedListener;
- /* Used to validate selected chips */
- private ChipValidator mValidator;
-
-
- public ChipsInputLayout(Context context) {
- this(context, null);
- }
-
- public ChipsInputLayout(Context c, AttributeSet attrs) {
- this(c, attrs, 0);
- }
-
- public ChipsInputLayout(Context c, AttributeSet attrs, int defStyleAttr) {
- super(c, attrs, defStyleAttr);
- mOptions = new ChipOptions(c, attrs, defStyleAttr);
- mDataSource = new ListChipDataSource();
-
- // Inflate the view
- inflate(c, R.layout.chips_input_view, this);
-
- // Setup the chips recycler view
- mChipsAdapter = new ChipsAdapter(
- mDataSource, loadChipsInput(), mOptions);
- mChipsRecycler = findViewById(R.id.chips_recycler);
- mChipsRecycler.addItemDecoration(new DefaultChipDecor(c));
- mChipsRecycler.setLayoutManager(ChipsLayoutManager.newBuilder(c).build());
- mChipsRecycler.setNestedScrollingEnabled(false);
- mChipsRecycler.setAdapter(mChipsAdapter);
-
- // Set the max height from options
- setMaxHeight(Utils.dp(40) * mOptions.mMaxRows);
- }
-
- @Override
- public void onFilteredChipClick(Chip chip) {
- // Hide the filterable recycler
- mFilteredRecycler.fadeOut();
-
- // Clear the input and refresh the chips recycler
- mChipsInput.setText("");
-
- // Close the software keyboard
- if (mOptions.mHideKeyboardOnChipClick) {
- hideKeyboard();
- }
- }
-
- /**
- * Sets and stores a list of chips that are filterable and updates the
- * UI to enable the filterable RecyclerView accordingly.
- *
- * Note: this should only be called if you want the user to be able to
- * filter pre-existing (filterable chip list) chips.
- *
- * @param chips List of {@link Chip}
- */
- public void setFilterableChipList(List extends Chip> chips) {
- mDataSource.setFilterableChips(chips);
-
- // Setup the filterable recycler when new
- // filterable data has been set
- loadFilterableRecycler();
- }
-
- /**
- * Sets and stores a list of chips that are selected and updates the UI
- * to display them accordingly.
- *
- * @param chips List of {@link Chip}
- */
- public void setSelectedChipList(List extends Chip> chips) {
- // Set the selected chips in the data source
- mDataSource.getSelectedChips().clear();
- mDataSource.getSelectedChips().addAll(chips);
-
- // Update the chips UI display
- mChipsAdapter.notifyDataSetChanged();
- }
-
- /**
- * Adds a new chip to the filterable chips, which will update the UI
- * accordingly because of the change observers.
- *
- * @param chip {@link Chip}
- */
- public void addFilteredChip(Chip chip) {
- // Ensure that the chip is actually filterable
- chip.setFilterable(true);
-
- // Ensure that the chip is not already in the data source
- if (mDataSource.existsInDataSource(chip)) {
- throw new IllegalArgumentException("Chip already exists in the data source!");
- }
-
- // Using the method on data source will update UI
- mDataSource.addFilteredChip(chip);
-
- // Create the filterable recycler at this point, if needed
- loadFilterableRecycler();
- }
-
- /**
- * Adds a new chip to the selected chips, which will update the UI
- * accordingly because of the change observers.
- *
- * @param chip {@link Chip}
- */
- public void addSelectedChip(Chip chip) {
- // Ensure that the chip is not already in the data source
- if (mDataSource.existsInDataSource(chip)) {
- throw new IllegalArgumentException("Chip already exists in the data source!");
- }
-
- // Using the method on data source will update UI
- mDataSource.addSelectedChip(chip);
- }
-
- /**
- * Clears all the filterable chips, which will update the UI accordingly
- * because of the change observers.
- */
- public void clearFilteredChips() {
- mDataSource.clearFilteredChips();
- }
-
- /**
- * Clears all the selected chips, which will update the UI accordingly
- * because of the change observers.
- */
- public void clearSelectedChips() {
- mDataSource.clearSelectedChips();
- }
-
- /**
- * Gets all the currently selected chips.
- *
- * @return List of {@link Chip}
- */
- public List extends Chip> getSelectedChips() {
- return mDataSource.getSelectedChips();
- }
-
- /**
- * Gets all the currently filtered chips.
- * @see #getOriginalFilterableChips() if you want the original list of chips
- *
- * @return List of {@link Chip}
- */
- public List extends Chip> getFilteredChips() {
- return mDataSource.getFilteredChips();
- }
-
- /**
- * Gets all the originally set filterable chips.
- *
- * @return List of {@link Chip}
- */
- public List extends Chip> getOriginalFilterableChips() {
- return mDataSource.getOriginalChips();
- }
-
- /**
- * Gets a selected chip using the given index.
- *
- * @param position Position of chip
- * @return {@link Chip}
- */
- public Chip getSelectedChipByPosition(int position) {
- return mDataSource.getSelectedChip(position);
- }
-
- /**
- * Gets a selected chip using the given ID, if possible.
- *
- * @param id ID of the selected chip
- * @return {@link Chip}
- */
- public Chip getSelectedChipById(Object id) {
- for (Chip chip : mDataSource.getSelectedChips()) {
- if (chip.getId() != null && chip.getId().equals(id)) {
- return chip;
- }
- }
- return null;
- }
-
- /**
- * Gets a selected chip with exactly the given title or like the given title.
- *
- * @param title Title to search for
- * @param exactlyEqual True if chip title should exactly match title
- * @return {@link Chip}
- */
- public Chip getSelectedChipByTitle(String title, boolean exactlyEqual) {
- for (Chip chip : mDataSource.getSelectedChips()) {
- if ((exactlyEqual && chip.getTitle().equals(title)) ||
- (!exactlyEqual && chip.getTitle().toLowerCase().contains(title.toLowerCase()))) {
- return chip;
- }
- }
- return null;
- }
-
- /**
- * Gets a selected chip with exactly the given subtitle or like the given subtitle.
- *
- * @param subtitle Subtitle to search for
- * @param exactlyEqual True if chip subtitle should exactly match subtitle
- * @return {@link Chip}
- */
- public Chip getSelectedChipBySubtitle(String subtitle, boolean exactlyEqual) {
- for (Chip chip : mDataSource.getSelectedChips()) {
- if (chip.getSubtitle() == null) { continue; }
- if ((exactlyEqual && chip.getSubtitle().equals(subtitle)) ||
- (!exactlyEqual && chip.getSubtitle().toLowerCase().contains(subtitle.toLowerCase()))) {
- return chip;
- }
- }
- return null;
- }
-
- /**
- * Gets a filtered chip using the given index.
- *
- * @param position Position of chip
- * @return {@link Chip}
- */
- public Chip getFilteredChipPosition(int position) {
- return mDataSource.getFilteredChip(position);
- }
-
- /**
- * Gets a filtered chip using the given ID, if possible.
- *
- * @param id Filtered chip's ID
- * @return {@link Chip}
- */
- public Chip getFilteredChipById(Object id) {
- for (Chip chip : mDataSource.getFilteredChips()) {
- if (chip.getId() != null && chip.getId().equals(id)) {
- return chip;
- }
- }
- return null;
- }
-
- /**
- * Gets a filtered chip with exactly the given title or like the given title.
- *
- * @param title Title to search for
- * @param exactlyEqual True if filtered chip title should exactly match title
- * @return {@link Chip}
- */
- public Chip getFilteredChipByTitle(String title, boolean exactlyEqual) {
- for (Chip chip : mDataSource.getFilteredChips()) {
- if ((exactlyEqual && chip.getTitle().equals(title)) ||
- (!exactlyEqual && chip.getTitle().toLowerCase().contains(title.toLowerCase()))) {
- return chip;
- }
- }
- return null;
- }
-
- /**
- * Gets a filtered chip with exactly the given subtitle or like the given subtitle.
- *
- * @param subtitle Subtitle to search for
- * @param exactlyEqual True if filtered chip subtitle should exactly match subtitle
- * @return {@link Chip}
- */
- public Chip getFilteredChipBySubtitle(String subtitle, boolean exactlyEqual) {
- for (Chip chip : mDataSource.getFilteredChips()) {
- if (chip.getSubtitle() == null) { continue; }
- if ((exactlyEqual && chip.getSubtitle().equals(subtitle)) ||
- (!exactlyEqual && chip.getSubtitle().toLowerCase().contains(subtitle.toLowerCase()))) {
- return chip;
- }
- }
- return null;
- }
-
- /**
- * Checks if the given chip exists in either the filterable or selected chips.
- *
- * @param chip {@link Chip}
- * @return True if chip exists in filterable or selected chips
- */
- public boolean doesChipExist(Chip chip) {
- return mDataSource.existsInDataSource(chip);
- }
-
- /**
- * Checks if the given chip exists in the filtered chips.
- *
- * @param chip {@link Chip}
- * @return True if chip exists in filtered chips
- */
- public boolean isChipFiltered(Chip chip) {
- return mDataSource.existsInFiltered(chip);
- }
-
- /**
- * Checks if the given chip exists in the selected chips.
- *
- * @param chip {@link Chip}
- * @return True if chip exists in selected chips
- */
- public boolean isChipSelected(Chip chip) {
- return mDataSource.existsInSelected(chip);
- }
-
- /**
- * Validates the given chip using {@link #mValidator}.
- *
- * @param chip {@link Chip}
- * @return True if chip is valid, or no chip mValidator is set
- */
- public boolean validateChip(Chip chip) {
- return mValidator == null || mValidator.validate(chip);
- }
-
- /**
- * Validates all the selected chips using {@link #mValidator}.
- *
- * @return True if all selected chips are valid, or no chip mValidator is set
- */
- public boolean validateSelectedChips() {
- if (mValidator != null) {
- for (Chip chip : mDataSource.getSelectedChips()) {
- if (!mValidator.validate(chip)) {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Sets the chip mValidator to valid chips.
- *
- * @param validator {@link ChipValidator}
- */
- public void setChipValidator(ChipValidator validator) {
- mValidator = validator;
- }
-
- /**
- * Adds an observer to watch selection events on the chip data source.
- *
- * @param observer {@link ChipDataSource.SelectionObserver}
- */
- public void addSelectionObserver(ChipDataSource.SelectionObserver observer) {
- mDataSource.addSelectionObserver(observer);
- }
-
- /**
- * Removes an observer from watching selection events on the chip data source.
- *
- * @param observer {@link ChipDataSource.SelectionObserver}
- */
- public void removeSelectionObserver(ChipDataSource.SelectionObserver observer) {
- mDataSource.removeSelectionObserver(observer);
- }
-
- /**
- * Adds an observer to watch for any change events on the chip data source.
- *
- * Note: please use this conservatively!
- *
- * @param observer {@link ChipDataSource.ChangeObserver}
- */
- public void addChangeObserver(ChipDataSource.ChangeObserver observer) {
- mDataSource.addChangedObserver(observer);
- }
-
- /**
- * Removes an observer from watching any change events on the chip data source.
- *
- * @param observer {@link ChipDataSource.ChangeObserver}
- */
- public void removeChangeObserver(ChipDataSource.ChangeObserver observer) {
- mDataSource.removeChangedObserver(observer);
- }
-
- /**
- * Changes the chip data source being used to manipulate chips, which will
- * update the UI accordingly.
- *
- * Note: will retain existing observers from old data source, but all chips
- * in the old data source will be cleared!
- *
- * @param dataSource {@link ChipDataSource}
- */
- public void changeChipDataSource(ChipDataSource dataSource) {
- mDataSource.cloneObservers(dataSource);
- mDataSource = dataSource;
- mChipsAdapter.notifyDataSetChanged();
- }
-
- /**
- * Gets an instance of {@link LetterTileProvider}.
- * @return {@link LetterTileProvider}
- */
- public LetterTileProvider getLetterTileProvider() {
- return LetterTileProvider.getInstance(getContext());
- }
-
- public OnChipsInputTextChangedListener getOnChipsInputTextChangedListener() {
- return mTextChangedListener;
- }
-
- public void setOnChipsInputTextChangedListener(OnChipsInputTextChangedListener listener) {
- mTextChangedListener = listener;
- }
-
- public void setInputTextColor(ColorStateList textColor) {
- mOptions.mTextColor = textColor;
- if (mChipsInput != null) { // Can be null because its lazy loaded
- mChipsInput.setTextColor(textColor);
- }
- }
-
- public void setInputHintTextColor(ColorStateList textColorHint) {
- mOptions.mTextColorHint = textColorHint;
- if (mChipsInput != null) { // Can be null because its lazy loaded
- mChipsInput.setHintTextColor(textColorHint);
- }
- }
-
- public void setInputHint(CharSequence hint) {
- mOptions.mHint = hint;
- if (mChipsInput != null) { // Can be null because its lazy loaded
- mChipsInput.setHint(hint);
- }
- }
-
- public void setInputType(int type) {
- if (mChipsInput != null) {
- mChipsInput.setInputType(type);
- }
- }
-
- public int getInputType() {
- if (mChipsInput == null) {
- return EditorInfo.TYPE_NULL;
- }
- return mChipsInput.getInputType();
- }
-
- public void setChipDeleteIconColor(ColorStateList deleteIconColor) {
- mOptions.mChipDeleteIconColor = deleteIconColor;
- }
-
- public void setChipBackgroundColor(ColorStateList chipBackgroundColor) {
- mOptions.mChipBackgroundColor = chipBackgroundColor;
- }
-
- public void setChipTitleTextColor(ColorStateList chipTitleTextColor) {
- mOptions.mChipTextColor = chipTitleTextColor;
- }
-
- public void setChipDeleteIcon(Drawable chipDeleteIcon) {
- mOptions.mChipDeleteIcon = chipDeleteIcon;
- }
-
- public void setChipDeleteIcon(@DrawableRes int res) {
- mOptions.mChipDeleteIcon = ContextCompat.getDrawable(getContext(), res);
- }
-
- public void setShowChipAvatarEnabled(boolean hasAvatar) {
- mOptions.mShowAvatar = hasAvatar;
- }
-
- public void setShowDetailedChipsEnabled(boolean enabled) {
- mOptions.mShowDetails = enabled;
- }
-
- public void setChipsDeletable(boolean enabled) {
- mOptions.mShowDelete = enabled;
- }
-
- public void setChipDetailsDeleteIconColor(ColorStateList detailedChipIconColor) {
- mOptions.mDetailsChipDeleteIconColor = detailedChipIconColor;
- }
-
- public void setChipDetailsBackgroundColor(ColorStateList detailedChipBackgroundColor) {
- mOptions.mDetailsChipBackgroundColor = detailedChipBackgroundColor;
- }
-
- public void setChipDetailsTextColor(ColorStateList detailedChipTextColor) {
- mOptions.mDetailsChipTextColor = detailedChipTextColor;
- }
-
- public void setFilterListBackgroundColor(ColorStateList backgroundColor) {
- mOptions.mFilterableListBackgroundColor = backgroundColor;
- }
-
- public void setFilterListTextColor(ColorStateList textColor) {
- mOptions.mFilterableListTextColor = textColor;
- }
-
- public void setFilterListElevation(float elevation) {
- mOptions.mFilterableListElevation = elevation;
- }
-
- public void setCustomChipsEnabled(boolean enabled) {
- mOptions.mAllowCustomChips = enabled;
- }
-
- public void setHideKeyboardOnChipClick(boolean hide) {
- mOptions.mHideKeyboardOnChipClick = hide;
- }
-
- public void setMaxRows(int rows) {
- mOptions.mMaxRows = rows;
- setMaxHeight(Utils.dp(40) * mOptions.mMaxRows);
- }
-
- public void setTypeface(Typeface typeface) {
- mOptions.mTypeface = typeface;
- LetterTileProvider.getInstance(getContext()).setTypeface(typeface);
- if (mChipsInput != null) {
- mChipsInput.setTypeface(typeface);
- }
- }
-
- public void setDelimiter(String delimiter, boolean regex){
- mOptions.mDelimiter = delimiter;
- mOptions.mDelimiterRegex = regex;
- }
-
- public void setDelimiter(String delimiter){
- setDelimiter(delimiter, false);
- }
-
- public ChipsEditText getChipsInputEditText() {
- return mChipsInput;
- }
-
- public void clearChipsInputText () {
- mChipsInput.setText("");
- }
-
- /**
- * Sets the image renderer used to load chip avatars.
- * @param renderer {@link ChipImageRenderer}
- */
- public void setImageRenderer(ChipImageRenderer renderer) {
- mOptions.mImageRenderer = renderer;
- }
-
- public ChipDataSource getChipDataSource() {
- return mDataSource;
- }
-
- ChipsEditText loadChipsInput() {
- if (mChipsInput == null) {
- mChipsInput = new ChipsEditText(getContext());
- mChipsInput.setChipOptions(mOptions);
- mChipsInput.addTextChangedListener(new ChipInputTextChangedHandler());
- }
- return mChipsInput;
- }
-
- private void loadFilterableRecycler() {
- if (mFilteredRecycler == null) {
- // Create and set the filterable chips adapter
- mFilteredAdapter = new FilterableChipsAdapter(mDataSource, mOptions, this);
-
- // Create a new filterable recycler view
- mFilteredRecycler = new FilterableRecyclerView(getContext());
- mFilteredRecycler.setChipOptions(mOptions);
- mFilteredRecycler.setup(mFilteredAdapter, this);
-
- // To show our filterable recycler view, we need to make sure
- // our ChipsInputLayout has already been displayed on the screen
- // so we can access its root view
- ViewGroup rootView = (ViewGroup)getRootView();
- RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
- Utils.getWindowWidth(getContext()),
- ViewGroup.LayoutParams.MATCH_PARENT
- );
- lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
- lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
- if (getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_PORTRAIT) {
- lp.bottomMargin = Utils.getNavBarHeight(getContext());
- }
- rootView.addView(mFilteredRecycler, lp);
- }
- }
-
- private void hideKeyboard() {
- ((InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE))
- .hideSoftInputFromWindow(mChipsInput.getWindowToken(), 0);
- }
-
-
- /**
- * Defines a validator to validate chips.
- */
- public interface ChipValidator {
- boolean validate(Chip chip);
- }
-
-
- /**
- * Implementation of {@link TextWatcher} that handles two things for us:
- * (1) Hides the filterable recycler if the user removes all the text from input.
- * (2) Tells the filterable recycler to filter the chips when the user enters text.
- */
- private final class ChipInputTextChangedHandler implements TextWatcher {
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- if (mFilteredRecycler != null) {
- // Hide the filterable recycler if there is no filter.
- // Filter the recycler if there is a filter
- if (TextUtils.isEmpty(s)) {
- mFilteredRecycler.fadeOut();
- } else {
- mFilteredRecycler.filterChips(s);
- }
- }
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
- @Override
- public void afterTextChanged(final Editable s) {
- if (mTextChangedListener != null) {
- mTextChangedListener.onChipsInputTextChanged(s);
-
- // TODO:
- // As this is a listener used mostly to dynamically change
- // the filteredList, a timeout before filtering should be
- // configured to replace 1500(ms) hardcoded value
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- onTextChanged(s, 0, 0, 0);
- }
- }, 1500);
- }
-
- String delimiter = mOptions.mDelimiter;
- if(delimiter != null && delimiter.length() > 0 && mChipsInput.getKeyboardListener() != null){
- String delimiterRegex = mOptions.mDelimiterRegex ? delimiter : Pattern.quote(delimiter);
- final String text = s.toString();
- if(Pattern.compile(delimiterRegex).matcher(text).find()){
- final String[] pieces = text.split(delimiterRegex);
- for(String piece : pieces) {
- mChipsInput.getKeyboardListener().onKeyboardActionDone(piece);
- }
- }
- }
- }
- }
-
-
- /**
- * Defines callbacks for text changed events.
- */
- public interface OnChipsInputTextChangedListener {
- void onChipsInputTextChanged(CharSequence s);
- }
-}
diff --git a/library/src/main/java/com/tylersuehr/chips/CircleImageView.java b/library/src/main/java/com/tylersuehr/chips/CircleImageView.java
index 9b5ac91f11067737418dd7f5a0bcd22f68ff0df3..8a5cb77ad8fa96f403c525ed452bcc83b6891ff1 100644
--- a/library/src/main/java/com/tylersuehr/chips/CircleImageView.java
+++ b/library/src/main/java/com/tylersuehr/chips/CircleImageView.java
@@ -1,417 +1,558 @@
package com.tylersuehr.chips;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.graphics.Shader;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.support.annotation.ColorInt;
-import android.support.annotation.ColorRes;
-import android.support.annotation.DrawableRes;
-import android.support.v7.widget.AppCompatImageView;
-import android.util.AttributeSet;
+
+import ohos.agp.components.AttrSet;
+import ohos.agp.components.Component;
+import ohos.agp.components.Image;
+import ohos.agp.components.element.Element;
+import ohos.agp.components.element.PixelMapElement;
+import ohos.agp.render.*;
+import ohos.agp.utils.Color;
+import ohos.agp.utils.Matrix;
+import ohos.app.Context;
+import ohos.hiviewdfx.HiLog;
+import ohos.hiviewdfx.HiLogLabel;
+import ohos.media.image.PixelMap;
+import ohos.media.image.common.AlphaType;
+import ohos.media.image.common.PixelFormat;
+import ohos.media.image.common.Size;
+
+import java.util.Optional;
+
+import static ohos.agp.render.Shader.TileMode.CLAMP_TILEMODE;
/**
* Copyright © 2017 Tyler Suehr
*
- * Subclass of {@link AppCompatImageView} that will crop the given image into
+ * Subclass of {@link Image} that will crop the given image into
* a circular Bitmap image.
*
* @author Tyler Suehr
* @version 1.0
*/
-public class CircleImageView extends AppCompatImageView {
- private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
+public class CircleImageView extends Image implements Component.DrawTask {
+ private static final ScaleMode SCALE_TYPE = ScaleMode.CENTER;
+
+ private static final PixelFormat PIXELMAP_CONFIG = PixelFormat.ARGB_8888;
+
+ private static final int DEFAULT_BORDER_WIDTH = 2;
+
+ private static final Color DEFAULT_BORDER_COLOR = Color.BLACK;
+
+ private static final Color DEFAULT_CIRCLE_BACKGROUND_COLOR = Color.TRANSPARENT;
+
+ private static final float DEFAULT_IMAGE_ALPHA = 255;
+
+ private static final float DEFAULT_VALUE_TWO_FLOAT = 2.0f;
+
+ private static final float DEFAULT_VALUE_TWO = 2;
+
+ private static final float DEFAULT_VALUE_POINT_FIVE = 0.5f;
+
+ private static final String ATTRIBUTE_BORDER_COLOR = "civ_color";
+
+ private static final String ATTRIBUTE_BORDER_WIDTH = "civ_border_width";
+
+ private static final String ATTRIBUTE_BG_COLOR = "civ_bg_color";
+
+ private static final int HILOG_TYPE = 3;
- private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
- private static final int COLOR_DRAWABLE_DIMENSION = 2;
+ private static final int HILOG_DOMAIN = 0xD000F00;
- private static final int DEFAULT_BORDER_WIDTH = 0;
- private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
- private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
- private static final boolean DEFAULT_BORDER_OVERLAY = false;
+ private static final HiLogLabel LABEL = new HiLogLabel(HILOG_TYPE, HILOG_DOMAIN, "[CircleImageView] ");
private final RectF mDrawableRect = new RectF();
+
private final RectF mBorderRect = new RectF();
- private final Matrix mShaderMatrix = new Matrix();
- private final Paint mBitmapPaint = new Paint();
+ private final RectF pixelMapRect = new RectF();
+
+ private Matrix mShaderMatrix = new Matrix();
+
+ private final Paint mPixelMapPaint = new Paint();
+
private final Paint mBorderPaint = new Paint();
- private final Paint mFillPaint = new Paint();
- private int mBorderColor = DEFAULT_BORDER_COLOR;
+ private final Paint mCircleBackgroundPaint = new Paint();
+
+ private Color mBorderColor = DEFAULT_BORDER_COLOR;
+
private int mBorderWidth = DEFAULT_BORDER_WIDTH;
- private int mFillColor = DEFAULT_FILL_COLOR;
- private Bitmap mBitmap;
- private BitmapShader mBitmapShader;
- private int mBitmapWidth;
- private int mBitmapHeight;
+ private boolean mIsBorderOverlay = false;
+
+ private Color mCircleBackgroundColor = DEFAULT_CIRCLE_BACKGROUND_COLOR;
+
+ private float mImageAlpha = DEFAULT_IMAGE_ALPHA;
+
+ private PixelMap mPixelMap;
+
+ private Canvas mPixelMapCanvas;
private float mDrawableRadius;
+
private float mBorderRadius;
- private ColorFilter mColorFilter;
+ private ColorMatrix mColorFilter = new ColorMatrix();
+
+ private boolean mIsInitialized;
+
+ private boolean mIsRebuildShader;
- private boolean mReady;
- private boolean mSetupPending;
- private boolean mBorderOverlay;
- private boolean mDisableCircularTransformation;
+ private boolean mIsDrawableDirty;
+ private boolean mIsDisableCircularTransformation;
+ /**
+ * CircleImageView Constructor
+ *
+ * @param context context
+ */
public CircleImageView(Context context) {
- this(context, null);
+ super(context);
+ init();
}
- public CircleImageView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ /**
+ * CircleImageView Constructor
+ *
+ * @param context context
+ * @param attrs attributeset
+ */
+ public CircleImageView(Context context, AttrSet attrs) {
+ this(context, attrs, null);
}
- public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
+ /**
+ * CircleImageView Constructor
+ *
+ * @param context context
+ * @param attrs attributeset
+ * @param defStyle defStyle
+ */
+ public CircleImageView(Context context, AttrSet attrs, String defStyle) {
super(context, attrs, defStyle);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
- this.mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_borderWidth, DEFAULT_BORDER_WIDTH);
- this.mBorderColor = a.getColor(R.styleable.CircleImageView_borderColor, DEFAULT_BORDER_COLOR);
- this.mFillColor = a.getColor(R.styleable.CircleImageView_fillColor, DEFAULT_FILL_COLOR);
- this.mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_borderOverlay, DEFAULT_BORDER_OVERLAY);
- a.recycle();
-
- super.setScaleType(SCALE_TYPE);
- this.mReady = true;
- if (mSetupPending) {
- setup();
- mSetupPending = false;
+ boolean isPresentBorderWidth = attrs.getAttr(ATTRIBUTE_BORDER_WIDTH).isPresent();
+ if (isPresentBorderWidth) {
+ mBorderWidth = attrs.getAttr(ATTRIBUTE_BORDER_WIDTH).get().getDimensionValue();
+ } else {
+ mBorderWidth = DEFAULT_BORDER_WIDTH;
+ }
+ boolean isPresentBorderColor = attrs.getAttr(ATTRIBUTE_BORDER_COLOR).isPresent();
+ if (isPresentBorderColor) {
+ mBorderColor = attrs.getAttr(ATTRIBUTE_BORDER_COLOR).get().getColorValue();
+ } else {
+ mBorderColor = DEFAULT_BORDER_COLOR;
}
+ boolean isPresentBgColor = attrs.getAttr(ATTRIBUTE_BG_COLOR).isPresent();
+ if (isPresentBgColor) {
+ mCircleBackgroundColor = attrs.getAttr(ATTRIBUTE_BG_COLOR).get().getColorValue();
+ } else {
+ mCircleBackgroundColor = DEFAULT_CIRCLE_BACKGROUND_COLOR;
+ }
+ init();
+ }
+
+ private void init() {
+ mIsInitialized = true;
+ super.setScaleMode(SCALE_TYPE);
+ mPixelMapPaint.setAntiAlias(true);
+ mPixelMapPaint.setDither(true);
+ mPixelMapPaint.setFilterBitmap(true);
+ mPixelMapPaint.setAlpha(mImageAlpha);
+ mPixelMapPaint.setColorMatrix(mColorFilter);
+ mBorderPaint.setStyle(Paint.Style.STROKE_STYLE);
+ mBorderPaint.setAntiAlias(true);
+ mBorderPaint.setColor(mBorderColor);
+ mBorderPaint.setStrokeWidth(mBorderWidth);
+ mCircleBackgroundPaint.setStyle(Paint.Style.FILL_STYLE);
+ mCircleBackgroundPaint.setAntiAlias(true);
+ mCircleBackgroundPaint.setColor(mCircleBackgroundColor);
+ setLayoutRefreshedListener(new RefreshListener());
+ addDrawTask(this);
}
@Override
- public ScaleType getScaleType() {
- return SCALE_TYPE;
- }
+ public void onDraw(Component view, Canvas canvas) {
+ if (mIsDisableCircularTransformation) {
+ super.setPixelMap(mPixelMap);
+ return;
+ }
- @Override
- public void setScaleType(ScaleType scaleType) {
- if (scaleType != SCALE_TYPE) {
- throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
+ if (mCircleBackgroundColor != Color.TRANSPARENT) {
+ canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius,
+ mCircleBackgroundPaint);
}
- }
- @Override
- public void setAdjustViewBounds(boolean adjustViewBounds) {
- if (adjustViewBounds) {
- throw new IllegalArgumentException("adjustViewBounds not supported.");
+ if (mPixelMap != null) {
+ if (mIsDrawableDirty && mPixelMapCanvas != null) {
+ mIsDrawableDirty = false;
+ Element drawable = getImageElement();
+ drawable.drawToCanvas(mPixelMapCanvas);
+ }
+
+ if (mIsRebuildShader) {
+ mIsRebuildShader = false;
+ PixelMapHolder pixelMapholder = new PixelMapHolder(mPixelMap);
+ Shader pixelMapShader = new PixelMapShader(pixelMapholder, CLAMP_TILEMODE, CLAMP_TILEMODE);
+ pixelMapShader.setShaderMatrix(mShaderMatrix);
+ mPixelMapPaint.setShader(pixelMapShader, Paint.ShaderType.PIXELMAP_SHADER);
+ }
+ canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mPixelMapPaint);
+ }
+ if (mBorderWidth > 0) {
+ canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint);
}
}
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- setup();
+ /**
+ * RefreshListener updates when view is relayout
+ */
+ class RefreshListener implements LayoutRefreshedListener {
+ @Override
+ public void onRefreshed(Component component) {
+ updateDimensions();
+ invalidate();
+ }
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
- setup();
+ updateDimensions();
+ invalidate();
}
@Override
public void setPaddingRelative(int start, int top, int end, int bottom) {
super.setPaddingRelative(start, top, end, bottom);
- setup();
- }
-
- @Override
- public void setImageBitmap(Bitmap bm) {
- super.setImageBitmap(bm);
- initializeBitmap();
- }
-
- @Override
- public void setImageDrawable(Drawable drawable) {
- super.setImageDrawable(drawable);
- initializeBitmap();
- }
-
- @Override
- public void setImageResource(@DrawableRes int resId) {
- super.setImageResource(resId);
- initializeBitmap();
+ updateDimensions();
+ invalidate();
}
- @Override
- public void setImageURI(Uri uri) {
- super.setImageURI(uri);
- initializeBitmap();
+ /**
+ * Obtains circle border color
+ *
+ * @return Color of the border
+ */
+ public Color getBorderColor() {
+ return mBorderColor;
}
- @Override
- public void setColorFilter(ColorFilter cf) {
- if (cf == mColorFilter) {
+ /**
+ * set circle border color
+ *
+ * @param borderColor borderColor
+ */
+ public void setBorderColor(Color borderColor) {
+ if (borderColor.equals(mBorderColor)) {
return;
}
- mColorFilter = cf;
- applyColorFilter();
+ mBorderColor = borderColor;
+ mBorderPaint.setColor(borderColor);
invalidate();
}
- @Override
- public ColorFilter getColorFilter() {
- return mColorFilter;
+ /**
+ * Gets circle Background color
+ * *
+ *
+ * @return Color color
+ */
+ public Color getCircleBackgroundColor() {
+ return mCircleBackgroundColor;
}
- @Override
- protected void onDraw(Canvas canvas) {
- if (mDisableCircularTransformation) {
- super.onDraw(canvas);
+ /**
+ * * Sets Circle background color
+ *
+ * @param circleBackgroundColor circleBackgroundColor
+ */
+ public void setCircleBackgroundColor(Color circleBackgroundColor) {
+ if (circleBackgroundColor.equals(mCircleBackgroundColor)) {
return;
}
-
- if (mBitmap == null) { return; }
-
- if (mFillColor != Color.TRANSPARENT) {
- canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mFillPaint);
- }
- canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint);
- if (mBorderWidth > 0) {
- canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint);
- }
+ mCircleBackgroundColor = circleBackgroundColor;
+ mCircleBackgroundPaint.setColor(circleBackgroundColor);
+ invalidate();
}
- public int getBorderColor() {
- return mBorderColor;
+ /**
+ * Obtains the circle border width
+ *
+ * @return Width of the border
+ */
+ public int getBorderWidth() {
+ return mBorderWidth;
}
- public void setBorderColor(@ColorInt int borderColor) {
- if (borderColor == mBorderColor) {
- return;
+ /**
+ * Sets circle border width
+ * *
+ *
+ * @param borderWidth borderWidth
+ */
+ public void setBorderWidth(int borderWidth) {
+ if (borderWidth != mBorderWidth) {
+ mBorderWidth = borderWidth;
+ mBorderPaint.setStrokeWidth(borderWidth);
+ updateDimensions();
+ invalidate();
}
-
- mBorderColor = borderColor;
- mBorderPaint.setColor(mBorderColor);
- invalidate();
}
/**
- * @deprecated Use {@link #setBorderColor(int)} instead
+ * Checks whether the border overlay is set
+ *
+ * @return true if border overlay is set
*/
- @Deprecated
- public void setBorderColorResource(@ColorRes int borderColorRes) {
- setBorderColor(getContext().getResources().getColor(borderColorRes));
+ public boolean isBorderOverlay() {
+ return mIsBorderOverlay;
}
/**
- * Return the color drawn behind the circle-shaped drawable.
- *
- * @return The color drawn behind the drawable
+ * * Sets border overlay
*
- * @deprecated Fill color support is going to be removed in the future
+ * @param isBorderOverlay borderOverlay
*/
- @Deprecated
- public int getFillColor() {
- return mFillColor;
+ public void setBorderOverlay(boolean isBorderOverlay) {
+ if (isBorderOverlay == mIsBorderOverlay) {
+ return;
+ }
+ mIsBorderOverlay = isBorderOverlay;
+ updateDimensions();
+ invalidate();
}
/**
- * Set a color to be drawn behind the circle-shaped drawable. Note that
- * this has no effect if the drawable is opaque or no drawable is set.
+ * Checks whether the Circular Transformation is disabled
*
- * @param fillColor The color to be drawn behind the drawable
+ * @return true if Circular Transformation is disabled
+ */
+ public boolean isDisableCircularTransformation() {
+ return mIsDisableCircularTransformation;
+ }
+
+ /**
+ * * Set setDisableCircularTransformation
*
- * @deprecated Fill color support is going to be removed in the future
+ * @param isDisableCircularTransformation disableCircularTransformation
*/
- @Deprecated
- public void setFillColor(@ColorInt int fillColor) {
- if (fillColor == mFillColor) {
+ public void setDisableCircularTransformation(boolean isDisableCircularTransformation) {
+ if (isDisableCircularTransformation == mIsDisableCircularTransformation) {
return;
}
- mFillColor = fillColor;
- mFillPaint.setColor(fillColor);
+ mIsDisableCircularTransformation = isDisableCircularTransformation;
+
+ if (isDisableCircularTransformation) {
+ mPixelMap = null;
+ mPixelMapCanvas = null;
+ mPixelMapPaint.setShader(null, Paint.ShaderType.PIXELMAP_SHADER);
+ } else {
+ initializePixelMap();
+ }
+ invalidate();
+ }
+
+ @Override
+ public void setPixelMap(PixelMap pixelMap) {
+ PixelMap emptyPixelMap = createEmptyPixelMap(pixelMap);
+ super.setPixelMap(emptyPixelMap);
+ mPixelMap = pixelMap;
+ initializePixelMap();
+ invalidate();
+ }
+
+ @Override
+ public void setPixelMap(int resId) {
+ super.setPixelMap(resId);
+ initializePixelMap();
invalidate();
}
/**
- * Set a color to be drawn behind the circle-shaped drawable. Note that
- * this has no effect if the drawable is opaque or no drawable is set.
- *
- * @param fillColorRes The color resource to be resolved to a color and
- * drawn behind the drawable
+ * Creates an empty pixel map
*
- * @deprecated Fill color support is going to be removed in the future
+ * @param pixelMap pixelMap
+ * @return pixelMap
*/
- @Deprecated
- public void setFillColorResource(@ColorRes int fillColorRes) {
- setFillColor(getContext().getResources().getColor(fillColorRes));
+ private PixelMap createEmptyPixelMap(PixelMap pixelMap) {
+ PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
+ initializationOptions.size = new Size(pixelMap.getImageInfo().size.width, pixelMap.getImageInfo().size.height);
+ initializationOptions.alphaType = AlphaType.UNKNOWN;
+ initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
+ return PixelMap.create(initializationOptions);
}
- public int getBorderWidth() {
- return mBorderWidth;
- }
-
- public void setBorderWidth(int borderWidth) {
- if (borderWidth == mBorderWidth) {
- return;
+ /**
+ * set image drawable
+ *
+ * @param drawable drawable
+ */
+ public void setImageDrawable(Element drawable) {
+ Optional pixelMap = getPixelMapFromDrawable(drawable);
+ if (pixelMap.isPresent()) {
+ setPixelMap(pixelMap.get());
+ } else {
+ HiLog.error(LABEL, "set imageview pixelMap failed, pixelMap is empty");
}
-
- mBorderWidth = borderWidth;
- setup();
}
- public boolean isBorderOverlay() {
- return mBorderOverlay;
+ /**
+ * set image Uri
+ *
+ * @param uri uri
+ */
+ public void setImageUri(String uri) {
+ Optional pixelMap = CircleImgUtils.getPixelMapByUri(uri);
+ if (pixelMap.isPresent()) {
+ setPixelMap(pixelMap.get());
+ }
+ initializePixelMap();
+ invalidate();
}
- public void setBorderOverlay(boolean borderOverlay) {
- if (borderOverlay == mBorderOverlay) {
+ @Override
+ public void setAlpha(float alpha) {
+ if (alpha == mImageAlpha) {
return;
}
+ mImageAlpha = alpha;
- mBorderOverlay = borderOverlay;
- setup();
+ // This might be called during ImageView construction before
+ // member initialization has finished on API level >= 16.
+ if (mIsInitialized) {
+ mPixelMapPaint.setAlpha(alpha);
+ invalidate();
+ }
}
- public boolean isDisableCircularTransformation() {
- return mDisableCircularTransformation;
+ @Override
+ public float getAlpha() {
+ return mImageAlpha;
}
- public void setDisableCircularTransformation(boolean disableCircularTransformation) {
- if (mDisableCircularTransformation == disableCircularTransformation) {
+ /**
+ * set color filter
+ *
+ * @param cf colormatrix
+ */
+ public void setColorFilter(ColorMatrix cf) {
+ if (cf == mColorFilter) {
return;
}
- mDisableCircularTransformation = disableCircularTransformation;
- initializeBitmap();
- }
+ mColorFilter = cf;
- private void applyColorFilter() {
- if (mBitmapPaint != null) {
- mBitmapPaint.setColorFilter(mColorFilter);
+ // This might be called during ImageView construction before
+ // member initialization has finished on API level <= 19.
+ if (mIsInitialized) {
+ mPixelMapPaint.setColorMatrix(cf);
+ invalidate();
}
}
- private Bitmap getBitmapFromDrawable(Drawable drawable) {
+ /**
+ * Obtains the ColorMatrix set to CircleImageView
+ *
+ * @return ColorMatrix set to CircleImageView
+ */
+ public ColorMatrix getColorFilter() {
+ return mColorFilter;
+ }
+
+ private Optional getPixelMapFromDrawable(Element drawable) {
if (drawable == null) {
- return null;
+ return Optional.empty();
}
- if (drawable instanceof BitmapDrawable) {
- return ((BitmapDrawable) drawable).getBitmap();
+ if (drawable instanceof PixelMapElement) {
+ return Optional.of(((PixelMapElement) drawable).getPixelMap());
}
try {
- Bitmap bitmap;
-
- if (drawable instanceof ColorDrawable) {
- bitmap = Bitmap.createBitmap(COLOR_DRAWABLE_DIMENSION, COLOR_DRAWABLE_DIMENSION, BITMAP_CONFIG);
- } else {
- bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
- }
-
- Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- drawable.draw(canvas);
- return bitmap;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
+ PixelMap pixelMap;
+ PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
+
+ initializationOptions.size = new Size(drawable.getBounds().getHeight(), drawable.getBounds().getWidth());
+ initializationOptions.pixelFormat = PIXELMAP_CONFIG;
+ pixelMap = PixelMap.create(initializationOptions);
+ Canvas canvas = new Canvas();
+ float radius = (pixelMap.getImageInfo().size.width) / DEFAULT_VALUE_TWO;
+ canvas.drawPixelMapHolderCircleShape(new PixelMapHolder(pixelMap), pixelMapRect, 0, 0, radius);
+ return Optional.of(pixelMap);
+ } catch (IllegalArgumentException e) {
+ return Optional.empty();
}
}
- private void initializeBitmap() {
- if (mDisableCircularTransformation) {
- mBitmap = null;
+ private void initializePixelMap() {
+ if (mPixelMap != null && mPixelMap.isEditable()) {
+ mPixelMapCanvas = new Canvas();
+ float radius = (mPixelMap.getImageInfo().size.width) / DEFAULT_VALUE_TWO;
+ mPixelMapCanvas.drawPixelMapHolderCircleShape(new PixelMapHolder(mPixelMap), pixelMapRect, 0, 0, radius);
} else {
- mBitmap = getBitmapFromDrawable(getDrawable());
+ mPixelMapCanvas = null;
}
- setup();
- }
- private void setup() {
- if (!mReady) {
- mSetupPending = true;
+ if (!mIsInitialized) {
return;
}
- if (getWidth() == 0 && getHeight() == 0) { return; }
-
- if (mBitmap == null) {
- invalidate();
- return;
+ if (mPixelMap != null) {
+ updateShaderMatrix(); /* if commented, img does not come */
+ } else {
+ mPixelMapPaint.setShader(null, Paint.ShaderType.PIXELMAP_SHADER);
}
+ }
- mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
-
- mBitmapPaint.setAntiAlias(true);
- mBitmapPaint.setShader(mBitmapShader);
-
- mBorderPaint.setStyle(Paint.Style.STROKE);
- mBorderPaint.setAntiAlias(true);
- mBorderPaint.setColor(mBorderColor);
- mBorderPaint.setStrokeWidth(mBorderWidth);
-
- mFillPaint.setStyle(Paint.Style.FILL);
- mFillPaint.setAntiAlias(true);
- mFillPaint.setColor(mFillColor);
-
- mBitmapHeight = mBitmap.getHeight();
- mBitmapWidth = mBitmap.getWidth();
-
+ private void updateDimensions() {
mBorderRect.set(calculateBounds());
- mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
+ mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / DEFAULT_VALUE_TWO_FLOAT,
+ (mBorderRect.width() - mBorderWidth) / DEFAULT_VALUE_TWO_FLOAT);
mDrawableRect.set(mBorderRect);
- if (!mBorderOverlay && mBorderWidth > 0) {
- mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f);
+ if (!mIsBorderOverlay && mBorderWidth > 0) {
+ mDrawableRect.inset(mBorderWidth - 1, mBorderWidth - 1);
}
- mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
-
- applyColorFilter();
+ mDrawableRadius = Math.min(mDrawableRect.height() / DEFAULT_VALUE_TWO_FLOAT,
+ mDrawableRect.width() / DEFAULT_VALUE_TWO_FLOAT);
updateShaderMatrix();
- invalidate();
}
private RectF calculateBounds() {
- int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
+ int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
-
int sideLength = Math.min(availableWidth, availableHeight);
-
- float left = getPaddingLeft() + (availableWidth - sideLength) / 2f;
- float top = getPaddingTop() + (availableHeight - sideLength) / 2f;
-
+ float left = getPaddingLeft() + (availableWidth - sideLength) / DEFAULT_VALUE_TWO_FLOAT;
+ float top = getPaddingTop() + (availableHeight - sideLength) / DEFAULT_VALUE_TWO_FLOAT;
return new RectF(left, top, left + sideLength, top + sideLength);
}
private void updateShaderMatrix() {
+ if (mPixelMap == null) {
+ return;
+ }
+
float scale;
float dx = 0;
float dy = 0;
- mShaderMatrix.set(null);
+ mShaderMatrix.setIdentity();
+ int pixelMapHeight = mPixelMap.getImageInfo().size.height;
+ int pixelMapWidth = mPixelMap.getImageInfo().size.width;
- if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
- scale = mDrawableRect.height() / (float) mBitmapHeight;
- dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
+ if (pixelMapWidth * mDrawableRect.height() > mDrawableRect.width() * pixelMapHeight) {
+ scale = mDrawableRect.height() / (float) pixelMapHeight;
+ dx = (mDrawableRect.width() - pixelMapWidth * scale) * DEFAULT_VALUE_POINT_FIVE;
} else {
- scale = mDrawableRect.width() / (float) mBitmapWidth;
- dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
+ scale = mDrawableRect.width() / (float) pixelMapWidth;
+ dy = (mDrawableRect.height() - pixelMapHeight * scale) * DEFAULT_VALUE_POINT_FIVE;
}
-
mShaderMatrix.setScale(scale, scale);
- mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
-
- mBitmapShader.setLocalMatrix(mShaderMatrix);
+ mShaderMatrix.postTranslate((int) (dx + DEFAULT_VALUE_POINT_FIVE) + mDrawableRect.left,
+ (int) (dy + DEFAULT_VALUE_POINT_FIVE) + mDrawableRect.top);
+ mIsRebuildShader = true;
}
-}
\ No newline at end of file
+}
diff --git a/library/src/main/java/com/tylersuehr/chips/CircleImgUtils.java b/library/src/main/java/com/tylersuehr/chips/CircleImgUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..cb7cfae36d2e2a27f1c8081cec44816f2ee0bfc9
--- /dev/null
+++ b/library/src/main/java/com/tylersuehr/chips/CircleImgUtils.java
@@ -0,0 +1,121 @@
+/*
+ * 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.tylersuehr.chips;
+
+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.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Optional;
+
+/**
+ * CircleImgUtils
+ */
+public class CircleImgUtils {
+ private static final String IMAGE_TYPE = "image/png";
+
+ private static final int HILOG_TYPE = 3;
+
+ private static final int HILOG_DOMAIN = 0xD000F00;
+
+ private static final HiLogLabel LABEL = new HiLogLabel(HILOG_TYPE, HILOG_DOMAIN, "[CircleImgUtils] ");
+
+ private static final int IO_END_LEN = -1;
+
+ private static final int CACHE_SIZE = 256 * 1024;
+
+ private CircleImgUtils() {
+ }
+
+ /**
+ * * getPixelMapByUri
+ *
+ * @param uri uri
+ * @return PixelMap pixelMap
+ * @throws NullPointerException Exception
+ */
+ public static Optional getPixelMapByUri(String uri) throws NullPointerException {
+ byte[] bytes = null;
+ if (uri != null) {
+ try {
+ bytes = readByteFromFile(uri);
+ } catch (IOException e) {
+ HiLog.error(LABEL, "read data from file failed");
+ }
+ }
+ if (bytes == null || bytes.length == 0) {
+ return Optional.empty();
+ }
+ ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
+ srcOpts.formatHint = IMAGE_TYPE;
+ ImageSource imageSource = ImageSource.create(bytes, srcOpts);
+ if (imageSource == null) {
+ return Optional.empty();
+ }
+
+ ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
+ decodingOpts.desiredSize = new Size(0, 0);
+ decodingOpts.desiredRegion = new Rect(0, 0, 0, 0);
+ decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888;
+ PixelMap decodePixelMap = imageSource.createPixelmap(decodingOpts);
+ return Optional.of(decodePixelMap);
+ }
+
+ /**
+ * * Read File
+ *
+ * @param filePath filePath
+ * @return byte array
+ * @throws IOException for reading data from file
+ */
+ public static byte[] readByteFromFile(String filePath) throws IOException {
+ FileInputStream fileInputStream = null;
+ byte[] cacheBytes = new byte[CACHE_SIZE];
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] bytes = new byte[0];
+ int len = IO_END_LEN;
+ try {
+ fileInputStream = new FileInputStream(new File(filePath));
+ len = fileInputStream.read(cacheBytes);
+ while (len != IO_END_LEN) {
+ baos.write(cacheBytes, 0, len);
+ len = fileInputStream.read(cacheBytes);
+ }
+ bytes = baos.toByteArray();
+ } catch (IOException e) {
+ HiLog.error(LABEL, "obtain data file stream failed");
+ } finally {
+ if (fileInputStream != null) {
+ fileInputStream.close();
+ }
+ cacheBytes = null;
+ try {
+ baos.close();
+ } catch (IOException e) {
+ HiLog.error(LABEL, "close stream failed");
+ }
+ }
+ return bytes;
+ }
+}
diff --git a/library/src/main/java/com/tylersuehr/chips/DefaultChipDecor.java b/library/src/main/java/com/tylersuehr/chips/DefaultChipDecor.java
deleted file mode 100644
index 94782b93d3f1bfe6454a19ce410ecb0304ea0f74..0000000000000000000000000000000000000000
--- a/library/src/main/java/com/tylersuehr/chips/DefaultChipDecor.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.tylersuehr.chips;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-
-/**
- * Copyright © 2017 Tyler Suehr
- *
- * Subclass of {@link RecyclerView.ItemDecoration} used to add margin
- * to chips on their left and bottom sides.
- *
- * @author Tyler Suehr
- * @version 1.0
- */
-class DefaultChipDecor extends RecyclerView.ItemDecoration {
- private final int mMargin;
-
-
- DefaultChipDecor(final Context c) {
- mMargin = (int)(8f * c.getResources().getDisplayMetrics().density);
- }
-
- @Override
- public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
- outRect.left = mMargin;
- outRect.bottom = (mMargin >> 1);
- }
-}
\ No newline at end of file
diff --git a/library/src/main/java/com/tylersuehr/chips/DefaultCustomChip.java b/library/src/main/java/com/tylersuehr/chips/DefaultCustomChip.java
index 6cb90cf8ecaa458b60411e032a55d39aff247fc3..e9bc957be24dfb363bd3c65b96b94a64ce1471fd 100644
--- a/library/src/main/java/com/tylersuehr/chips/DefaultCustomChip.java
+++ b/library/src/main/java/com/tylersuehr/chips/DefaultCustomChip.java
@@ -1,9 +1,7 @@
package com.tylersuehr.chips;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import ohos.agp.components.element.Element;
+import ohos.utils.net.Uri;
import java.util.UUID;
@@ -23,44 +21,38 @@ final class DefaultCustomChip extends Chip {
private String id;
private String title;
-
- DefaultCustomChip(String title, boolean filtered) {
+ DefaultCustomChip(String title, boolean isFiltered) {
this.id = UUID.randomUUID().toString();
this.title = title;
- setFilterable(filtered);
+ setFilterable(isFiltered);
}
DefaultCustomChip(String title) {
this(title, false);
}
- @Nullable
@Override
public Object getId() {
return id;
}
- @NonNull
@Override
public String getTitle() {
return title;
}
- @Nullable
@Override
public String getSubtitle() {
return null;
}
- @Nullable
@Override
public Uri getAvatarUri() {
return null;
}
- @Nullable
@Override
- public Drawable getAvatarDrawable() {
+ public Element getAvatarDrawable() {
return null;
}
}
\ No newline at end of file
diff --git a/library/src/main/java/com/tylersuehr/chips/DefaultImageRenderer.java b/library/src/main/java/com/tylersuehr/chips/DefaultImageRenderer.java
index 83e87b088fa1cc6dbe6a0fe788acd7a85f394e0e..ef3f4ea57b4f396202dedebb9aaf1dc86d750564 100644
--- a/library/src/main/java/com/tylersuehr/chips/DefaultImageRenderer.java
+++ b/library/src/main/java/com/tylersuehr/chips/DefaultImageRenderer.java
@@ -1,13 +1,19 @@
package com.tylersuehr.chips;
-import android.widget.ImageView;
+import ohos.agp.components.Image;
+import ohos.media.image.ImageSource;
+import ohos.media.image.PixelMap;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
/**
* Copyright © 2017 Tyler Suehr
- *
+ *
* Implementation of {@link ChipImageRenderer} that affords the default
* way of rendering avatar images.
- *
+ *
* The default renderer does this:
* (1) Try to load the avatar uri, or
* (2) Try to load the avatar drawable, or
@@ -17,16 +23,42 @@ import android.widget.ImageView;
* @version 1.0
*/
class DefaultImageRenderer implements ChipImageRenderer {
+ /**
+ * 超时时间
+ */
+ private static final int CONNECT_TIMEOUT = 5000;
+ private static final int READ_TIMEOUT = 8000;
+
@Override
- public void renderAvatar(ImageView imageView, Chip chip) {
+ public void renderAvatar(Image imageView, Chip chip) {
if (chip.getAvatarUri() != null) {
- imageView.setImageURI(chip.getAvatarUri());
+ imageView.setPixelMap(getBitmapFromUrl(chip.getAvatarUri().toString()));
} else if (chip.getAvatarDrawable() != null) {
- imageView.setImageDrawable(chip.getAvatarDrawable());
+ imageView.setBackground(chip.getAvatarDrawable());
} else {
- imageView.setImageBitmap(LetterTileProvider
- .getInstance(imageView.getContext())
- .getLetterTile(chip.getTitle()));
+ }
+ }
+
+ /**
+ * 根据Url获取网络图片资源
+ *
+ * @param url 图片url
+ * @return PixelMap
+ */
+ private PixelMap getBitmapFromUrl(String url) {
+ try {
+ URLConnection conn = new URL(url).openConnection();
+ conn.setConnectTimeout(CONNECT_TIMEOUT);
+ conn.setReadTimeout(READ_TIMEOUT);
+ InputStream is = conn.getInputStream();
+ ImageSource source = ImageSource.create(is, new ImageSource.SourceOptions());
+ ImageSource.DecodingOptions options = new ImageSource.DecodingOptions();
+ PixelMap pixelMap = source.createPixelmap(options);
+ is.close();
+ return pixelMap;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
}
}
}
\ No newline at end of file
diff --git a/library/src/main/java/com/tylersuehr/chips/FilterableChipsAdapter.java b/library/src/main/java/com/tylersuehr/chips/FilterableChipsAdapter.java
deleted file mode 100644
index dafdb377e936f82ff4a2575cb5a5f83ab5499252..0000000000000000000000000000000000000000
--- a/library/src/main/java/com/tylersuehr/chips/FilterableChipsAdapter.java
+++ /dev/null
@@ -1,187 +0,0 @@
-package com.tylersuehr.chips;
-
-import android.graphics.PorterDuff;
-import android.support.v7.widget.RecyclerView;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Filter;
-import android.widget.Filterable;
-import android.widget.TextView;
-
-/**
- * Copyright © 2017 Tyler Suehr
- *
- * Subclass of {@link RecyclerView.Adapter} to adapt the filterable chips
- * into views and display them in a linear list-list fashion.
- *
- * This should afford the ability to filter the appropriate data source and
- * update the UI accordingly. It should also allow the user to press on a
- * filterable chip item to select it.
- *
- * This observes changes to {@link ChipDataSource} to update its UI accordingly.
- *
- * @author Tyler Suehr
- * @version 1.0
- */
-class FilterableChipsAdapter
- extends RecyclerView.Adapter
- implements Filterable, ChipDataSource.ChangeObserver {
- private final OnFilteredChipClickListener mListener;
- private final ChipDataSource mDataSource;
- private final ChipOptions mOptions;
- private ChipFilter mFilter;
-
-
- FilterableChipsAdapter(ChipDataSource chipDataSource,
- ChipOptions chipOptions,
- OnFilteredChipClickListener listener) {
- mDataSource = chipDataSource;
- mOptions = chipOptions;
- mListener = listener;
-
- // Register an observer on chip data source
- mDataSource.addChangedObserver(this);
- }
-
- @Override
- public int getItemCount() {
- return mDataSource.getFilteredChips().size();
- }
-
- @Override
- public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
- LayoutInflater inflater = LayoutInflater.from(parent.getContext());
- View v = inflater.inflate(R.layout.chip_view_filterable, parent, false);
- return new Holder(v);
- }
-
- @Override
- public void onBindViewHolder(Holder holder, int position) {
- final Chip chip = mDataSource.getFilteredChip(position);
-
- // Set the chip avatar, if possible
- mOptions.mImageRenderer.renderAvatar(holder.image, chip);
-
- // Set the chip title
- holder.title.setText(chip.getTitle());
- holder.title.setTypeface(mOptions.mTypeface);
-
- // Set the chip subtitle, if possible
- if (chip.getSubtitle() != null) {
- holder.subtitle.setVisibility(View.VISIBLE);
- holder.subtitle.setText(chip.getSubtitle());
- holder.subtitle.setTypeface(mOptions.mTypeface);
- } else {
- holder.subtitle.setVisibility(View.GONE);
- }
-
- // Set chip colors from options, if possible
- if (mOptions.mFilterableListBackgroundColor != null) {
- holder.itemView.getBackground().setColorFilter(mOptions
- .mFilterableListBackgroundColor.getDefaultColor(), PorterDuff.Mode.SRC_ATOP);
- }
- if (mOptions.mFilterableListTextColor != null) {
- holder.title.setTextColor(mOptions.mFilterableListTextColor);
- holder.subtitle.setTextColor(mOptions.mFilterableListTextColor);
- }
- }
-
- @Override
- public Filter getFilter() {
- if (mFilter == null) {
- mFilter = new ChipFilter();
- }
- return mFilter;
- }
-
- @Override
- public void onChipDataSourceChanged() {
- notifyDataSetChanged();
- }
-
-
- /**
- * Nested inner-subclass of {@link RecyclerView.ViewHolder} to hold
- * references to the views in the filterable list item.
- */
- class Holder extends RecyclerView.ViewHolder implements View.OnClickListener {
- CircleImageView image;
- TextView title, subtitle;
-
- Holder(View v) {
- super(v);
- v.setOnClickListener(this);
- this.image = v.findViewById(R.id.image);
- this.title = v.findViewById(R.id.title);
- this.subtitle = v.findViewById(R.id.subtitle);
- }
-
- @Override
- public void onClick(View v) {
- // TODO: POSSIBLE OPTIMIZATION
- // Have takeChip(int) return a Chip object; which can be null checked for callback
-
- final int index = getAdapterPosition();
- if (index >= 0 && index < getItemCount()) {
- // Take the chip from the filtered chip list
- final Chip chip = mDataSource.getFilteredChip(getAdapterPosition());
- mDataSource.takeChip(chip);
-
- // Trigger callback with the clicked chip
- mListener.onFilteredChipClick(chip);
- }
- }
- }
-
-
- /**
- * Callbacks for filtered chip click events.
- */
- interface OnFilteredChipClickListener {
- void onFilteredChipClick(Chip chip);
- }
-
-
- /**
- * Concrete implementation of {@link Filter} to help us mFilter our list of filterable chips.
- *
- * This works by cloning the list of filterable chips, so that the original filterable chips
- * list is retained, and then inclusively filtering the data source filterable chips list.
- *
- * Once the data source filterable chips list is filtered, the adapter will notify data
- * set changes have happened.
- *
- * If the user removes the mFilter (removing all the typed characters), the original list
- * of filterable chips will be added back into the data source filterable chips.
- */
- private final class ChipFilter extends Filter {
- @Override
- protected FilterResults performFiltering(CharSequence constraint) {
- FilterResults results = new FilterResults();
-
- mDataSource.getFilteredChips().clear();
- if (TextUtils.isEmpty(constraint)) {
- mDataSource.getFilteredChips().addAll(mDataSource.getOriginalChips());
- } else {
- final String pattern = constraint.toString().toLowerCase().trim();
- for (Chip chip : mDataSource.getOriginalChips()) {
- if (chip.getTitle().toLowerCase().contains(pattern)
- || (chip.getSubtitle() != null && chip.getSubtitle().toLowerCase().replaceAll("\\s", "").contains(pattern))) {
- mDataSource.getFilteredChips().add(chip);
- }
- }
- }
-
- results.values = mDataSource.getFilteredChips();
- results.count = mDataSource.getFilteredChips().size();
- return results;
- }
-
- @Override
- protected void publishResults(CharSequence constraint, FilterResults results) {
- notifyDataSetChanged();
- }
- }
-}
diff --git a/library/src/main/java/com/tylersuehr/chips/FilterableRecyclerView.java b/library/src/main/java/com/tylersuehr/chips/FilterableRecyclerView.java
deleted file mode 100644
index 673e4c414f22d4b9051c1ada48a9a27a30423130..0000000000000000000000000000000000000000
--- a/library/src/main/java/com/tylersuehr/chips/FilterableRecyclerView.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.tylersuehr.chips;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AlphaAnimation;
-import android.widget.Filter;
-import android.widget.Filterable;
-
-/**
- * Copyright © 2017 Tyler Suehr
- *
- * Subclass of {@link RecyclerView} to enable calling to {@link Filter} object
- * to filter the appropriate data source, and then receive a callback once the
- * filtering is completed.
- *
- * Callbacks for filtering events are necessary because they are used to show/hide
- * this view respectively.
- *
- * @author Tyler Suehr
- * @version 1.0
- */
-class FilterableRecyclerView extends RecyclerView implements ChipComponent {
- /* Used to find its location in window */
- private ChipsInputLayout mChipsInput;
- /* Used to trigger filtering and receive callbacks to show or hide this */
- private Filter mFilter;
-
-
- FilterableRecyclerView(Context c) {
- super(c);
- setBackgroundColor(Color.WHITE);
- setLayoutManager(new LinearLayoutManager(c));
- setVisibility(GONE);
- }
-
- @Override
- public void setChipOptions(ChipOptions options) {
- ViewCompat.setElevation(this, options.mFilterableListElevation);
- if (options.mFilterableListBackgroundColor != null) {
- getBackground().setColorFilter(options.mFilterableListBackgroundColor
- .getDefaultColor(), PorterDuff.Mode.SRC_ATOP);
- }
- }
-
-
- void setup(T adapter, ChipsInputLayout chipsInputLayout) {
- setAdapter(adapter);
- mFilter = adapter.getFilter();
- mChipsInput = chipsInputLayout;
- }
-
- /**
- * Applies the given filter pattern to the filter. If the filter yields no results,
- * then we hide this filterable recycler, or show it otherwise.
- *
- * @param filter Filter pattern
- */
- void filterChips(CharSequence filter) {
- if (filter != null) {
- mFilter.filter(filter, new Filter.FilterListener() {
- @Override
- public void onFilterComplete(int count) {
- // Show if, and only if, there are results
- if (count > 0) {
- fadeIn();
- } else {
- fadeOut();
- }
- }
- });
- }
- }
-
- /**
- * Uses alpha animation to fade in the current view if it's not visible.
- */
- void fadeIn() {
- if (getVisibility() == VISIBLE) { return; }
-
- // Get visible window (keyboard shown)
- Rect r = new Rect();
- final View rootView = getRootView();
- rootView.getWindowVisibleDisplayFrame(r);
-
- int[] coord = new int[2];
- mChipsInput.getLocationInWindow(coord);
-
- ViewGroup.MarginLayoutParams lp = (MarginLayoutParams)getLayoutParams();
- lp.topMargin = coord[1] + mChipsInput.getHeight();
-
- // Height of the keyboard
- lp.bottomMargin = rootView.getHeight() - r.bottom;
- setLayoutParams(lp);
-
- AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
- anim.setDuration(200);
- startAnimation(anim);
-
- setVisibility(VISIBLE);
- }
-
- /**
- * Uses alpha animation to fade out the current view if it's not gone.
- */
- void fadeOut() {
- if (getVisibility() == GONE) { return; }
-
- AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f);
- anim.setDuration(200);
- startAnimation(anim);
-
- setVisibility(GONE);
- }
-}
\ No newline at end of file
diff --git a/library/src/main/java/com/tylersuehr/chips/FlowLayout.java b/library/src/main/java/com/tylersuehr/chips/FlowLayout.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6ec9673f50a6efb65c17446550732a4ef8eca96
--- /dev/null
+++ b/library/src/main/java/com/tylersuehr/chips/FlowLayout.java
@@ -0,0 +1,507 @@
+package com.tylersuehr.chips;
+
+import ohos.agp.components.AttrSet;
+import ohos.agp.components.Component;
+import ohos.agp.components.ComponentContainer;
+import ohos.agp.utils.LayoutAlignment;
+import ohos.agp.window.dialog.ToastDialog;
+import ohos.app.Context;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FlowLayout extends ComponentContainer implements Component.EstimateSizeListener, ComponentContainer.ArrangeListener {
+ private static final String LOG_TAG = FlowLayout.class.getSimpleName();
+
+ /**
+ * Special value for the child view spacing.
+ * SPACING_AUTO means that the actual spacing is calculated according to the size of the
+ * container and the number of the child views, so that the child views are placed evenly in
+ * the container.
+ */
+ public static final int SPACING_AUTO = -65536;
+
+ /**
+ * Special value for the horizontal spacing of the child views in the last row
+ * SPACING_ALIGN means that the horizontal spacing of the child views in the last row keeps
+ * the same with the spacing used in the row above. If there is only one row, this value is
+ * ignored and the spacing will be calculated according to childSpacing.
+ */
+ public static final int SPACING_ALIGN = -65537;
+
+ private static final int SPACING_UNDEFINED = -65538;
+
+ private static final int UNSPECIFIED_GRAVITY = -1;
+
+ private static final int ROW_VERTICAL_GRAVITY_AUTO = -65536;
+
+ private static final boolean ISDEFAULT_FLOW = true;
+ private static final int DEFAULT_CHILD_SPACING = 0;
+ private static final int DEFAULT_CHILD_SPACING_FOR_LAST_ROW = SPACING_UNDEFINED;
+ private static final float DEFAULT_ROW_SPACING = 0;
+ private static final boolean ISDEFAULT_RTL = false;
+ private static final int DEFAULT_MAX_ROWS = Integer.MAX_VALUE;
+
+ private boolean isFlow = ISDEFAULT_FLOW;
+ private int mChildSpacing = DEFAULT_CHILD_SPACING;
+ private int mMinChildSpacing = DEFAULT_CHILD_SPACING;
+ private int mChildSpacingForLastRow = DEFAULT_CHILD_SPACING_FOR_LAST_ROW;
+ private float mRowSpacing = DEFAULT_ROW_SPACING;
+ private float mAdjustedRowSpacing = DEFAULT_ROW_SPACING;
+ private boolean isRtl = ISDEFAULT_RTL;
+ private int mMaxRows = DEFAULT_MAX_ROWS;
+ private int mGravity = UNSPECIFIED_GRAVITY;
+ private int mRowVerticalGravity = ROW_VERTICAL_GRAVITY_AUTO;
+ private String mRowVerticalGravityStr = null;
+ private int mExactMeasuredHeight;
+
+ private List mHorizontalSpacingForRow = new ArrayList<>();
+ private List mHeightForRow = new ArrayList<>();
+ private List mWidthForRow = new ArrayList<>();
+ private List mChildNumForRow = new ArrayList<>();
+ private ClickedListener clickedListener;
+ private int marginLeft = 0;
+ private int marginTop = 0;
+ private int marginBottom = 0;
+ private int marginRight = 0;
+
+ public FlowLayout(Context context) {
+ this(context, null);
+ }
+
+ public FlowLayout(Context context, AttrSet attrs) {
+ super(context, attrs);
+ // 是否是流式布局 flRtl "true" 流式布局,反之将所有子 view 放在一行中 flMaxRows
+ if (attrs.getAttr("flFlow").isPresent()) {
+ isFlow = attrs.getAttr("flFlow").get().getBoolValue();
+ }
+
+ // 以行数表示的FlowLayout的最大高度。
+ if (attrs.getAttr("flMaxRows").isPresent()) {
+ mMaxRows = attrs.getAttr("flMaxRows").get().getIntegerValue();
+ }
+
+ // ' true '用于从右到左布局子视图。' false '从左到右布局。默认值是' false '
+ if (attrs.getAttr("flRtl").isPresent()) {
+ isRtl = attrs.getAttr("flRtl").get().getBoolValue();
+ }
+
+ // 子 view 间距
+ if (attrs.getAttr("flChildSpacing").isPresent()) {
+ String childMarginStr = attrs.getAttr("flChildSpacing").get().getStringValue();
+ if (childMarginStr.equals("align")) {
+ mChildSpacing = SPACING_ALIGN;
+ } else {
+ mChildSpacing = Integer.parseInt(childMarginStr);
+ }
+ }
+
+ // 行距
+ if (attrs.getAttr("flRowSpacing").isPresent()) {
+ this.setRowSpacing(attrs.getAttr("flRowSpacing").get().getFloatValue());
+ }
+
+ // 最后一行的布局样式
+ if (attrs.getAttr("flChildSpacingForLastRow").isPresent()) {
+ String mChildSpacingForLastRowStr = attrs.getAttr("flChildSpacingForLastRow").get().getStringValue();
+ if (mChildSpacingForLastRowStr.equals("auto")) {
+ mChildSpacingForLastRow = SPACING_AUTO;
+ } else if (mChildSpacingForLastRowStr.equals("align")) {
+ mChildSpacingForLastRow = SPACING_ALIGN;
+ } else {
+ mChildSpacingForLastRow = Integer.parseInt(mChildSpacingForLastRowStr);
+ }
+ }
+
+ // 每一行垂直方向的布局方式(居中,居底部)
+ if (attrs.getAttr("flRowVerticalGravity").isPresent()) {
+ mRowVerticalGravityStr = attrs.getAttr("flRowVerticalGravity").get().getStringValue();
+ }
+
+ setEstimateSizeListener(this);
+ setArrangeListener(this);
+ }
+
+ public void setListener(ClickedListener clickedListener) {
+ this.clickedListener = clickedListener;
+ }
+
+ @Override
+ public boolean onEstimateSize(int width, int height) {
+ final int widthSize = EstimateSpec.getSize(width);
+ final int widthMode = EstimateSpec.getMode(width);
+ final int heightSize = EstimateSpec.getSize(height);
+ final int heightMode = EstimateSpec.getMode(height);
+
+ mHorizontalSpacingForRow.clear();
+ mHeightForRow.clear();
+ mWidthForRow.clear();
+ mChildNumForRow.clear();
+
+ int measuredHeight = 0, measuredWidth = 0, childCount = getChildCount();
+
+ int rowWidth = 0, maxChildHeightInRow = 0, childNumInRow = 0;
+
+ final int rowSize = widthSize - getPaddingLeft() - getPaddingRight();
+
+ int rowTotalChildWidth = 0;
+ final boolean isAllowFlow = widthMode != EstimateSpec.UNCONSTRAINT && isFlow;
+ final int childSpacing = mChildSpacing == SPACING_ALIGN && widthMode == EstimateSpec.UNCONSTRAINT
+ ? 0 : mChildSpacing;
+ final float tmpSpacing = childSpacing == SPACING_ALIGN ? mMinChildSpacing : childSpacing;
+
+ for (int i = 0; i < childCount; i++) {
+ Component child = getComponentAt(i);
+ child.setClickedListener(new ClickedListener() {
+ @Override
+ public void onClick(Component component) {
+ clickedListener.onClick(component);
+ }
+ });
+ if (child.getVisibility() == HIDE) {
+ continue;
+ }
+
+ LayoutConfig childParams = child.getLayoutConfig();
+ int horizontalMargin = 0, verticalMargin = 0;
+ horizontalMargin = childParams.getMarginLeft() + childParams.getMarginRight();
+ verticalMargin = childParams.getMarginTop() + childParams.getMarginBottom();
+
+ int childWidth = child.getEstimatedWidth();
+ int childHeight = child.getEstimatedHeight();
+ if (isAllowFlow && rowWidth + childWidth > rowSize) {
+ mHorizontalSpacingForRow.add(
+ getSpacingForRow(childSpacing, rowSize, rowTotalChildWidth, childNumInRow));
+ mChildNumForRow.add(childNumInRow);
+ mHeightForRow.add(maxChildHeightInRow);
+ mWidthForRow.add(rowWidth - (int) tmpSpacing);
+ if (mHorizontalSpacingForRow.size() <= mMaxRows) {
+ measuredHeight += maxChildHeightInRow;
+ }
+ measuredWidth = Math.max(measuredWidth, rowWidth);
+
+ // Place the child view to next row
+ childNumInRow = 1;
+ rowWidth = childWidth + (int) tmpSpacing;
+ rowTotalChildWidth = childWidth;
+ maxChildHeightInRow = childHeight;
+ } else {
+ childNumInRow++;
+ rowWidth += childWidth + tmpSpacing;
+ rowTotalChildWidth += childWidth;
+ maxChildHeightInRow = Math.max(maxChildHeightInRow, childHeight);
+ }
+ }
+
+ // Measure remaining child views in the last row
+ if (mChildSpacingForLastRow == SPACING_ALIGN) {
+ // For SPACING_ALIGN, use the same spacing from the row above if there is more than one
+ // row.
+ if (mHorizontalSpacingForRow.size() >= 1) {
+ mHorizontalSpacingForRow.add(
+ mHorizontalSpacingForRow.get(mHorizontalSpacingForRow.size() - 1));
+ } else {
+ mHorizontalSpacingForRow.add(
+ getSpacingForRow(childSpacing, rowSize, rowTotalChildWidth, childNumInRow));
+ }
+ } else if (mChildSpacingForLastRow != SPACING_UNDEFINED) {
+ // For SPACING_AUTO and specific DP values, apply them to the spacing strategy.
+ mHorizontalSpacingForRow.add(
+ getSpacingForRow(mChildSpacingForLastRow, rowSize, rowTotalChildWidth, childNumInRow));
+ } else {
+ // For SPACING_UNDEFINED, apply childSpacing to the spacing strategy for the last row.
+ mHorizontalSpacingForRow.add(
+ getSpacingForRow(childSpacing, rowSize, rowTotalChildWidth, childNumInRow));
+ }
+
+ mChildNumForRow.add(childNumInRow);
+ mHeightForRow.add(maxChildHeightInRow);
+ mWidthForRow.add(rowWidth - (int) tmpSpacing);
+ if (mHorizontalSpacingForRow.size() <= mMaxRows) {
+ measuredHeight += maxChildHeightInRow;
+ }
+ measuredWidth = Math.max(measuredWidth, rowWidth);
+
+ if (childSpacing == SPACING_ALIGN) {
+ measuredWidth = widthSize;
+ } else if (widthMode == EstimateSpec.UNCONSTRAINT) {
+ measuredWidth = measuredWidth + getPaddingLeft() + getPaddingRight();
+ } else {
+ measuredWidth = Math.min(measuredWidth + getPaddingLeft() + getPaddingRight(), widthSize);
+ }
+
+ measuredHeight += getPaddingTop() + getPaddingBottom();
+ int rowNum = Math.min(mHorizontalSpacingForRow.size(), mMaxRows);
+ float rowSpacing = mRowSpacing == SPACING_ALIGN && heightMode == EstimateSpec.UNCONSTRAINT
+ ? 0 : mRowSpacing;
+ if (rowSpacing == SPACING_ALIGN) {
+ if (rowNum > 1) {
+ mAdjustedRowSpacing = (heightSize - measuredHeight) / (rowNum - 1);
+ } else {
+ mAdjustedRowSpacing = 0;
+ }
+ measuredHeight = heightSize;
+ } else {
+ mAdjustedRowSpacing = rowSpacing;
+ if (rowNum > 1) {
+ measuredHeight = heightMode == EstimateSpec.UNCONSTRAINT
+ ? ((int) (measuredHeight + mAdjustedRowSpacing * (rowNum - 1)))
+ : (Math.min((int) (measuredHeight + mAdjustedRowSpacing * (rowNum - 1)),
+ heightSize));
+ }
+ }
+ mExactMeasuredHeight = measuredHeight;
+
+ measuredWidth = widthMode == EstimateSpec.PRECISE ? widthSize : measuredWidth;
+ measuredHeight = heightMode == EstimateSpec.PRECISE ? heightSize : measuredHeight;
+ System.out.println("measuredHeight" + measuredHeight);
+ setEstimatedSize(measuredWidth, measuredHeight);
+ return false;
+ }
+
+ @Override
+ public boolean onArrange(int left, int top, int right, int bottom) {
+ final int paddingLeft = getPaddingLeft(), paddingRight = getPaddingRight(),
+ paddingTop = getPaddingTop(), paddingBottom = getPaddingBottom();
+
+ int x = isRtl ? (getWidth() - paddingRight) : paddingLeft;
+ int y = paddingTop;
+
+ int verticalGravity = mGravity & LayoutAlignment.VERTICAL_CENTER;
+ int horizontalGravity = mGravity & LayoutAlignment.LEFT;
+
+ switch (verticalGravity) {
+ case LayoutAlignment.VERTICAL_CENTER: {
+ int offset = (bottom - top - paddingTop - paddingBottom - mExactMeasuredHeight) / 2;
+ y += offset;
+ break;
+ }
+ case LayoutAlignment.BOTTOM: {
+ int offset = bottom - top - paddingTop - paddingBottom - mExactMeasuredHeight;
+ y += offset;
+ break;
+ }
+ default:
+ break;
+ }
+ int horizontalPadding = paddingLeft + paddingRight, layoutWidth = right - left;
+ x += getHorizontalGravityOffsetForRow(horizontalGravity, layoutWidth, horizontalPadding, 0);
+ int verticalRowGravity = 0;
+ if (mRowVerticalGravityStr != null && mRowVerticalGravityStr.length() > 0) {
+ if (mRowVerticalGravityStr.equals("center")) {
+ verticalRowGravity = LayoutAlignment.LEFT;
+ } else if (mRowVerticalGravityStr.equals("bottom")) {
+ verticalRowGravity = LayoutAlignment.BOTTOM;
+ }
+ }
+
+ int rowCount = mChildNumForRow.size(), childIdx = 0;
+ for (int row = 0; row < Math.min(rowCount, mMaxRows); row++) {
+ int childNum = mChildNumForRow.get(row);
+ int rowHeight = mHeightForRow.get(row);
+ float spacing = mHorizontalSpacingForRow.get(row);
+ for (int i = 0; i < childNum && childIdx < getChildCount(); ) {
+ Component child = getComponentAt(childIdx++);
+ if (child.getVisibility() == HIDE) {
+ continue;
+ } else {
+ i++;
+ }
+
+ LayoutConfig childParams = child.getLayoutConfig();
+
+ marginLeft = childParams.getMarginLeft();
+ marginRight = childParams.getMarginRight();
+ marginTop = childParams.getMarginTop();
+ marginBottom = childParams.getMarginBottom();
+
+ int childWidth = child.getEstimatedWidth();
+ int childHeight = child.getEstimatedHeight();
+ int tt = y + marginTop;
+ if (verticalRowGravity == LayoutAlignment.BOTTOM) {
+ tt = y + rowHeight - marginBottom - childHeight;
+ } else if (verticalRowGravity == LayoutAlignment.VERTICAL_CENTER) {
+ tt = y + marginTop + (rowHeight - marginTop - marginBottom - childHeight) / 2;
+ }
+ int bb = tt + childHeight;
+ if (isRtl) {
+ int l1 = x - marginRight - childWidth;
+ int r1 = x - marginRight;
+ child.setComponentPosition(l1, tt, r1, bb);
+ x -= childWidth + spacing + marginLeft + marginRight;
+ } else {
+ int l2 = x + marginLeft;
+ int r2 = x + marginLeft + childWidth;
+ child.setComponentPosition(l2, tt, r2, bb);
+ x += childWidth + spacing + marginLeft + marginRight;
+ }
+ }
+ x = isRtl ? (getWidth() - paddingRight) : paddingLeft;
+ x += getHorizontalGravityOffsetForRow(
+ horizontalGravity, layoutWidth, horizontalPadding, row + 1);
+ y += rowHeight + mAdjustedRowSpacing;
+ }
+
+ for (int i = childIdx; i < getChildCount(); i++) {
+ Component child = getComponentAt(i);
+ if (child.getVisibility() == HIDE) {
+ continue;
+ }
+ child.setComponentPosition(0, 0, 0, 0);
+ }
+ return false;
+ }
+
+ private int getHorizontalGravityOffsetForRow(int horizontalGravity, int parentWidth, int horizontalPadding, int row) {
+ if (mChildSpacing == SPACING_ALIGN || row >= mWidthForRow.size()
+ || row >= mChildNumForRow.size() || mChildNumForRow.get(row) <= 0) {
+ return 0;
+ }
+
+ int offset = 0;
+ switch (horizontalGravity) {
+ case LayoutAlignment.HORIZONTAL_CENTER:
+ offset = (parentWidth - horizontalPadding - mWidthForRow.get(row)) / 2;
+ break;
+ case LayoutAlignment.RIGHT:
+ offset = parentWidth - horizontalPadding - mWidthForRow.get(row);
+ break;
+ default:
+ break;
+ }
+ return offset;
+ }
+
+ /**
+ * Returns whether to allow child views flow to next row when there is no enough space.
+ *
+ * @return Whether to flow child views to next row when there is no enough space.
+ */
+ public boolean isFlow() {
+ return isFlow;
+ }
+
+ /**
+ * Returns the horizontal spacing between child views.
+ *
+ * @return The spacing, either {@link FlowLayout#SPACING_AUTO}, or a fixed size in pixels.
+ */
+ public int getChildSpacing() {
+ return mChildSpacing;
+ }
+
+ /**
+ * Sets the horizontal spacing between child views.
+ *
+ * @param childSpacing The spacing, either {@link FlowLayout#SPACING_AUTO}, or a fixed size in pixels.
+ */
+ public void setChildSpacing(int childSpacing) {
+ mChildSpacing = childSpacing;
+ postLayout();
+ }
+
+ /**
+ * Returns the horizontal spacing between child views of the last row.
+ *
+ * @return The spacing, either {@link FlowLayout#SPACING_AUTO},
+ * {@link FlowLayout#SPACING_ALIGN}, or a fixed size in pixels
+ */
+ public int getChildSpacingForLastRow() {
+ return mChildSpacingForLastRow;
+ }
+
+ /**
+ * Sets the horizontal spacing between child views of the last row.
+ *
+ * @param childSpacingForLastRow The spacing, either {@link FlowLayout#SPACING_AUTO},
+ * {@link FlowLayout#SPACING_ALIGN}, or a fixed size in pixels
+ */
+ public void setChildSpacingForLastRow(int childSpacingForLastRow) {
+ mChildSpacingForLastRow = childSpacingForLastRow;
+ postLayout();
+ }
+
+ /**
+ * Returns the vertical spacing between rows.
+ *
+ * @return The spacing, either {@link FlowLayout#SPACING_AUTO}, or a fixed size in pixels.
+ */
+ public float getRowSpacing() {
+ return mRowSpacing;
+ }
+
+ /**
+ * Sets the vertical spacing between rows in pixels. Use SPACING_AUTO to evenly place all rows
+ * in vertical.
+ *
+ * @param setRowSpacing
+ */
+ public void setRowSpacing(float rowSpacing) {
+ mRowSpacing = rowSpacing;
+ postLayout();
+ }
+
+ /**
+ * Returns the maximum number of rows of the FlowLayout.
+ *
+ * @return The maximum number of rows.
+ */
+ public int getMaxRows() {
+ return mMaxRows;
+ }
+
+ /**
+ * Sets the height of the FlowLayout to be at most maxRows tall.
+ *
+ * @param maxRows The maximum number of rows.
+ */
+ public void setMaxRows(int maxRows) {
+ mMaxRows = maxRows;
+ postLayout();
+ }
+
+ public void setGravity(int gravity) {
+ if (mGravity != gravity) {
+ mGravity = gravity;
+ postLayout();
+ }
+ }
+
+ public void setRowVerticalGravity(int rowVerticalGravity) {
+ if (mRowVerticalGravity != rowVerticalGravity) {
+ mRowVerticalGravity = rowVerticalGravity;
+ postLayout();
+ }
+ }
+
+ public boolean isRtl() {
+ return isRtl;
+ }
+
+ public int getMinChildSpacing() {
+ return mMinChildSpacing;
+ }
+
+ public void setMinChildSpacing(int minChildSpacing) {
+ this.mMinChildSpacing = minChildSpacing;
+ postLayout();
+ }
+
+ public int getRowsCount() {
+ return mChildNumForRow.size();
+ }
+
+ private float getSpacingForRow(int spacingAttribute, int rowSize, int usedSize, int childNum) {
+ float spacing;
+ if (spacingAttribute == SPACING_ALIGN) {
+ if (childNum > 1) {
+ spacing = (rowSize - usedSize) / (childNum - 1);
+ } else {
+ spacing = 0;
+ }
+ } else {
+ spacing = spacingAttribute;
+ }
+ return spacing;
+ }
+}
diff --git a/library/src/main/java/com/tylersuehr/chips/LetterTileProvider.java b/library/src/main/java/com/tylersuehr/chips/LetterTileProvider.java
deleted file mode 100644
index a4cf9a9128b811a6850fd4252fd83ae57d2726ae..0000000000000000000000000000000000000000
--- a/library/src/main/java/com/tylersuehr/chips/LetterTileProvider.java
+++ /dev/null
@@ -1,223 +0,0 @@
-package com.tylersuehr.chips;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.support.v4.content.ContextCompat;
-import android.text.TextPaint;
-
-/**
- * Copyright © Tyler Suehr
- *
- * This is used to create a Bitmap containing a single letter with a background of
- * a randomly, but repeatable, color. If no digit or letter in the English alphabet
- * is available, a default image is shown instead.
- *
- * This affords the above with two methods:
- * (1) {@link #getLetterTile(String)}, and
- * (2) {@link #getCircularLetterTile(String)}
- *
- * @author Tyler Suehr
- * @version 1.1
- */
-public class LetterTileProvider {
- private static volatile LetterTileProvider instance;
-
- /* Default colors for the letter tiles */
- private static final String[] DEFAULT_COLORS = new String[] {
- "#f16364", "#f58559", "#f9a43e", "#e4c62e",
- "#67bf74", "#59a2be", "#2093cd", "#ad62a7"
- };
-
- private final TextPaint paint = new TextPaint();
- private final Rect bounds = new Rect();
- private final Canvas canvas = new Canvas();
- private final char[] firstChar = new char[1];
-
- private String[] colors;
- private Bitmap defaultBitmap;
- private int tileSize;
-
-
- /* Constructors with all defaults */
- private LetterTileProvider(Context c) {
- // Setup the paint
- this.paint.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL));
- this.paint.setColor(Color.WHITE);
- this.paint.setTextAlign(Paint.Align.CENTER);
- this.paint.setAntiAlias(true);
-
- // Setup the properties
- this.colors = DEFAULT_COLORS;
- this.tileSize = c.getResources().getDimensionPixelSize(R.dimen.default_letter_tile_size);
- this.defaultBitmap = drawableToBitmap(ContextCompat
- .getDrawable(c, R.drawable.chip_delete_icon_24dp));
- }
-
- public static LetterTileProvider getInstance(Context c) {
- if (instance == null) {
- synchronized (LetterTileProvider.class) {
- if (instance == null) {
- instance = new LetterTileProvider(c);
- }
- }
- }
- return instance;
- }
-
- public void setTypeface(Typeface typeface) {
- this.paint.setTypeface(typeface);
- }
-
- public void setColors(String[] colorHexes) {
- this.colors = colorHexes;
- }
-
- public void setTileSize(int tileSize) {
- this.tileSize = tileSize;
- }
-
- public void setDefaultIcon(Drawable dr) {
- this.defaultBitmap = drawableToBitmap(dr);
- }
-
- /**
- * Convenience method to make the custom Bitmap from {@link #getLetterTile(String)}
- * a circular Bitmap.
- *
- * @param displayName Any string value
- * @return {@link Bitmap}
- */
- public Bitmap getCircularLetterTile(String displayName) {
- return getCircularBitmap(getLetterTile(displayName));
- }
-
- /**
- * Creates a custom Bitmap containing a letter, digit, or default image (if no letter
- * or digit can be resolved), positioned at the center, with a randomized background
- * color, picked from {@link #colors}, based on the hashed value of the given string.
- *
- * @param displayName Any string value
- * @return {@link Bitmap}
- */
- public Bitmap getLetterTile(String displayName) {
- // Don't allow empty strings
- if (displayName == null || displayName.length() == 0) { return null; }
-
- final char firstChar = displayName.charAt(0);
-
- // Create a Bitmap with the width & height specified from resources
- final Bitmap bitmap = Bitmap.createBitmap(tileSize, tileSize, Bitmap.Config.ARGB_8888);
-
- // Setup our canvas for drawing
- final Canvas c = canvas;
- c.setBitmap(bitmap);
- c.drawColor(pickColor(displayName));
-
- // We want to use the default Bitmap if our character is not a letter or digit
- if (Character.isLetterOrDigit(firstChar)) {
- this.firstChar[0] = Character.toUpperCase(firstChar);
-
- // Set the paint text size as half the bitmap's height
- this.paint.setTextSize(tileSize >> 1);
-
- // Measure the bounds of our first character
- this.paint.getTextBounds(this.firstChar, 0, 1, bounds);
-
- // Draw the character on the Canvas
- c.drawText(this.firstChar, 0, 1,
- tileSize / 2,
- tileSize / 2 + (bounds.bottom - bounds.top) / 2,
- paint);
- } else {
- // (32 - 24) / 2 = 4
- final float density = Resources.getSystem().getDisplayMetrics().density;
- final float defSize = (4f * density);
- c.drawBitmap(defaultBitmap, defSize, defSize, null);
- }
-
- return bitmap;
- }
-
- /**
- * Randomly picks one of the colors in {@link #colors} using an algorithm based
- * on the hashed value of the given key.
- *
- * This is consistent because String.hashCode() is guaranteed to not change across
- * Java versions, which implicates that the same key always maps to the same color.
- *
- * @param key Any string value
- * @return {@link android.support.annotation.ColorInt}
- */
- private int pickColor(String key) {
- final int whichColor = Math.abs(key.hashCode()) % colors.length;
- return Color.parseColor(colors[whichColor]);
- }
-
- /**
- * Creates a circular Bitmap by drawing a circle and then the given
- * Bitmap in the center.
- *
- * @param bitmap {@link Bitmap}
- * @return {@link Bitmap}
- */
- private Bitmap getCircularBitmap(Bitmap bitmap) {
- Bitmap output;
-
- final int smallestSize = Math.min(bitmap.getWidth(), bitmap.getHeight());
- output = Bitmap.createBitmap(smallestSize, smallestSize, Bitmap.Config.ARGB_8888);
-
- Canvas canvas = new Canvas(output);
-
- final int color = 0xff424242;
- final Paint paint = new Paint();
- final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
-
- float r = smallestSize / 2;
-
- paint.setAntiAlias(true);
- canvas.drawARGB(0, 0, 0, 0); // Draw the entire bitmap transparent
- paint.setColor(color);
- canvas.drawCircle(r, r, r, paint);
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
- canvas.drawBitmap(bitmap, rect, rect, paint);
- return output;
- }
-
- /**
- * Creates a Bitmap object from a Drawable object.
- */
- private static Bitmap drawableToBitmap(Drawable dr) {
- // Attempt to retrieve any existing Bitmap, if possible
- if (dr instanceof BitmapDrawable) {
- BitmapDrawable bDr = (BitmapDrawable)dr;
- if (bDr.getBitmap() != null) {
- return bDr.getBitmap();
- }
- }
-
- // Create a valid blank Bitmap
- final Bitmap bitmap;
- if (dr.getIntrinsicWidth() <= 0 || dr.getIntrinsicHeight() <= 0) {
- // Single color bitmap will be create of 1x1 pixel
- bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
- } else {
- bitmap = Bitmap.createBitmap(dr.getIntrinsicWidth(),
- dr.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
- }
-
- // Use our Canvas to draw the Drawable onto the Bitmap
- Canvas canvas = new Canvas(bitmap);
- dr.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- dr.draw(canvas);
- return bitmap;
- }
-}
\ No newline at end of file
diff --git a/library/src/main/java/com/tylersuehr/chips/ListChipDataSource.java b/library/src/main/java/com/tylersuehr/chips/ListChipDataSource.java
index 71fd52d20c0c0ca469c435cb34233279930484d4..f5df2243aec25547ef91d53a6aa77092ac0f9d6a 100644
--- a/library/src/main/java/com/tylersuehr/chips/ListChipDataSource.java
+++ b/library/src/main/java/com/tylersuehr/chips/ListChipDataSource.java
@@ -1,12 +1,12 @@
package com.tylersuehr.chips;
-import android.support.annotation.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Copyright © 2017 Tyler Suehr
- *
+ *
* Subclass of {@link ObservableChipDataSource} that stores chips using
* an {@link ArrayList}.
*
@@ -15,18 +15,14 @@ import java.util.List;
*/
public class ListChipDataSource extends ObservableChipDataSource {
/* Aggregation of all the original chips */
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
List mOriginal;
/* Aggregation of all filtered chips, not selected by the user */
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
List mFiltered;
/* Aggregation of all selected chips, selected by the user */
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
List mSelected;
-
/* Construct with all empty lists */
public ListChipDataSource() {
mOriginal = new ArrayList<>();
diff --git a/library/src/main/java/com/tylersuehr/chips/MaxHeightScrollView.java b/library/src/main/java/com/tylersuehr/chips/MaxHeightScrollView.java
index e2f3f087cc27eb881555a43c3a5afb682f127f25..bb92581dea0f676b7f8e9453982827c7a3aefd09 100644
--- a/library/src/main/java/com/tylersuehr/chips/MaxHeightScrollView.java
+++ b/library/src/main/java/com/tylersuehr/chips/MaxHeightScrollView.java
@@ -1,45 +1,47 @@
package com.tylersuehr.chips;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.support.v4.widget.NestedScrollView;
-import android.util.AttributeSet;
+
+import ohos.agp.components.AttrSet;
+import ohos.agp.components.Component;
+import ohos.agp.components.NestedScrollView;
+import ohos.app.Context;
/**
* Copyright © 2017 Tyler Suehr
- *
+ *
* Subclass of {@link NestedScrollView} that allows a maximum height to be specified
* such that this views height cannot exceed it.
*
* @author Tyler Suehr
* @version 1.0
*/
-public class MaxHeightScrollView extends NestedScrollView {
+public class MaxHeightScrollView extends NestedScrollView implements Component.EstimateSizeListener {
private int mMaxHeight;
-
public MaxHeightScrollView(Context context) {
this(context, null);
}
- public MaxHeightScrollView(Context c, AttributeSet attrs) {
- this(c, attrs, 0);
+ public MaxHeightScrollView(Context c, AttrSet attrs) {
+ this(c, attrs, null);
}
- public MaxHeightScrollView(Context c, AttributeSet attrs, int defStyleAttr) {
+ public MaxHeightScrollView(Context c, AttrSet attrs, String defStyleAttr) {
super(c, attrs, defStyleAttr);
- TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView);
- this.mMaxHeight = a.getDimensionPixelSize(R.styleable.MaxHeightScrollView_android_maxHeight, Utils.dp(300));
- a.recycle();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ this.mMaxHeight = TypedAttrUtils.getInteger(attrs, "MaxHeightScrollView_android_maxHeight", 300);
}
public void setMaxHeight(int height) {
this.mMaxHeight = height;
invalidate();
}
+
+ @Override
+ public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
+ int width = Component.EstimateSpec.getSize(widthEstimateConfig);
+ int height = Component.EstimateSpec.getSize(heightEstimateConfig);
+ setEstimatedSize(
+ Component.EstimateSpec.getChildSizeWithMode(width, width, Component.EstimateSpec.NOT_EXCEED),
+ Component.EstimateSpec.getChildSizeWithMode(height, height, Component.EstimateSpec.NOT_EXCEED));
+ return true;
+ }
}
diff --git a/library/src/main/java/com/tylersuehr/chips/ObservableChipDataSource.java b/library/src/main/java/com/tylersuehr/chips/ObservableChipDataSource.java
index fbdd7ca8c0676c0ca0a9ce811cdd2afbf301562e..39960c748e66b0d3015caea33640584374c4c8e9 100644
--- a/library/src/main/java/com/tylersuehr/chips/ObservableChipDataSource.java
+++ b/library/src/main/java/com/tylersuehr/chips/ObservableChipDataSource.java
@@ -1,15 +1,15 @@
package com.tylersuehr.chips;
-import android.support.annotation.VisibleForTesting;
+
import java.util.LinkedList;
import java.util.List;
/**
* Copyright © 2017 Tyler Suehr
- *
+ *
* Implementation of {@link ChipDataSource} to provide the basic functionality for
- * observers ONLY. It manages the observers in a {@link java.util.LinkedList}, and
+ * observers ONLY. It manages the observers in a {@link LinkedList}, and
* includes convenience methods for notifying them too.
- *
+ *
* Note: when notifying observers, it's a good idea to notify change observers first
* because that will update the internal components before any other observers.
*
@@ -18,14 +18,11 @@ import java.util.List;
*/
public abstract class ObservableChipDataSource implements ChipDataSource {
/* Aggregation of observers to watch changes to chip selection */
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
List mSelectionObservers;
/* Aggregation of observers to watch changes to data source */
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
List mChangeObservers;
-
@Override
public final void addSelectionObserver(SelectionObserver observer) {
if (observer == null) {
@@ -115,6 +112,7 @@ public abstract class ObservableChipDataSource implements ChipDataSource {
/**
* Notifies {@link #mSelectionObservers} that a chip was selected
* in the data source.
+ *
* @param chip {@link Chip} selected
*/
protected final void notifyChipSelected(Chip chip) {
@@ -130,6 +128,7 @@ public abstract class ObservableChipDataSource implements ChipDataSource {
/**
* Notifies {@link #mSelectionObservers} that a chip was unselected
* in the data source.
+ *
* @param chip {@link Chip} unselected
*/
protected final void notifyChipUnselected(Chip chip) {
diff --git a/library/src/main/java/com/tylersuehr/chips/RectF.java b/library/src/main/java/com/tylersuehr/chips/RectF.java
new file mode 100644
index 0000000000000000000000000000000000000000..d66884be42ea062a5665e12a47beb505745c629d
--- /dev/null
+++ b/library/src/main/java/com/tylersuehr/chips/RectF.java
@@ -0,0 +1,125 @@
+/*
+ * 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.tylersuehr.chips;
+
+import ohos.agp.utils.RectFloat;
+import ohos.media.image.common.Rect;
+
+/**
+ * RectF class
+ */
+public class RectF extends RectFloat {
+ /**
+ * default constant
+ **/
+ public static final float DEFAULT_VAL_POINT_FIVE = 0.5f;
+
+ /**
+ * Default constructor for RectF
+ */
+ public RectF() {
+ super();
+ }
+
+ /**
+ * * Parameterised constructor for RectF
+ *
+ * @param left left
+ * @param top top
+ * @param right right
+ * @param bottom bottom
+ */
+ public RectF(float left, float top, float right, float bottom) {
+ super(left, top, right, bottom);
+ }
+
+ /**
+ * * calculate center X
+ *
+ * @return centerX
+ */
+ public final float centerX() {
+ return (left + right) * DEFAULT_VAL_POINT_FIVE;
+ }
+
+ /**
+ * * calculate center Y
+ *
+ * @return centerY
+ */
+ public final float centerY() {
+ return (top + bottom) * DEFAULT_VAL_POINT_FIVE;
+ }
+
+ /**
+ * * calculates width
+ *
+ * @return width
+ */
+ public final float width() {
+ return right - left;
+ }
+
+ /**
+ * * calculates height
+ *
+ * @return height
+ */
+ public final float height() {
+ return bottom - top;
+ }
+
+ /**
+ * * set RectF coordinates
+ *
+ * @param src src
+ */
+ public void set(RectF src) {
+ if (src == null) {
+ return;
+ }
+ left = src.left;
+ top = src.top;
+ right = src.right;
+ bottom = src.bottom;
+ }
+
+ /**
+ * * inset
+ *
+ * @param dxValue dx
+ * @param dyValue dy
+ */
+ public void inset(float dxValue, float dyValue) {
+ left += dxValue;
+ top += dyValue;
+ right -= dxValue;
+ bottom -= dyValue;
+ }
+
+ /**
+ * * roundOut
+ *
+ * @param dst dst
+ */
+ public void roundOut(Rect dst) {
+ if (dst == null) {
+ return;
+ }
+ dst.cropRect((int) Math.floor(left), (int) Math.floor(top), (int) Math.ceil(right), (int) Math.ceil(bottom));
+ }
+}
+
diff --git a/library/src/main/java/com/tylersuehr/chips/TypedAttrUtils.java b/library/src/main/java/com/tylersuehr/chips/TypedAttrUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..a934236ecb979f76e6d08bddeb68ebdb0d8aa93e
--- /dev/null
+++ b/library/src/main/java/com/tylersuehr/chips/TypedAttrUtils.java
@@ -0,0 +1,108 @@
+/*
+ * 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.tylersuehr.chips;
+
+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 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;
+ }
+}
diff --git a/library/src/main/java/com/tylersuehr/chips/Utils.java b/library/src/main/java/com/tylersuehr/chips/Utils.java
index d06e9756e7a099cee83f30a4792dec648bc43ba5..72e94d8698c9961a8d9dd0c1ae63595a7408930a 100644
--- a/library/src/main/java/com/tylersuehr/chips/Utils.java
+++ b/library/src/main/java/com/tylersuehr/chips/Utils.java
@@ -1,16 +1,13 @@
package com.tylersuehr.chips;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.support.annotation.Px;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
+
+import ohos.agp.colors.RgbColor;
+import ohos.agp.window.service.Display;
+import ohos.agp.window.service.DisplayManager;
+import ohos.app.Context;
/**
* Copyright © 2017 Tyler Suehr
- *
+ *
* Utility class that provides common methods needed by many different components
* or for convenience.
*
@@ -18,53 +15,15 @@ import android.view.ViewConfiguration;
* @version 1.0
*/
final class Utils {
- static int dp(@Px int px) {
- final float density = Resources.getSystem()
- .getDisplayMetrics().density;
- return (int)(px * density);
- }
-
static boolean isColorDark(int color) {
- double darkness = 1 - (0.2126 * Color.red(color)
- + 0.7152 * Color.green(color)
- + 0.0722 * Color.blue(color)) / 255;
+ double darkness = 1 - (0.2126 * RgbColor.fromArgbInt(color).getRed()
+ + 0.7152 * RgbColor.fromArgbInt(color).getGreen()
+ + 0.0722 * RgbColor.fromArgbInt(color).getBlue()) / 255;
return darkness >= 0.5;
}
static int getWindowWidth(Context c) {
- final Resources res = c.getResources();
- return res.getDisplayMetrics().widthPixels;
- }
-
- static int getNavBarHeight(Context c) {
- int result = 0;
- boolean hasMenuKey = ViewConfiguration.get(c).hasPermanentMenuKey();
- boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
-
- if (!hasMenuKey && !hasBackKey) {
- // The device has a navigation bar
- final Resources res = c.getResources();
- final Configuration config = res.getConfiguration();
-
- int orientation = config.orientation;
- int resourceId;
-
- // Check if the device is a tablet
- if ((config.screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
- >= Configuration.SCREENLAYOUT_SIZE_LARGE) {
- resourceId = res.getIdentifier(orientation == Configuration.ORIENTATION_PORTRAIT
- ? "navigation_bar_height" : "navigation_bar_height_landscape",
- "dimen", "android");
- } else {
- resourceId = res.getIdentifier(orientation == Configuration.ORIENTATION_PORTRAIT
- ? "navigation_bar_height" : "navigation_bar_width",
- "dimen", "android");
- }
-
- if (resourceId > 0) {
- return res.getDimensionPixelSize(resourceId);
- }
- }
- return result;
+ Display display = DisplayManager.getInstance().getDefaultDisplay(c).get();
+ return display.getAttributes().width;
}
}
\ No newline at end of file
diff --git a/library/src/main/res/drawable-v21/ripple_chip_view.xml b/library/src/main/res/drawable-v21/ripple_chip_view.xml
deleted file mode 100644
index 2c632387a50604e6c4c9aafdd30b7d968c81f352..0000000000000000000000000000000000000000
--- a/library/src/main/res/drawable-v21/ripple_chip_view.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
- -
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/library/src/main/res/drawable/bg_chip_view.xml b/library/src/main/res/drawable/bg_chip_view.xml
deleted file mode 100644
index 58b375ecc25403558ef1a11d62da65f99400a739..0000000000000000000000000000000000000000
--- a/library/src/main/res/drawable/bg_chip_view.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- -
-
-
-
-
-
-
\ No newline at end of file
diff --git a/library/src/main/res/drawable/bg_chip_view_opened.xml b/library/src/main/res/drawable/bg_chip_view_opened.xml
deleted file mode 100644
index 69dbc5bded5af6d358ced90a005abcc34e93ecf9..0000000000000000000000000000000000000000
--- a/library/src/main/res/drawable/bg_chip_view_opened.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- -
-
-
-
-
-
-
\ No newline at end of file
diff --git a/library/src/main/res/drawable/chip_background.xml b/library/src/main/res/drawable/chip_background.xml
deleted file mode 100644
index 6a38d7a30b4897a51b483391eb2b10a606021b5b..0000000000000000000000000000000000000000
--- a/library/src/main/res/drawable/chip_background.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/library/src/main/res/drawable/chip_delete_icon_20dp.xml b/library/src/main/res/drawable/chip_delete_icon_20dp.xml
deleted file mode 100644
index bc35b5f933f641a509320ea6c26f4fafceb5726a..0000000000000000000000000000000000000000
--- a/library/src/main/res/drawable/chip_delete_icon_20dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/library/src/main/res/drawable/chip_delete_icon_24dp.xml b/library/src/main/res/drawable/chip_delete_icon_24dp.xml
deleted file mode 100644
index bfd52c718bc32cdddd13db3e06ad2988e0d2c666..0000000000000000000000000000000000000000
--- a/library/src/main/res/drawable/chip_delete_icon_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/library/src/main/res/drawable/chip_details_background.xml b/library/src/main/res/drawable/chip_details_background.xml
deleted file mode 100644
index 4edeb330ea1b2f4ab98813e99918021e0cf76aee..0000000000000000000000000000000000000000
--- a/library/src/main/res/drawable/chip_details_background.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/library/src/main/res/drawable/ripple_chip_view.xml b/library/src/main/res/drawable/ripple_chip_view.xml
deleted file mode 100644
index 58b375ecc25403558ef1a11d62da65f99400a739..0000000000000000000000000000000000000000
--- a/library/src/main/res/drawable/ripple_chip_view.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- -
-
-
-
-
-
-
\ No newline at end of file
diff --git a/library/src/main/res/layout/chip_view.xml b/library/src/main/res/layout/chip_view.xml
deleted file mode 100644
index 745c587d3f1c1e6f63acb0600c78bacbb52daee4..0000000000000000000000000000000000000000
--- a/library/src/main/res/layout/chip_view.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/library/src/main/res/layout/chip_view_detailed.xml b/library/src/main/res/layout/chip_view_detailed.xml
deleted file mode 100644
index c39a1a5a1b5d1777cd79c85477271ddeedbec126..0000000000000000000000000000000000000000
--- a/library/src/main/res/layout/chip_view_detailed.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/library/src/main/res/layout/chips_input_view.xml b/library/src/main/res/layout/chips_input_view.xml
deleted file mode 100644
index bfaa0d2dbeeae5150654f3158d3dda66c6fa9b2a..0000000000000000000000000000000000000000
--- a/library/src/main/res/layout/chips_input_view.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml
deleted file mode 100644
index 29282a4b1230ae8569c14215356390fc6e23f1a1..0000000000000000000000000000000000000000
--- a/library/src/main/res/values/attrs.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/library/src/main/res/values/colors.xml b/library/src/main/res/values/colors.xml
deleted file mode 100644
index 0a6fea64fc50076a5630a0dc137d9c9ea2e28816..0000000000000000000000000000000000000000
--- a/library/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
- #E0E0E0
- #009688
- #ababab
- #b9ffffff
- ?attr/colorAccent
-
- #E0E0E0
- #00B8D4
- #FFFFFF
- #DB000000
- #8C000000
-
\ No newline at end of file
diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml
deleted file mode 100644
index 8189ceb6a3ac01877d248d25400a70fc681fb63a..0000000000000000000000000000000000000000
--- a/library/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- 64dp
-
- 32dp
- 13sp
- 16sp
- 8dp
-
\ No newline at end of file
diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml
deleted file mode 100644
index cf17aaa3bea531c8afb6f2b7b9ad9cf77eb8c436..0000000000000000000000000000000000000000
--- a/library/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- Chips Library
-
\ No newline at end of file
diff --git a/library/src/main/resources/base/element/color.json b/library/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..f1d3d530c19720f5c581a4bf53195cfe2f35708a
--- /dev/null
+++ b/library/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "chip_focused_text_color",
+ "value": "#000000"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/library/src/main/resources/base/element/float.json b/library/src/main/resources/base/element/float.json
new file mode 100644
index 0000000000000000000000000000000000000000..587b979f29a66fc4c0888de76baf0ef58d2b365c
--- /dev/null
+++ b/library/src/main/resources/base/element/float.json
@@ -0,0 +1,8 @@
+{
+ "float": [
+ {
+ "name": "chip_title_text_size",
+ "value": "16fp"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/library/src/main/resources/base/element/string.json b/library/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..1e2b219ccdd1183e23968586e5e2e404b41c38c9
--- /dev/null
+++ b/library/src/main/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "library"
+ }
+ ]
+}
diff --git a/library/src/main/resources/base/graphic/chip_delete_icon_24dp.xml b/library/src/main/resources/base/graphic/chip_delete_icon_24dp.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f7ecb35ffaa706de412898dd2a51b2ba011c4368
--- /dev/null
+++ b/library/src/main/resources/base/graphic/chip_delete_icon_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/library/src/main/resources/base/graphic/chip_details_background.xml b/library/src/main/resources/base/graphic/chip_details_background.xml
new file mode 100644
index 0000000000000000000000000000000000000000..66c7ee13dc75e06ba31be3a3c362296cc7b37461
--- /dev/null
+++ b/library/src/main/resources/base/graphic/chip_details_background.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/resources/base/graphic/circle.xml b/library/src/main/resources/base/graphic/circle.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e2f27f5cdad643e9656f20bd912cea7bcb21b093
--- /dev/null
+++ b/library/src/main/resources/base/graphic/circle.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/resources/base/layout/chip_view.xml b/library/src/main/resources/base/layout/chip_view.xml
new file mode 100644
index 0000000000000000000000000000000000000000..df85c63e6c290c4a4cc7e8e1634be01bdd4bba10
--- /dev/null
+++ b/library/src/main/resources/base/layout/chip_view.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/resources/base/layout/chip_view_detailed.xml b/library/src/main/resources/base/layout/chip_view_detailed.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1bf377b224119d3816cd2c54172f050f0e895add
--- /dev/null
+++ b/library/src/main/resources/base/layout/chip_view_detailed.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/res/layout/chip_view_filterable.xml b/library/src/main/resources/base/layout/chip_view_filterable.xml
similarity index 100%
rename from library/src/main/res/layout/chip_view_filterable.xml
rename to library/src/main/resources/base/layout/chip_view_filterable.xml
diff --git a/library/src/main/resources/base/layout/chips_input_view.xml b/library/src/main/resources/base/layout/chips_input_view.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d58b53ce706c012ceeb7703986ff6d511294c14f
--- /dev/null
+++ b/library/src/main/resources/base/layout/chips_input_view.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/res/drawable/avatar.png b/library/src/main/resources/base/media/avatar.png
similarity index 100%
rename from library/src/main/res/drawable/avatar.png
rename to library/src/main/resources/base/media/avatar.png
diff --git a/library/src/test/java/com/tylersuehr/chips/ExampleTest.java b/library/src/test/java/com/tylersuehr/chips/ExampleTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..03b404dcc2b3139a47a3644cc0c3e393b424a1fe
--- /dev/null
+++ b/library/src/test/java/com/tylersuehr/chips/ExampleTest.java
@@ -0,0 +1,9 @@
+package com.tylersuehr.chips;
+
+import org.junit.Test;
+
+public class ExampleTest {
+ @Test
+ public void onStart() {
+ }
+}
diff --git a/library/src/test/java/com/tylersuehr/chips/ExampleUnitTest.java b/library/src/test/java/com/tylersuehr/chips/ExampleUnitTest.java
deleted file mode 100644
index 8a4a2fa1dc948955b402a8b3b644cc34008b63ed..0000000000000000000000000000000000000000
--- a/library/src/test/java/com/tylersuehr/chips/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.tylersuehr.chips;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see Testing documentation
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() throws Exception {
- assertEquals(4, 2 + 2);
- }
-}
\ No newline at end of file