{"id":20756566,"url":"https://github.com/tylersuehr7/chips-input-layout","last_synced_at":"2025-04-05T20:08:01.426Z","repository":{"id":130831196,"uuid":"105960127","full_name":"tylersuehr7/chips-input-layout","owner":"tylersuehr7","description":"A customizable Android ViewGroup for displaying Chips (specified in the Material Design Guide). ","archived":false,"fork":false,"pushed_at":"2019-07-25T19:38:26.000Z","size":13290,"stargazers_count":583,"open_issues_count":24,"forks_count":64,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-03-29T19:06:17.423Z","etag":null,"topics":["android","android-viewgroup","chip","chips","chips-view","contacts","custom-chips","design","filter","filter-existing-chips","filterable","material","view","viewgroup"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tylersuehr7.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-10-06T02:21:59.000Z","updated_at":"2024-11-05T20:38:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"b340c302-bdcb-4b1d-a22e-63c616c0ce7a","html_url":"https://github.com/tylersuehr7/chips-input-layout","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylersuehr7%2Fchips-input-layout","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylersuehr7%2Fchips-input-layout/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylersuehr7%2Fchips-input-layout/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylersuehr7%2Fchips-input-layout/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tylersuehr7","download_url":"https://codeload.github.com/tylersuehr7/chips-input-layout/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247393570,"owners_count":20931812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-viewgroup","chip","chips","chips-view","contacts","custom-chips","design","filter","filter-existing-chips","filterable","material","view","viewgroup"],"created_at":"2024-11-17T09:33:26.794Z","updated_at":"2025-04-05T20:08:01.370Z","avatar_url":"https://github.com/tylersuehr7.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Chips Input Layout\nA highly customizable Android ViewGroup for displaying Chips (specified in the Material Design Guide)!\n\n\u003cimg src=\"https://github.com/tylersuehr7/chips-input-layout/blob/master/docs/screen_filterable_list.png\" width=\"200\"\u003e \u003cimg src=\"https://github.com/tylersuehr7/chips-input-layout/blob/master/docs/screen_contact_chip_multiple.png\" width=\"200\"\u003e \u003cimg src=\"https://github.com/tylersuehr7/chips-input-layout/blob/master/docs/screen_chips_multiple.png\" width=\"200\"\u003e \u003cimg src=\"https://github.com/tylersuehr7/chips-input-layout/blob/master/docs/screen_contact_chip_details.png\" width=\"200\"\u003e\n\nHow to use it...\n\nIn your project level build.gradle :\n```java\nallprojects {\n    repositories {\n        ...\n        maven { url \"https://jitpack.io\" }\n    }\n} \n```\n\nIn your app level build.gradle:\n```java\ndependencies {\n    compile 'com.github.tylersuehr7:chips-input-layout:2.3'\n}  \n```\n\nCore features of this library:\n* Use libraries (Glide, Picasso,...) to load chip avatars\n* Filter chips as user inputs text\n* Allow user to create custom chips\n* Specify if chips show details, are deletable, or have an avatar\n* Specify how chips are managed/stored in-memory\n* Validate any chips\n* Highly customizable chips\n* Strictly sticks to the Google Material Design Guide\n\n*Honorable Mentions:*\n* This uses a RecyclerView layout manager: https://github.com/BelooS/ChipsLayoutManager\n\n## Using the `ChipsInputLayout`\nThe 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.\n\n### Using in an XML layout\n`ChipsInputLayout` can be used in any ViewGroup and supports all width and height attributes. Simple usage is shown here:\n```xml\n\u003ccom.tylersuehr.chips.ChipsInputLayout\n        android:id=\"@+id/chips_input\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"Start typing for chips... \"\n        android:textColorHint=\"#757575\"\n        android:textColor=\"#212121\"\n        app:chip_showDetails=\"true\"/\u003e\n```\n\nHere is a table of all the XML attributes available for this view:\n\nAttribute | Type | Summary\n--- | :---: | ---\n`android:hint` | `string` | Hint shown in the chips input.\n`android:textColorHint` | `color` | Text color of the hint shown in the chips input. \n`android:textColor` | `color` | Text color of chips input.\n`app:allowCustomChips` | `boolean` | True if user is allowed to enter custom chips.\n`app:hideKeyboardOnChipClick` | `boolean` | True if the keyboard should hide when a filterable chip is clicked.\n`app:maxRows` | `int` | Maximum number of rows used to display chips.\n`app:delimiter` | `string` | A custom delimiter used to submit new chips.\n`app:delimiterRegex` | `boolean` | True if `app:delimiter` is a regular expression.\n`app:chip_showDetails` | `boolean` | True if clicking a chip should show its details.\n`app:chip_showAvatar` | `boolean` | True if each chip should show an avatar icon.\n`app:chip_showDelete` | `boolean` | True if each chip should be deletable by the user.\n`app:chip_deleteIcon` | `reference` | Changes the chips' delete icons.\n`app:chip_deleteIconColor` | `color` | Color of each chips' delete icon.\n`app:chip_backgroundColor` | `color` | Color of each chips' background.\n`app:chip_textColor` | `color` | Text color of each chips' title and subtitle.\n`app:details_deleteIconColor` | `color` | Color of each detailed chips' delete icon.\n`app:details_backgroundColor` | `color` | Color of each detailed chips' background.\n`app:details_textColor` | `color` | Text color of each detailed chips' title and subtitle.\n`app:filter_elevation` | `dimension` | Elevation of the filterable list.\n`app:filter_backgroundColor` | `color` | Color of the filterable list's background.\n`app:filter_textColor` | `color` | Text color of the filterable list's items.\n\n### Using in Java code\n`ChipsInputLayout` can be programmatically added into any ViewGroup. Simple usage in an Activity is shown here:\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    \n    ChipsInputLayout chipsInputLayout = new ChipsInputLayout(this);\n    // Set any properties for chips input layout\n    \n    setContentView(chipsInputLayout);\n}\n```\n\nHere is a table of all the accessible attributes available for this view:\n\nMethod | Summary\n--- | ---\n`setInputHint(CharSequence)` | Changes hint shown in the chips input.\n`setInputHintTextColor(ColorStateList)` | Changes text color of the hint shown in the chips input. \n`setInputTextColor(ColorStateList)` | Changes text color of chips input.\n`setShowDetailedChipsEnabled(boolean)` |  True if clicking a chip should show its details.\n`setCustomChipsEnabled(boolean)` | True if user is allowed to enter custom chips.\n`setHideKeyboardOnChipClick(boolean)` | True if the keyboard should hide when filterable chip is clicked.\n`setMaxRows(int)` | Changes maximum number of rows used to display chips.\n`setTypeface(Typeface)` | Changes the typeface of the ChipsInputLayout and all associated textual-based components.\n`setDelimiter(String)` | Sets the customer delimiter to be used to separate new chips.\n`setDelimiter(String, boolean)` | Sets the customer delimiter to be used to separate new chips. Boolean is whether string is a regular expression or not.\n`setChipTitleTextColor(ColorStateList)` | Changes text color of each chips' title and subtitle.\n`setShowChipAvatarEnabled(boolean)` | True if each chip should show an avatar icon.\n`setChipsDeletable(boolean)` | True if each chip should be deletable by the user.\n`setChipDeleteIconColor(ColorStateList)` | Changes color of each chips' delete icon.\n`setChipBackgroundColor(ColorStateList)` | Changes color of each chips' background.\n`setChipDeleteIcon(Drawable)` | Changes the each chips' delete icon.\n`setChipDeleteIcon(int)` | Overload of setChipDeleteIcon(Drawable).\n`setChipDetailsTextColor(ColorStateList)` | Changes text color of each detailed chips' title and subtitle.\n`setChipDetailsBackgroundColor(ColorStateList)` | Changes color of each detailed chips' background.\n`setChipDetailsDeleteIconColor(ColorStateList)` | Changes color of each detailed chips' delete icon.\n`setFilterListBackgroundColor(ColorStateList)` | Changes color of the filterable list's background.\n`setFilterListTextColor(ColorStateList)` | Changes text color of the filterable list's items.\n`setFilterListElevation(float)` | Changes elevation of the filterable list.\n`setInputType(int)` | Sets the text input type on the ChipsEditText.\n`setOnChipsInputTextChangedListener(OnChipsInputTextChangedListener)` | Sets a text changed listener that gets invoked when text it changed on the ChipsEditText.\n\n## Using the Chips\nThere 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.\n\n### Creating a chip\n`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! \n\nHere's a small example:\n```java\npublic class CoolChip extends Chip {\n    private final String coolName;\n    private final Uri coolPic;\n    \n    public CoolChip(String coolName, Uri coolPic) {\n        this.coolName = coolName;\n        this.coolPic = coolPic;\n    }\n    \n    Override\n    public String getTitle() {\n        return coolName;\n    }\n    \n    @Override\n    public Uri getAvatarUri() {\n        return coolPic;\n    }\n    \n    // ...other chip methods that are required to implement\n}\n```\n\n### Setting a filterable list of chips in `ChipsInputLayout`\n`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`.\n\nNot 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.\n\nHere is a simple example:\n``` java\n@Override\nprotected void onCreate(List\u003cContactChip\u003e chips) {\n    // ...Cool onCreate stuff in activity\n    \n    ChipsInputLayout chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input);\n    \n    // ...Cool logic to acquire chips\n    List\u003cAwesomeChip\u003e chips = getReallyCoolChips();\n        \n    this.chipsInput.setFilterableChipList(chips);\n}\n```\n\n### Setting a pre-selected list of chips in `ChipsInputLayout`\n`ChipsInputLayout` supports the ability to set an already-selected list of chips. To use this feature, simply call `setSelectedChipList(List)` in `ChipsInputLayout`.\n\nHere is a simple example:\n```java\n@Override\nprotected void onCreate(List\u003cContactChip\u003e chips) {\n    // ...Cool onCreate stuff in activity\n    \n    ChipsInputLayout chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input);\n    \n    // ...Cool logic to acquire chips\n    List\u003cTagChip\u003e defaultChips = getDefaultTagChips();\n        \n    this.chipsInput.setSelectedChipList(chips);\n}\n```\n\n### Other chip manipulation methods in `ChipsInputLayout`\n\nMethod | Summary\n--- | ---\n`addFilteredChip(Chip)` | Adds a new chip to the filterable chips, which will update the UI accordingly because of the change observers.\n`addSelectedChip(Chip)` | Adds a new chip to the selected chips, which will update the UI accordingly because of the change observers.\n`clearFilteredChips()` | Clears all the filterable chips, which will update the UI accordingly because of the change observers.\n`clearSelectedChips()` | Clears all the selected chips, which will update the UI accordingly because of the change observers.\n`getSelectedChips()` | Gets all the currently selected chips.\n`getFilteredChips()` | Gets all the currently filtered chips.\n`getOriginalFilterableChips()` | Gets all the originally set filterable chips.\n`getSelectedChipByPosition(int)` | Gets a selected chip using the given index.\n`getSelectedChipById(Object id)` | Gets a selected chip using the given ID, if possible.\n`getSelectedChipByTitle(String, boolean)` | Gets a selected chip with exactly the given title or like the given title.\n`getSelectedChipBySubtitle(String, boolean)` | Gets a selected chip with exactly the given subtitle or like the given subtitle.\n`getFilteredChipPosition(int)` | Gets a filtered chip using the given index.\n`getFilteredChipById(Object)` | Gets a filtered chip using the given ID, if possible.\n`getFilteredChipByTitle(String, boolean)` | Gets a filtered chip with exactly the given title or like the given title.\n`getFilteredChipBySubtitle(String, boolean)` | Gets a filtered chip with exactly the given subtitle or like the given subtitle.\n`doesChipExist(Chip)` | Checks if the given chip exists in either the filterable or selected chips.\n`isChipFiltered(Chip)` | Checks if the given chip exists in the filtered chips.\n`isChipSelected(Chip)` | Checks if the given chip exists in the selected chips.\n`getChipDataSource()` | Gets the currently used chip data source.\n`changeChipDataSource(ChipDataSource)` | Changes the chip data source being used to manage chips, cloning existing observers.\n\n## Managing the Chips\nWhere 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. \n\nAll 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`.\n\nAlthough 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.\n\nBy 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.\n\n### Observing chip selection changes\n`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.\n\nTo 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. \n\nTo set the observer, you'll need to call the `addSelectionObserver(ChipDataSource.SelectionObserver)` method in `ChipsInputLayout`.\n\nHere is a simple example:\n```java\npublic class CoolActivity extends AppCompatActivity implements ChipDataSource.SelectionObserver {\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_cool);\n        \n        // Get the ChipsInputLayout from the layout file\n        ChipsInputLayout chipsInput = (ChipsInputLayout)findViewById(R.id.chips);\n        chipsInput.addSelectionObserver(this);\n    }\n    \n    @Override\n    public void onChipSelected(Chip selectedChip) {\n        // Cool chip selection stuff here...\n    }\n    \n    @Override\n    public void onChipUnselected(Chip unselectedChip) {\n        // Cool chip unselection stuff here...\n    }\n}\n```\n\n### Observing any change to the chip data source\n`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. \n\nThis is used internally by the library to trigger UI updates on `RecyclerView` adapters when the data has changed.\n\nTo 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. \n\nTo set the observer, you'll need to call the `addChangeObserver(ChipDataSource.ChangeObserver)` method in `ChipsInputLayout`.\n\nHere is a simple example:\n```java\npublic class CoolAdapter extends RecyclerView.Adapter\u003cRecyclerView.ViewHolder\u003e implements ChipDataSouce.ChangeObserver {\n    public CoolAdapter(ChipDataSource dataSource) {\n        dataSource.addChangeObserver(this);\n    }\n    \n    // adapter implementation to do really cool adapter stuff...\n    \n    @Override\n    public void onChipDataSourceChanged() {\n        // This example would just update the Recycler when the chip data source changes\n        notifyDataSetChanged();\n    }\n}\n```\n\n## Using Image Loading Libraries (Glide, Picasso,...)\nThis 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. \n\nBy 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`.\n\nHere's a small example (using Glide):\n```java\npublic class GlideRenderer implements ChipImageRenderer {\n    @Override\n    public void renderAvatar(ImageView imageView, Chip chip) {\n        if (chip.getAvatarUri() != null) {\n            // Use Glide to load URL (provided in avatar uri)\n            Glide.with(imageView.getContext())\n                    .load(chip.getAvatarUri())\n                    .into(imageView);\n        } else {\n            // Default to circular tile if no uri exists\n            imageView.setImageBitmap(LetterTileProvider\n                    .getInstance(imageView.getContext())\n                    .getLetterTile(chip.getTitle()));\n        }\n    }\n}\n\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_cool);\n    \n    // Find out chips input layout in xml layout\n    ChipsInputLayout chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input);\n    \n    // Set the custom image renderer for chip avatars\n    chipsInput.setImageRenderer(new GlideRenderer());\n}\n```\n\n## Chip Validation\nThis 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.\n\nValidation 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.\n\n### Creating a chip validator\n`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.\n\nHere's a small example:\n```java\npublic class CustomChipValidator implements ChipsInputLayout.ChipValidator {\n    @Override\n    public boolean validate(Chip chip) {\n        // This example will make the chip valid if the chip's title contains the letter \"T\"\n        return chip.getTitle().toLowerCase().contains(\"t\");\n    }\n}\n```\n\n### Setting a chip validator\nA custom implementation of `ChipValidator` can be set using the `ChipsInputLayout`. Simply call the `setChipValidator(ChipValidator)` method in `ChipsInputLayout`.\n\nHere's a simple example:\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_cool);\n    \n    // Find out chips input layout in xml layout\n    ChipsInputLayout chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input);\n    \n    // Set an instance of chip validator in chips input layout\n    chipsInput.setChipValidator(new MyCoolChipValidator());\n}\n```\n\n### Using a chip validator\nUsing 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. \n\nValidating 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.\n\nHere's a simple example:\n```java\npublic class CoolActivity extends AppCompatActivity {\n    private ChipsInputLayout chipsInput;\n    \n    \n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_cool);\n        \n        // Find chips input layout in XML layout\n        this.chipsInput = (ChipsInputLayout)findViewById(R.id.chips_input);\n        \n        // Set custom chip validator\n        this.chipsInput.setChipValidator(new MyCoolChipValidator());\n    }\n    \n    public void onCoolButtonClicked(View v) {\n        // Example to show selected chip validation\n        if (chipsInput.validateSelectedChips()) {\n            Toast.makeText(this, \"Selected chips are valid!\", Toast.LENGTH_SHORT).show();\n        } else {\n            Toast.makeText(this, \"Selected chips are NOT valid!\", Toast.LENGTH_SHORT).show();\n        }\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftylersuehr7%2Fchips-input-layout","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftylersuehr7%2Fchips-input-layout","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftylersuehr7%2Fchips-input-layout/lists"}