diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..37a4eb8b43d978ea05b2c6e3fb934f9b40dddd4d --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +/entry/.preview +.cxx diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7f4cb416c083d265558da75d457237d671..0000000000000000000000000000000000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..62c8f7971a2d7aedb3d5e2dbe99146647f751db0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,2 @@ +## 0.0.1-SNAPSHOT +ohos第一个版本,完整实现了原库的全部api diff --git a/README.OPENSOURCE b/README.OPENSOURCE new file mode 100644 index 0000000000000000000000000000000000000000..78a4e397e160d301e58aedb773b6193daba6a642 --- /dev/null +++ b/README.OPENSOURCE @@ -0,0 +1,10 @@ +[ + { + "Name": " chips-input-layout ", + "License": " MIT License ", + "License File": " LICENSE ", + "Version Number": " 2.3 ", + "Upstream URL": " https://github.com/tylersuehr7/chips-input-layout ", + "Description": " 该库提供了使用自定义图像渲染的能力,以便您可以使用任何您希望的第 3 方图像加载库。ChipImageRenderer提供给库组件在需要加载芯片头像时使用。 " + } +] diff --git a/README.md b/README.md index a77c24da1ddaa4e5f130b42108377c796d9add7d..2ca68844c2799c5569f1620105c38956e4d83d94 100644 --- a/README.md +++ b/README.md @@ -1,391 +1,118 @@ -# Chips Input Layout -A highly customizable Android ViewGroup for displaying Chips (specified in the Material Design Guide)! - - - -How to use it... - -In your project level build.gradle : -```java +# chips-input-layout + +#### 项目介绍 +- 项目名称:chips-input-layout +- 所属系列:openharmony的第三方组件适配移植 +- 功能:实现可以展开/折叠的Text控件 +- 项目移植状态:主功能完成 +- 调用差异:无 +- 开发版本:sdk5,DevEco Studio 2.1 Release +- 基线版本:Release 2.3 + +#### 效果演示 +![效果演示](./img/demo.gif) + +#### 安装教程 + +1.在项目根目录下的build.gradle文件中, + ```gradle allprojects { repositories { - ... - maven { url "https://jitpack.io" } - } -} -``` - -In your app level build.gradle: -```java -dependencies { - compile 'com.github.tylersuehr7:chips-input-layout:2.3' -} -``` - -Core features of this library: -* Use libraries (Glide, Picasso,...) to load chip avatars -* Filter chips as user inputs text -* Allow user to create custom chips -* Specify if chips show details, are deletable, or have an avatar -* Specify how chips are managed/stored in-memory -* Validate any chips -* Highly customizable chips -* Strictly sticks to the Google Material Design Guide - -*Honorable Mentions:* -* This uses a RecyclerView layout manager: https://github.com/BelooS/ChipsLayoutManager - -## Using the `ChipsInputLayout` -The purpose of this library is to allow users to interact with chips, specified in the Google Material Design Guide. To achieve this functionality, you'll need to use the `ChipsInputLayout` view. - -### Using in an XML layout -`ChipsInputLayout` can be used in any ViewGroup and supports all width and height attributes. Simple usage is shown here: -```xml - -``` - -Here is a table of all the XML attributes available for this view: - -Attribute | Type | Summary ---- | :---: | --- -`android:hint` | `string` | Hint shown in the chips input. -`android:textColorHint` | `color` | Text color of the hint shown in the chips input. -`android:textColor` | `color` | Text color of chips input. -`app:allowCustomChips` | `boolean` | True if user is allowed to enter custom chips. -`app:hideKeyboardOnChipClick` | `boolean` | True if the keyboard should hide when a filterable chip is clicked. -`app:maxRows` | `int` | Maximum number of rows used to display chips. -`app:delimiter` | `string` | A custom delimiter used to submit new chips. -`app:delimiterRegex` | `boolean` | True if `app:delimiter` is a regular expression. -`app:chip_showDetails` | `boolean` | True if clicking a chip should show its details. -`app:chip_showAvatar` | `boolean` | True if each chip should show an avatar icon. -`app:chip_showDelete` | `boolean` | True if each chip should be deletable by the user. -`app:chip_deleteIcon` | `reference` | Changes the chips' delete icons. -`app:chip_deleteIconColor` | `color` | Color of each chips' delete icon. -`app:chip_backgroundColor` | `color` | Color of each chips' background. -`app:chip_textColor` | `color` | Text color of each chips' title and subtitle. -`app:details_deleteIconColor` | `color` | Color of each detailed chips' delete icon. -`app:details_backgroundColor` | `color` | Color of each detailed chips' background. -`app:details_textColor` | `color` | Text color of each detailed chips' title and subtitle. -`app:filter_elevation` | `dimension` | Elevation of the filterable list. -`app:filter_backgroundColor` | `color` | Color of the filterable list's background. -`app:filter_textColor` | `color` | Text color of the filterable list's items. - -### Using in Java code -`ChipsInputLayout` can be programmatically added into any ViewGroup. Simple usage in an Activity is shown here: -```java -@Override -protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - ChipsInputLayout chipsInputLayout = new ChipsInputLayout(this); - // Set any properties for chips input layout - - setContentView(chipsInputLayout); -} -``` - -Here is a table of all the accessible attributes available for this view: - -Method | Summary ---- | --- -`setInputHint(CharSequence)` | Changes hint shown in the chips input. -`setInputHintTextColor(ColorStateList)` | Changes text color of the hint shown in the chips input. -`setInputTextColor(ColorStateList)` | Changes text color of chips input. -`setShowDetailedChipsEnabled(boolean)` | True if clicking a chip should show its details. -`setCustomChipsEnabled(boolean)` | True if user is allowed to enter custom chips. -`setHideKeyboardOnChipClick(boolean)` | True if the keyboard should hide when filterable chip is clicked. -`setMaxRows(int)` | Changes maximum number of rows used to display chips. -`setTypeface(Typeface)` | Changes the typeface of the ChipsInputLayout and all associated textual-based components. -`setDelimiter(String)` | Sets the customer delimiter to be used to separate new chips. -`setDelimiter(String, boolean)` | Sets the customer delimiter to be used to separate new chips. Boolean is whether string is a regular expression or not. -`setChipTitleTextColor(ColorStateList)` | Changes text color of each chips' title and subtitle. -`setShowChipAvatarEnabled(boolean)` | True if each chip should show an avatar icon. -`setChipsDeletable(boolean)` | True if each chip should be deletable by the user. -`setChipDeleteIconColor(ColorStateList)` | Changes color of each chips' delete icon. -`setChipBackgroundColor(ColorStateList)` | Changes color of each chips' background. -`setChipDeleteIcon(Drawable)` | Changes the each chips' delete icon. -`setChipDeleteIcon(int)` | Overload of setChipDeleteIcon(Drawable). -`setChipDetailsTextColor(ColorStateList)` | Changes text color of each detailed chips' title and subtitle. -`setChipDetailsBackgroundColor(ColorStateList)` | Changes color of each detailed chips' background. -`setChipDetailsDeleteIconColor(ColorStateList)` | Changes color of each detailed chips' delete icon. -`setFilterListBackgroundColor(ColorStateList)` | Changes color of the filterable list's background. -`setFilterListTextColor(ColorStateList)` | Changes text color of the filterable list's items. -`setFilterListElevation(float)` | Changes elevation of the filterable list. -`setInputType(int)` | Sets the text input type on the ChipsEditText. -`setOnChipsInputTextChangedListener(OnChipsInputTextChangedListener)` | Sets a text changed listener that gets invoked when text it changed on the ChipsEditText. - -## Using the Chips -There are a plethora of ways you can manipulate chips in `ChipsInputLayout`. However, the main abilities afforded by `ChipsInputLayout` are that you can set a list of chips that can be filtered by user input and set a list of chips that are pre-selected. Other features are listed in the table below. - -### Creating a chip -`Chip` is the base object needed for `ChipsInputLayout`, and associated components in the library, to work properly. `ChipsInputLayout` can work with anything that is a `Chip`. So, that means that you can create any type of 'chip' data you want... simply inherit the `Chip` class and you're good to go! - -Here's a small example: -```java -public class CoolChip extends Chip { - private final String coolName; - private final Uri coolPic; - - public CoolChip(String coolName, Uri coolPic) { - this.coolName = coolName; - this.coolPic = coolPic; - } - - Override - public String getTitle() { - return coolName; - } - - @Override - public Uri getAvatarUri() { - return coolPic; + maven { + url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' + } } - - // ...other chip methods that are required to implement -} -``` - -### Setting a filterable list of chips in `ChipsInputLayout` -`ChipsInputLayout` supports the ability to show/hide a list of chips that are filterable as the user inputs text into it. To use this feature, simply call `setFilterableChipList(List)` in `ChipsInputLayout`. - -Not calling `setFilterableChipList(List)` will imply you don't wish to use that feature, therefore, `ChipsInputLayout`, will not show/hide the filterable list as the user inputs text. - -Here is a simple example: -``` java -@Override -protected void onCreate(List chips) { - // ...Cool onCreate stuff in activity - - ChipsInputLayout chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input); - - // ...Cool logic to acquire chips - List chips = getReallyCoolChips(); - - this.chipsInput.setFilterableChipList(chips); -} -``` - -### Setting a pre-selected list of chips in `ChipsInputLayout` -`ChipsInputLayout` supports the ability to set an already-selected list of chips. To use this feature, simply call `setSelectedChipList(List)` in `ChipsInputLayout`. - -Here is a simple example: -```java -@Override -protected void onCreate(List chips) { - // ...Cool onCreate stuff in activity - - ChipsInputLayout chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input); - - // ...Cool logic to acquire chips - List defaultChips = getDefaultTagChips(); - - this.chipsInput.setSelectedChipList(chips); } + ``` +2.在entry模块的build.gradle文件中, + ```gradle + dependencies { + implementation('com.gitee.chinasoft_ohos:ExpandableTextView:0.0.1-SNAPSHOT') + ...... + } ``` -### Other chip manipulation methods in `ChipsInputLayout` - -Method | Summary ---- | --- -`addFilteredChip(Chip)` | Adds a new chip to the filterable chips, which will update the UI accordingly because of the change observers. -`addSelectedChip(Chip)` | Adds a new chip to the selected chips, which will update the UI accordingly because of the change observers. -`clearFilteredChips()` | Clears all the filterable chips, which will update the UI accordingly because of the change observers. -`clearSelectedChips()` | Clears all the selected chips, which will update the UI accordingly because of the change observers. -`getSelectedChips()` | Gets all the currently selected chips. -`getFilteredChips()` | Gets all the currently filtered chips. -`getOriginalFilterableChips()` | Gets all the originally set filterable chips. -`getSelectedChipByPosition(int)` | Gets a selected chip using the given index. -`getSelectedChipById(Object id)` | Gets a selected chip using the given ID, if possible. -`getSelectedChipByTitle(String, boolean)` | Gets a selected chip with exactly the given title or like the given title. -`getSelectedChipBySubtitle(String, boolean)` | Gets a selected chip with exactly the given subtitle or like the given subtitle. -`getFilteredChipPosition(int)` | Gets a filtered chip using the given index. -`getFilteredChipById(Object)` | Gets a filtered chip using the given ID, if possible. -`getFilteredChipByTitle(String, boolean)` | Gets a filtered chip with exactly the given title or like the given title. -`getFilteredChipBySubtitle(String, boolean)` | Gets a filtered chip with exactly the given subtitle or like the given subtitle. -`doesChipExist(Chip)` | Checks if the given chip exists in either the filterable or selected chips. -`isChipFiltered(Chip)` | Checks if the given chip exists in the filtered chips. -`isChipSelected(Chip)` | Checks if the given chip exists in the selected chips. -`getChipDataSource()` | Gets the currently used chip data source. -`changeChipDataSource(ChipDataSource)` | Changes the chip data source being used to manage chips, cloning existing observers. - -## Managing the Chips -Where this library capitalizes, is how it decentralizes where and how the selected and filterable chips are stored. This makes accessing and receiving updates to data source changes from various Android components really simple. - -All chips are managed by, `ChipDataSource`, which is an abstraction to decouple the concrete implementation of how the abstract methods manage the chips. This means that other implementations of `ChipDataSource` can be made at your own leisure. Simply call `changeChipDataSource(ChipDataSource)` in `ChipsInputLayout` to use your implementation of `ChipDataSource`. - -Although not required, but definitely recommeneded, you can inherit the semi-concrete, `ObservableChipDataSource`, which is an implementation of `ChipDataSource` that handles the observer functionality for you properly so that it simplifies writing other `ChipDataSource` implementations. - -By default, `ChipsInputLayout` will automatically use `ListChipDataSource`; which is out-of-the-box really good at being processing and memory efficient, and it relies on the `ArrayList` to manage chips. - -### Observing chip selection changes -`ChipDataSource` has the ability to notify observers that want to observe specific chip selection events in `ChipDataSource`. The observers will be notified if a chip has been selected or unselected from the selected chip list in `ChipDataSource`. Both selection and deselection events will afford the chip that was selected or deselected respectively. - -To use this functionality, you'll want to implement the `ChipDataSource.SelectionObserver` and register it on `ChipDataSource`. Be sure to manage unregistering the observer, if need be, as well. - -To set the observer, you'll need to call the `addSelectionObserver(ChipDataSource.SelectionObserver)` method in `ChipsInputLayout`. - -Here is a simple example: -```java -public class CoolActivity extends AppCompatActivity implements ChipDataSource.SelectionObserver { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_cool); - - // Get the ChipsInputLayout from the layout file - ChipsInputLayout chipsInput = (ChipsInputLayout)findViewById(R.id.chips); - chipsInput.addSelectionObserver(this); - } - - @Override - public void onChipSelected(Chip selectedChip) { - // Cool chip selection stuff here... - } - - @Override - public void onChipUnselected(Chip unselectedChip) { - // Cool chip unselection stuff here... - } -} +在sdk5,DevEco Studio 2.1 Release下项目可直接运行 +如无法运行,删除项目.gradle,.idea,build,gradle,build.gradle文件, +并依据自己的版本创建新项目,将新项目的对应文件复制到根目录下 + +#### 使用说明 + +使用该库非常简单,只需查看提供的示例的源代码。(查看ViewCreateHelper.java中在ScrollView和ListContainer中的使用) +```示例XML + + + + + + ``` -### Observing any change to the chip data source -`ChipDataSource` has the ability to notify observers that want to observe any type of change to the data in `ChipDataSource`. The observers will be notified if a chip has been added or removed from either the selected or filtered lists in the `ChipDataSource`; however, there's no information about the event though. - -This is used internally by the library to trigger UI updates on `RecyclerView` adapters when the data has changed. - -To use this functionality, you'll want to implement the `ChipDataSource.ChangeObserver` and register it on `ChipDataSource`. Be sure to manage unregistering the observer, if need be, as well. - -To set the observer, you'll need to call the `addChangeObserver(ChipDataSource.ChangeObserver)` method in `ChipsInputLayout`. - -Here is a simple example: ```java -public class CoolAdapter extends RecyclerView.Adapter implements ChipDataSouce.ChangeObserver { - public CoolAdapter(ChipDataSource dataSource) { - dataSource.addChangeObserver(this); - } - - // adapter implementation to do really cool adapter stuff... - - @Override - public void onChipDataSourceChanged() { - // This example would just update the Recycler when the chip data source changes - notifyDataSetChanged(); - } -} +ExpandableTextView expandableTextView = (ExpandableTextView) + component.findComponentById(ResourceTable.Id_expandable); +expandableTextView.setText(slice.getString(ResourceTable.String_dummy_text2)); ``` +另外,您可以选择在布局xml文件中设置以下属性,以自定义ExpandableTextView的行为。 +1. maxCollapsedLines (默认为8)当TextView折叠时允许显示的最大文本行数 -## Using Image Loading Libraries (Glide, Picasso,...) -This library affords the ability to use custom image rendering so that you can use any 3rd-party image loading libraries that you wish. `ChipImageRenderer` is provided to the library components to use when they need to load chip avatars. +2. animDuration (默认为300毫秒)扩展/折叠动画的持续时间 -By default, `ChipsInputLayout` will use its own implementation of `ChipImageRenderer`, but you can provide a custom implementation to use instead by calling `setImageRenderer(ChipImageRenderer)` in `ChipsInputLayout`. +3. animAlphaStart (默认值为0.7f)动画开始时TextView的Alpha值(注意)如果要禁用Alpha动画,请将此值设置为1。 -Here's a small example (using Glide): -```java -public class GlideRenderer implements ChipImageRenderer { - @Override - public void renderAvatar(ImageView imageView, Chip chip) { - if (chip.getAvatarUri() != null) { - // Use Glide to load URL (provided in avatar uri) - Glide.with(imageView.getContext()) - .load(chip.getAvatarUri()) - .into(imageView); - } else { - // Default to circular tile if no uri exists - imageView.setImageBitmap(LetterTileProvider - .getInstance(imageView.getContext()) - .getLetterTile(chip.getTitle())); - } - } -} - -@Override -protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_cool); - - // Find out chips input layout in xml layout - ChipsInputLayout chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input); - - // Set the custom image renderer for chip avatars - chipsInput.setImageRenderer(new GlideRenderer()); -} -``` +4. expandDrawable 自定义一个可绘制的设置为ImageButton以展开TextView -## Chip Validation -This library also affords the ability to validate chips. Chip validtion can be used for a plethora of reasons or use-cases. Validation can be done on the selected chips or on a single chip itself. +5. collapseDrawable 自定义一个可绘制的设置为ImageButton以折叠TextView -Validation is abstracted by the `ChipValidator` interface. This allows you to provide your own implementation of chip validation for whatever purpose you want or need it for. By default, there is no implementation of `ChipValidator` set or provided by this library. +#### 测试信息 -### Creating a chip validator -`ChipValidator` must be implemented in order to write your own chip validation logic. `ChipValidator` has one method only, `validate(Chip)`, and it is used to determine when a single given chip should be considered valid. +CodeCheck代码测试无异常 -Here's a small example: -```java -public class CustomChipValidator implements ChipsInputLayout.ChipValidator { - @Override - public boolean validate(Chip chip) { - // This example will make the chip valid if the chip's title contains the letter "T" - return chip.getTitle().toLowerCase().contains("t"); - } -} -``` +CloudTest代码测试无异常 -### Setting a chip validator -A custom implementation of `ChipValidator` can be set using the `ChipsInputLayout`. Simply call the `setChipValidator(ChipValidator)` method in `ChipsInputLayout`. +病毒安全检测通过 -Here's a simple example: -```java -@Override -protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_cool); - - // Find out chips input layout in xml layout - ChipsInputLayout chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input); - - // Set an instance of chip validator in chips input layout - chipsInput.setChipValidator(new MyCoolChipValidator()); -} -``` +当前版本demo功能与原组件基本无差异 -### Using a chip validator -Using a chip validator is really easy! After setting a chip validator in `ChipsInputLayout`, you can validate a single given chip or all the selected chips. +#### 版本迭代 -Validating a single given chip can be done by calling, `validateChip(Chip)`, in `ChipsInputLayout`. Validating all the selected chips can be done by calling, `validateSelectedChips()`, in `ChipsInputLayout`. When you call either of those methods without having set a chip validator, it will simply return true. +- 0.0.1-SNAPSHOT -Here's a simple example: -```java -public class CoolActivity extends AppCompatActivity { - private ChipsInputLayout chipsInput; - - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_cool); - - // Find chips input layout in XML layout - this.chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input); - - // Set custom chip validator - this.chipsInput.setChipValidator(new MyCoolChipValidator()); - } - - public void onCoolButtonClicked(View v) { - // Example to show selected chip validation - if (chipsInput.validateSelectedChips()) { - Toast.makeText(this, "Selected chips are valid!", Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(this, "Selected chips are NOT valid!", Toast.LENGTH_SHORT).show(); - } - } -} -``` +#### 版权和许可信息 diff --git a/app/build.gradle b/app/build.gradle index bb61a318f09febafd21e852406a99de21655a8dc..60e88391f40bc5e2ffde509aa3b73bf08fe2b48c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,60 +1,28 @@ -buildscript { - ext.kotlin_version = '1.2.40' - - repositories { - google() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.1.1' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - google() - jcenter() - maven { url "https://jitpack.io" } - } -} - - - -apply plugin: 'com.android.application' - -android { - - compileSdkVersion 28 - buildToolsVersion "28.0.2" +apply plugin: 'com.huawei.ohos.hap' +apply plugin: 'com.huawei.ohos.decctest' +ohos { + compileSdkVersion 5 defaultConfig { - applicationId "com.tylersuehr.chips" - minSdkVersion 16 - targetSdkVersion 28 - versionCode 1 - versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + compatibleSdkVersion 5 } 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:design:28.0.0-rc01' - implementation 'com.android.support.constraint:constraint-layout:1.1.2' - testImplementation 'junit:junit:4.12' + implementation fileTree(dir: 'libs', include: ['*.jar', '*.har']) + testImplementation 'junit:junit:4.13' + ohosTestImplementation 'com.huawei.ohos.testkit:runner:1.0.0.100' implementation project(':library') - implementation 'com.github.bumptech.glide:glide:4.0.0' + +} +decc { + supportType = ['html','xml'] } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000000000000000000000000000000000000..f7666e47561d514b2a76d5a7dfbb43ede86da92a --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1 @@ +# config module specific ProGuard rules here. \ No newline at end of file diff --git a/app/src/androidTest/java/com/tylersuehr/chipexample/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/tylersuehr/chipexample/ExampleInstrumentedTest.java deleted file mode 100644 index fdbd862804cdbac37af2b07289c78c014a5719fd..0000000000000000000000000000000000000000 --- a/app/src/androidTest/java/com/tylersuehr/chipexample/ExampleInstrumentedTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.tylersuehr.chipexample; - -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -/** - * Instrumentation test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() throws Exception { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - assertEquals("com.tylersuehr.chips", appContext.getPackageName()); - } -} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml deleted file mode 100644 index 0430c9dce45d41835ee652453548ef13ea363ae1..0000000000000000000000000000000000000000 --- a/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/config.json b/app/src/main/config.json new file mode 100644 index 0000000000000000000000000000000000000000..2baf3fc2b843f7cae200196127694905c064cf51 --- /dev/null +++ b/app/src/main/config.json @@ -0,0 +1,58 @@ +{ + "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": ".MyApplication", + "deviceType": [ + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "app", + "moduleType": "entry" + }, + "metaData": { + "customizeData": [ + { + "name": "hwc-theme", + "value": "androidhwext:style/Theme.Emui.NoTitleBar", + "extra": "" + } + ] + }, + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "orientation": "unspecified", + "name": "com.tylersuehr.chipexample.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "label": "$string:app_name", + "type": "page", + "launchType": "standard" + } + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tylersuehr/chipexample/ContactChip.java b/app/src/main/java/com/tylersuehr/chipexample/ContactChip.java deleted file mode 100644 index f3f5ea1aba70a0ef3c8326345c9daf1d50153fe0..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/tylersuehr/chipexample/ContactChip.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.tylersuehr.chipexample; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import com.tylersuehr.chips.Chip; - -/** - * Copyright © 2017 Tyler Suehr - * - * @author Tyler Suehr - * @version 1.0 - */ -public class ContactChip extends Chip { - private int id; - private String name; - private String phone; - private String email; - private String phoneType; - - private Uri avatarUri; - private Drawable avatarDr; - - - public ContactChip() {} - - @Nullable - @Override - public Integer getId() { - return id; - } - - @NonNull - @Override - public String getTitle() { - return name; - } - - @Nullable - @Override - public String getSubtitle() { - if (phoneType != null && phone != null) { - return phoneType + ": " + phone; - } - return null; - } - - @Nullable - @Override - public Uri getAvatarUri() { - return avatarUri; - } - - @Nullable - @Override - public Drawable getAvatarDrawable() { - return avatarDr; - } - - public void setAvatarUri(Uri uri) { - this.avatarUri = uri; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getPhone() { - return phone; - } - - public void setPhone(String phone) { - this.phone = phone; - } - - public String getPhoneType() { - return phoneType; - } - - public void setPhoneType(String phoneType) { - this.phoneType = phoneType; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tylersuehr/chipexample/ContactLoadingActivity.java b/app/src/main/java/com/tylersuehr/chipexample/ContactLoadingActivity.java deleted file mode 100644 index 77d16964165c242140ee09f4fd8a5cbdf43dc88d..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/tylersuehr/chipexample/ContactLoadingActivity.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.tylersuehr.chipexample; -import android.Manifest; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.provider.ContactsContract; -import android.support.annotation.NonNull; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.ContextCompat; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v7.app.AppCompatActivity; -import android.widget.Toast; -import java.util.ArrayList; -import java.util.List; - -/** - * Copyright © 2017 Tyler Suehr - * - * This activity is just to load contact information on the phone using the LoaderManager - * APIs, and then callback with the data. - * - * The reason for this abstraction is so that it's easy to comprehend the code specific - * to the chips in {@link ExampleChipsActivity}, as this is an example to observe how - * to use the chips, not load contact information. - * - * Simply call {@link #loadContactsWithRuntimePermission()} to load contacts. Runtime - * permissions must be granted for API 23+ - * - * @author Tyler Suehr - * @version 1.0 - */ -abstract class ContactLoadingActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks { - @Override - public Loader onCreateLoader(int id, Bundle args) { - return new CursorLoader(this, - ContactsContract.CommonDataKinds.Phone.CONTENT_URI,// Content provider - null, null, null, - ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY + " ASC"); // OrderBy clause - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - // Collect all the contact information from the Cursor in a List - List chips = new ArrayList<>(data.getCount()); - for (int i = 0; i < data.getCount(); i++) { - data.moveToPosition(i); - - ContactChip chip = new ContactChip(); - chip.setId(i); - chip.setName(data.getString(data.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME))); - chip.setPhone(data.getString(data.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))); - int phoneType = data.getInt(data.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE)); - chip.setPhoneType(ContactsContract.CommonDataKinds.Phone.getTypeLabel(getResources(), phoneType, "").toString()); - - String avatar = data.getString(data.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI)); - if (avatar != null) { - chip.setAvatarUri(Uri.parse(avatar)); - } - - chips.add(chip); - } - - // Set the list of chips on the ChipsInput and normal adapter - onContactsAvailable(chips); - } - - @Override - public void onLoaderReset(Loader loader) { - onContactsReset(); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (requestCode == 0) { - // If the request is cancelled, the result arrays are empty - boolean allGranted = false; - for (int grantResult : grantResults) { - allGranted = grantResult == PackageManager.PERMISSION_GRANTED; - if (!allGranted) { break; } - } - - if (allGranted) { - // Permissions were granted, yay!! - getSupportLoaderManager().initLoader(0, null, this); - } else { - // Permissions were denied! User is a piece of shit - Toast.makeText(this, "Permissions are needed to load your contacts!", Toast.LENGTH_SHORT).show(); - finish(); - } - } - } - - protected void loadContactsWithRuntimePermission() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - // Runtime permission must be granted for - // (1) Reading contacts - // (2) Sending SMS messages - String[] permissions = new String[] { - Manifest.permission.READ_CONTACTS, - Manifest.permission.READ_PHONE_STATE - }; - - // If the app doesn't have all the permissions above, request for them! - if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED - && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { - getSupportLoaderManager().initLoader(0, null, this); - } else { - ActivityCompat.requestPermissions(this, permissions, 0); - } - } else { - // APIs older than Lollipop don't have runtime permissions :) - getSupportLoaderManager().initLoader(0, null, this); - } - } - - /** - * Called when the current user's contacts are available as a list of {@link ContactChip}. - * - * @param chips List of {@link ContactChip} - */ - protected abstract void onContactsAvailable(List chips); - - /** - * Called when the current user's contacts should be reset. - */ - protected abstract void onContactsReset(); -} \ No newline at end of file diff --git a/app/src/main/java/com/tylersuehr/chipexample/ContactOnChipAdapter.java b/app/src/main/java/com/tylersuehr/chipexample/ContactOnChipAdapter.java deleted file mode 100644 index 0e63b3b651d8a8476f2c47e34078e674f1d40e05..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/tylersuehr/chipexample/ContactOnChipAdapter.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.tylersuehr.chipexample; - -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import com.tylersuehr.chips.Chip; -import com.tylersuehr.chips.ChipDataSource; - -/** - * Copyright © 2017 Tyler Suehr - * - * @author Tyler Suehr - * @version 1.0 - */ -class ContactOnChipAdapter - extends RecyclerView.Adapter - implements ChipDataSource.ChangeObserver { - private final OnContactClickListener listener; - private ChipDataSource chipDataSource; - - - ContactOnChipAdapter(OnContactClickListener listener) { - this.listener = listener; - } - - @Override - public int getItemCount() { - return chipDataSource == null ? 0 : chipDataSource.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) { - Chip chip = chipDataSource.getFilteredChips().get(position); - holder.text.setText(chip.getTitle()); - holder.subtitle.setText(chip.getSubtitle()); - if (chip.getAvatarUri() != null) { - holder.image.setImageURI(chip.getAvatarUri()); - } else if (chip.getAvatarDrawable() != null) { - holder.image.setImageDrawable(chip.getAvatarDrawable()); - } else { - holder.image.setImageDrawable(null); - } - } - - @Override - public void onChipDataSourceChanged() { - notifyDataSetChanged(); - } - - void setChipDataSource(ChipDataSource chipDataSource) { - this.chipDataSource = chipDataSource; - notifyDataSetChanged(); - } - - interface OnContactClickListener { - void onContactClicked(ContactChip chip); - } - - - class Holder extends RecyclerView.ViewHolder implements View.OnClickListener { - TextView text, subtitle; - ImageView image; - - Holder(View v) { - super(v); - this.text = v.findViewById(R.id.title); - this.subtitle = v.findViewById(R.id.subtitle); - this.image = v.findViewById(R.id.image); - v.setOnClickListener(this); - } - - @Override - public void onClick(View v) { - final Chip clickedChip = chipDataSource.getFilteredChip(getAdapterPosition()); - - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tylersuehr/chipexample/ExampleChipsActivity.java b/app/src/main/java/com/tylersuehr/chipexample/ExampleChipsActivity.java deleted file mode 100644 index 6927219f594b4b30154c0acbfb69c1f61c932bc2..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/tylersuehr/chipexample/ExampleChipsActivity.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.tylersuehr.chipexample; -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.Toast; - -import com.tylersuehr.chips.ChipsInputLayout; -import java.util.List; - -/** - * Copyright © 2017 Tyler Suehr - * - * @author Tyler Suehr - * @version 1.0 - */ -public class ExampleChipsActivity extends ContactLoadingActivity - implements ContactOnChipAdapter.OnContactClickListener { - private ContactOnChipAdapter contactAdapter; - private ChipsInputLayout chipsInput; - - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_example_chips); - - // Setup toolbar - Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - - // Setup the recycler - this.contactAdapter = new ContactOnChipAdapter(this); - RecyclerView recycler = (RecyclerView)findViewById(R.id.recycler); - recycler.setLayoutManager(new LinearLayoutManager(this)); - recycler.setAdapter(contactAdapter); - - // Setup chips input - this.chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input); - - // Load the current user's contact information - loadContactsWithRuntimePermission(); - - recycler.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(ExampleChipsActivity.this, "Clicked", Toast.LENGTH_SHORT).show(); - } - }); - } - - /** - * When we have contact chips available, let's make them filterable in our ChipsInputView! - */ - @Override - protected void onContactsAvailable(List chips) { - System.out.println("Number of contacts: " + chips.size()); - this.chipsInput.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/GlideRenderer.java b/app/src/main/java/com/tylersuehr/chipexample/GlideRenderer.java deleted file mode 100644 index df093e3edcce579617b17cf7f79a67e2552a4dc8..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/tylersuehr/chipexample/GlideRenderer.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.tylersuehr.chipexample; - -import android.widget.ImageView; - -import com.bumptech.glide.Glide; -import com.tylersuehr.chips.ChipImageRenderer; -import com.tylersuehr.chips.LetterTileProvider; -import com.tylersuehr.chips.Chip; - -/** - * Copyright © 2017 Tyler Suehr - * - * Example of custom chip image renderer that uses Glide - * to load images. - * - * @author Tyler Suehr - * @version 1.0 - */ -class GlideRenderer implements ChipImageRenderer { - @Override - public void renderAvatar(ImageView imageView, Chip chip) { - if (chip.getAvatarUri() != null) { - Glide.with(imageView.getContext()) - .load(chip.getAvatarUri()) - .into(imageView); - } else { - imageView.setImageBitmap(LetterTileProvider - .getInstance(imageView.getContext()) - .getLetterTile(chip.getTitle())); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tylersuehr/chipexample/MainAbility.java b/app/src/main/java/com/tylersuehr/chipexample/MainAbility.java new file mode 100644 index 0000000000000000000000000000000000000000..2a7cdfed6797c2c5e74d8ae11506a4a857445c0a --- /dev/null +++ b/app/src/main/java/com/tylersuehr/chipexample/MainAbility.java @@ -0,0 +1,13 @@ +package com.tylersuehr.chipexample; + +import com.tylersuehr.chipexample.slice.MainAbilitySlice; +import ohos.aafwk.ability.Ability; +import ohos.aafwk.content.Intent; + +public class MainAbility extends Ability { + @Override + public void onStart(Intent intent) { + super.onStart(intent); + super.setMainRoute(MainAbilitySlice.class.getName()); + } +} diff --git a/app/src/main/java/com/tylersuehr/chipexample/MainActivity.java b/app/src/main/java/com/tylersuehr/chipexample/MainActivity.java deleted file mode 100644 index 9f6013efa46f46a9042dbd3debafaa0944ddb016..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/tylersuehr/chipexample/MainActivity.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.tylersuehr.chipexample; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.widget.Toolbar; -import android.view.View; -import android.widget.TextView; - -import com.tylersuehr.chips.ChipsInputLayout; - -import java.util.List; - -/** - * Copyright © 2017 Tyler Suehr - * - * @author Tyler Suehr - * @version 1.0 - */ -public class MainActivity extends ContactLoadingActivity - implements ContactOnChipAdapter.OnContactClickListener { - private ChipsInputLayout mChipsInput; - - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - // Setup toolbar - Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - - // Setup chips input - mChipsInput = (ChipsInputLayout)findViewById(R.id.chips_input); - mChipsInput.setImageRenderer(new GlideRenderer()); - - // Load the current user's contact information - loadContactsWithRuntimePermission(); - mChipsInput.getmChipsInput().setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mChipsInput.getmChipsInput().setFocusableInTouchMode(true); - } - }); - - TextView t=findViewById(R.id.t); - t.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mChipsInput.getmChipsInput().clearFocus(); - mChipsInput.getmChipsInput().setFocusableInTouchMode(false); - } - }); - } - - /** - * When we have contact chips available, let's make them filterable in our ChipsInputView! - */ - @Override - protected void onContactsAvailable(List 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 @@ - - - - - - - -