mTagViewList = new ArrayList<>();
57 |
58 | private EditText editText;
59 | private RecyclerView recyclerView;
60 | private TextView textViewAdd;
61 |
62 | private TagViewAdapter mAdapter;
63 |
64 | private final String EMPTY_STRING = "";
65 | private final String DEFAULT_TAG_LIMIT_MESSAGE = "You reach maximum tags";
66 |
67 | /**
68 | * This is Default Tab separator.
69 | * User can add different tab separator
70 | *
71 | * Tag separator must be a single character.
72 | *
73 | * And the Tag separator will be special character
74 | */
75 | private String tagSeparator = TagSeparator.valueOf(TagSeparator.COMMA_SEPARATOR.name()).getValue();
76 |
77 |
78 | /**
79 | * The tagLimit define how many tag will show
80 | * Default it take maximum value.
81 | * It not Take 0/Zero value
82 | */
83 | private int tagLimit = Integer.MAX_VALUE;
84 |
85 | /**
86 | * Tag view Background color
87 | */
88 | private int tagBackgroundColor;
89 |
90 | private int mTagTextColor;
91 |
92 | private String mTagLimitMessage;
93 |
94 | /**
95 | * The both drawable and bitmap enable only when
96 | * other is null.
97 | * N.B: Both can be null
98 | */
99 | private Drawable mCrossDrawable;
100 | private Bitmap mCrossBitmap;
101 |
102 | private TagItemListener mTagItemListener;
103 |
104 | private List mTagItemList = new ArrayList<>();
105 |
106 | public TagView(Context context) {
107 | super(context);
108 | }
109 |
110 | public TagView(Context context, AttributeSet attrs) {
111 | super(context, attrs);
112 |
113 | setFlexWrap(FlexWrap.WRAP);
114 |
115 | setJustifyContent(JustifyContent.FLEX_START);
116 |
117 | tagBackgroundColor = getResources().getColor(R.color.tag_bg);
118 |
119 | mTagTextColor = getResources().getColor(R.color.white);
120 |
121 | mAdapter = new TagViewAdapter(mTagTextColor, tagBackgroundColor);
122 |
123 | addEditText();
124 |
125 | init(attrs);
126 |
127 | }
128 |
129 | private void init(AttributeSet attributeSet) {
130 | TypedArray typedArray = getContext().obtainStyledAttributes(attributeSet, R.styleable.TagView);
131 |
132 | mTagTextColor = typedArray.getColor(R.styleable.TagView_tag_text_color, getResources().getColor(R.color.white));
133 |
134 | tagBackgroundColor = typedArray.getColor(R.styleable.TagView_tag_background_color, getResources().getColor(R.color.tag_bg));
135 |
136 | tagLimit = typedArray.getInt(R.styleable.TagView_tag_limit, 1);
137 |
138 | mCrossDrawable = typedArray.getDrawable(R.styleable.TagView_close_icon);
139 |
140 | mTagLimitMessage = typedArray.getString(R.styleable.TagView_limit_error_text);
141 |
142 |
143 | int separator = typedArray.getInt(R.styleable.TagView_tag_separator, 0);
144 |
145 | tagSeparator = convertSeparator(separator);
146 |
147 | typedArray.recycle();
148 | }
149 |
150 | /**
151 | * Adding a tag view in Main view
152 | */
153 | private void addTagInView() {
154 | final TagModel model = mTagList.get(mTagList.size() - 1);
155 |
156 | final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
157 | final View tagView = inflater.inflate(R.layout.tag_layout, null);
158 |
159 | TextView tagTextView = tagView.findViewById(R.id.text_view_tag);
160 |
161 | ImageView imageView = tagView.findViewById(R.id.image_view_cross);
162 |
163 | LinearLayout linearLayout = tagView.findViewById(R.id.tag_container);
164 |
165 | GradientDrawable drawable = (GradientDrawable) linearLayout.getBackground();
166 |
167 | drawable.setColor(tagBackgroundColor);
168 |
169 | tagTextView.setTextColor(mTagTextColor);
170 |
171 | if (mCrossBitmap != null) {
172 | imageView.setImageBitmap(mCrossBitmap);
173 | } else if (mCrossDrawable != null) {
174 | imageView.setImageDrawable(mCrossDrawable);
175 | }
176 |
177 | /*
178 | * Here we remove the tag
179 | * */
180 | imageView.setOnClickListener(new OnClickListener() {
181 | @Override
182 | public void onClick(View view) {
183 | removeView(tagView);
184 | mTagList.remove(model);
185 |
186 | if (model.isFromList()) {
187 | mAdapter.addItem(model.getTagText());
188 | }
189 |
190 | if (mTagItemListener != null) {
191 | mTagItemListener.onGetRemovedItem(model);
192 | }
193 |
194 | invalidate();
195 | }
196 | });
197 |
198 | tagTextView.setText(model.getTagText());
199 |
200 | this.addView(tagView, mTagList.indexOf(model));
201 |
202 | if (mTagItemListener != null) {
203 | mTagItemListener.onGetAddedItem(model);
204 | }
205 |
206 | // mTagViewList.add(view);
207 |
208 | invalidate();
209 |
210 | }
211 |
212 | /**
213 | * First add an Edit text to show edit form where user can create a tag
214 | */
215 | private void addEditText() {
216 | editText = new EditText(getContext());
217 |
218 | recyclerView = new RecyclerView(getContext());
219 |
220 | textViewAdd = new TextView(getContext());
221 |
222 | editText.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
223 |
224 |
225 | editText.addTextChangedListener(new TextWatcher() {
226 | @Override
227 | public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
228 |
229 | }
230 |
231 | @Override
232 | public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
233 |
234 | }
235 |
236 | @Override
237 | public void afterTextChanged(Editable editable) {
238 | if (editable.toString().contains(tagSeparator)) {
239 | if (mTagList.size() < tagLimit) {
240 | String tagText = editable.toString();
241 | tagText = tagText.replace(tagSeparator, EMPTY_STRING);
242 |
243 | addTag(tagText, false);
244 |
245 | editText.setText("");
246 | } else {
247 | showTagLimitMessage();
248 | }
249 |
250 | } else {
251 | mAdapter.getFilter().filter(editable.toString());
252 | mAdapter.notifyDataSetChanged();
253 |
254 | if (mAdapter.getItemCount() == 0) {
255 | textViewAdd.setVisibility(VISIBLE);
256 | recyclerView.setVisibility(GONE);
257 | textViewAdd.setText(editable.toString());
258 | } else {
259 | textViewAdd.setVisibility(GONE);
260 | recyclerView.setVisibility(VISIBLE);
261 | }
262 | }
263 |
264 | if (editable.toString().isEmpty()) {
265 | textViewAdd.setVisibility(GONE);
266 | recyclerView.setVisibility(VISIBLE);
267 | }
268 | }
269 | });
270 |
271 |
272 | }
273 |
274 | private String convertSeparator(int separator) {
275 | String tagSeparator = "";
276 | switch (separator) {
277 | case 1:
278 | tagSeparator = TagSeparator.valueOf(TagSeparator.COMMA_SEPARATOR.name()).getValue();
279 | break;
280 | case 2:
281 | tagSeparator = TagSeparator.valueOf(TagSeparator.PLUS_SEPARATOR.name()).getValue();
282 | break;
283 | case 3:
284 | tagSeparator = TagSeparator.valueOf(TagSeparator.MINUS_SEPARATOR.name()).getValue();
285 | break;
286 | case 4:
287 | tagSeparator = TagSeparator.valueOf(TagSeparator.SPACE_SEPARATOR.name()).getValue();
288 | break;
289 | case 5:
290 | tagSeparator = TagSeparator.valueOf(TagSeparator.AT_SEPARATOR.name()).getValue();
291 | break;
292 | case 6:
293 | tagSeparator = TagSeparator.valueOf(TagSeparator.HASH_SEPARATOR.name()).getValue();
294 | break;
295 | }
296 | return tagSeparator;
297 | }
298 |
299 | /**
300 | * Add a Tag or Create a Tag.
301 | *
302 | * @param text It takes String and create a mode {@link TagModel}
303 | */
304 | private void addTag(String text, boolean isFromList) {
305 | if (text == null) {
306 | text = EMPTY_STRING;
307 | }
308 |
309 | TagModel model = new TagModel();
310 | model.setTagText(text);
311 | model.setFromList(isFromList);
312 |
313 | mTagList.add(model);
314 |
315 | addTagInView();
316 | }
317 |
318 | /**
319 | * Add recycler view if item list available.
320 | * first the item will be invisible.
321 | * Latter the item will add according user input.
322 | * If not matching item, the editor text will add in recycler view item temporary to select or add
323 | * Tag
324 | */
325 | private void addRecyclerView() {
326 | recyclerView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
327 |
328 | textViewAdd.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
329 | textViewAdd.setGravity(Gravity.CENTER);
330 | textViewAdd.setPadding(4, 0, 4, 0);
331 | textViewAdd.setBackground(getResources().getDrawable(R.drawable.drawable_tag));
332 |
333 | GradientDrawable drawable = (GradientDrawable) textViewAdd.getBackground();
334 | drawable.setColor(tagBackgroundColor);
335 |
336 | textViewAdd.setTextColor(mTagTextColor);
337 |
338 | textViewAdd.setOnClickListener(new OnClickListener() {
339 | @Override
340 | public void onClick(View view) {
341 | if (mTagList.size() < tagLimit) {
342 | addTag(textViewAdd.getText().toString(), false);
343 | textViewAdd.setText("");
344 | textViewAdd.setVisibility(GONE);
345 | recyclerView.setVisibility(VISIBLE);
346 | editText.setText("");
347 | } else {
348 | showTagLimitMessage();
349 | }
350 |
351 | }
352 | });
353 |
354 | this.addView(editText);
355 | if (mTagItemList != null) {
356 | FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(getContext());
357 |
358 | layoutManager.setJustifyContent(JustifyContent.FLEX_START);
359 | layoutManager.setFlexWrap(FlexWrap.WRAP);
360 | recyclerView.setLayoutManager(layoutManager);
361 |
362 | recyclerView.setAdapter(mAdapter);
363 |
364 | // set adapter click listener
365 | mAdapter.setTagClickListener(this);
366 |
367 | mAdapter.addItems(mTagItemList);
368 |
369 | }
370 |
371 | this.addView(recyclerView);
372 |
373 | this.addView(textViewAdd);
374 | textViewAdd.setVisibility(GONE);
375 |
376 |
377 | invalidate();
378 | }
379 |
380 | private void showTagLimitMessage() {
381 | if (mTagLimitMessage != null) {
382 | Toast.makeText(getContext(), mTagLimitMessage, Toast.LENGTH_SHORT).show();
383 | } else {
384 | Toast.makeText(getContext(), DEFAULT_TAG_LIMIT_MESSAGE, Toast.LENGTH_SHORT).show();
385 | }
386 | }
387 |
388 | @Override
389 | public void onGetSelectTag(int position, String tagText) {
390 | // We get tag item. we have to add tag
391 |
392 | addTag(tagText, true);
393 |
394 | mAdapter.removeTagItem(position, tagText);
395 | }
396 |
397 |
398 | /*
399 | * User setter method
400 | * */
401 |
402 |
403 | /**
404 | * User can set hint of edit text
405 | *
406 | * @param hint This take only String. If it get null it will convert null to Empty String
407 | */
408 | public void setHint(String hint) {
409 | if (hint == null) {
410 | hint = EMPTY_STRING;
411 | }
412 | editText.setHint(hint);
413 | }
414 |
415 | /**
416 | * Add Tag separator within Defined Separator
417 | *
418 | * @param separator This is Tag separator. It contains only
419 | * few separator {@link TagSeparator}
420 | */
421 | public void addTagSeparator(Enum separator) {
422 |
423 | TagSeparator tagSeparator = TagSeparator.valueOf(separator.name());
424 |
425 | this.tagSeparator = tagSeparator.getValue();
426 | Log.d("TagTest", tagSeparator.getValue());
427 |
428 | }
429 |
430 | /**
431 | * User can set tag limit but never set zero
432 | *
433 | * @param limit Integer value
434 | */
435 | public void addTagLimit(int limit) {
436 | if (limit == 0) {
437 | limit = 1;
438 | }
439 | tagLimit = limit;
440 | }
441 |
442 | /**
443 | * User can set Integer color
444 | *
445 | * @param color Integer Color
446 | */
447 | public void setTagBackgroundColor(int color) {
448 | tagBackgroundColor = color;
449 |
450 | mAdapter.addTagBackgroundColor(tagBackgroundColor);
451 | }
452 |
453 | /**
454 | * User can set background as String color
455 | *
456 | * @param color String color code
457 | */
458 | public void setTagBackgroundColor(String color) {
459 | tagBackgroundColor = Color.parseColor(color);
460 |
461 | mAdapter.addTagBackgroundColor(tagBackgroundColor);
462 | }
463 |
464 | /**
465 | * User can set/ change tag text color
466 | *
467 | * @param color {@link Integer}
468 | */
469 | public void setTagTextColor(int color) {
470 | mTagTextColor = color;
471 |
472 | mAdapter.addTagTextColor(mTagTextColor);
473 | }
474 |
475 | /**
476 | * User can set/ change tag text color
477 | *
478 | * @param color {@link String}
479 | */
480 | public void setTagTextColor(String color) {
481 | mTagTextColor = Color.parseColor(color);
482 |
483 | mAdapter.addTagTextColor(mTagTextColor);
484 | }
485 |
486 | /**
487 | * User can modify default tag limit message
488 | *
489 | * @param message User defined message
490 | */
491 | public void setMaximumTagLimitMessage(String message) {
492 | if (TextUtils.isEmpty(message)) {
493 | mTagLimitMessage = DEFAULT_TAG_LIMIT_MESSAGE;
494 | } else {
495 | mTagLimitMessage = message;
496 | }
497 | }
498 |
499 | /**
500 | * User can change cross button as drawable
501 | *
502 | * @param crossDrawable It takes resources drawable
503 | */
504 | public void setCrossButton(Drawable crossDrawable) {
505 | mCrossDrawable = crossDrawable;
506 | mCrossBitmap = null;
507 | }
508 |
509 | /**
510 | * User can change cross button as bitmap
511 | *
512 | * @param crossBitmap It takes Bitmap
513 | */
514 | public void setCrossButton(Bitmap crossBitmap) {
515 | mCrossDrawable = null;
516 | mCrossBitmap = crossBitmap;
517 | }
518 |
519 | /**
520 | * User can notify when Tag item added or removed
521 | *
522 | * @param listener {@link TagItemListener}
523 | */
524 | public void initTagListener(TagItemListener listener) {
525 | mTagItemListener = listener;
526 | }
527 |
528 | /**
529 | * This is the main challenging part of
530 | * TagView. Tag list will show when user will write in editText
531 | * and user click will add a tag
532 | *
533 | * @param tagList List of String
534 | */
535 | public void setTagList(List tagList) {
536 | if (tagList == null) {
537 | tagList = new ArrayList<>();
538 | }
539 | mTagItemList = tagList;
540 |
541 | addRecyclerView();
542 | }
543 |
544 | /**
545 | * User Can provide tag list as String array
546 | *
547 | * @param tagList It is string array
548 | */
549 | public void setTagList(String... tagList) {
550 | List tempList = Arrays.asList(tagList);
551 |
552 | mTagItemList.addAll(tempList);
553 |
554 | addRecyclerView();
555 | }
556 |
557 | /**
558 | * User can get all selected Tag list
559 | *
560 | * @return {@link TagModel} of List
561 | */
562 | public List getSelectedTags() {
563 | return mTagList;
564 | }
565 |
566 | }
567 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
146 |
147 |
148 |
149 | addRecy
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 | 1552901564465
451 |
452 |
453 | 1552901564465
454 |
455 |
456 | 1553081100481
457 |
458 |
459 |
460 | 1553081100481
461 |
462 |
463 | 1565260300976
464 |
465 |
466 |
467 | 1565260300976
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 | 1.8
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
--------------------------------------------------------------------------------