How to add chips from Material Components library to input field in android?

后端 未结 4 655
长情又很酷
长情又很酷 2020-12-07 23:43

I\'ve seen that in android-P google add new material components library which contains material chips:

Material components for android

Material.io chips us

相关标签:
4条回答
  • 2020-12-07 23:52

    We can do this by using material chips design itself without adding any extra styles.

    Add it on app gradle For AndroidX

    implementation 'com.google.android.material:material:1.0.0-beta01'

    For earlier than AndroidX use this

    implementation 'com.android.support:design:28.0.0'

    Fragment

    class EntryChipDemoFragment : Fragment() {
        private lateinit var mView: View
    
        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                                  savedInstanceState: Bundle?): View? {
            mView = inflater.inflate(R.layout.fragment_entry_chip_demo, container, false)
    
            mView.etValue.setOnEditorActionListener(TextView.OnEditorActionListener { v, actionId, _ ->
                if (actionId == EditorInfo.IME_ACTION_DONE) {
                    val txtVal = v.text
                    if(!txtVal.isNullOrEmpty()) {
                        addChipToGroup(txtVal.toString(), mView.chipGroup2)
                        mView.etValue.setText("")
                    }
    
                    return@OnEditorActionListener true
                }
                false
            })
    
            return mView
        }
    
    
        private fun addChipToGroup(txt: String, chipGroup: ChipGroup) {
            val chip = Chip(context)
            chip.text = txt
    //        chip.chipIcon = ContextCompat.getDrawable(requireContext(), baseline_person_black_18)
            chip.isCloseIconEnabled = true
            chip.setChipIconTintResource(R.color.chipIconTint)
    
            // necessary to get single selection working
            chip.isClickable = false
            chip.isCheckable = false
            chipGroup.addView(chip as View)
            chip.setOnCloseIconClickListener { chipGroup.removeView(chip as View) }
            printChipsValue(chipGroup)
        }
    
        private fun printChipsValue(chipGroup: ChipGroup) {
            for (i in 0 until chipGroup.childCount) {
                val chipObj = chipGroup.getChildAt(i) as Chip
                Log.d("Chips text :: " , chipObj.text.toString())
    
            }
        }
    
        companion object {
            @JvmStatic
            fun newInstance() = EntryChipDemoFragment()
        }
    }
    

    XML File:

    <HorizontalScrollView
        android:id="@+id/chipGroup2HorizontalView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:scrollbars="none"
        app:layout_constraintVertical_bias="0.62">
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:orientation="horizontal">
    
            <androidx.appcompat.widget.AppCompatTextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Skills: " />
    
            <com.google.android.material.chip.ChipGroup
                android:id="@+id/chipGroup2"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:duplicateParentState="false">
    
            </com.google.android.material.chip.ChipGroup>
    
            <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/textInputLayout"
                android:layout_width="wrap_content"
                android:layout_height="43dp"
                android:layout_marginStart="8dp"
                android:layout_marginEnd="8dp"
                android:layout_marginBottom="5dp"
                android:minWidth="32dp"
                android:visibility="visible"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@id/chipGroup2HorizontalView"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintWidth_min="32dp">
    
                <androidx.appcompat.widget.AppCompatEditText
                    android:id="@+id/etValue"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@android:color/transparent"
                    android:imeOptions="actionDone"
                    android:maxLines="1"
                    android:singleLine="true" />
    
            </com.google.android.material.textfield.TextInputLayout>
    
        </LinearLayout>
    
    
    </HorizontalScrollView>
    

    For more reference Click Here

    0 讨论(0)
  • 2020-12-08 00:04

    Answer

    No default input field for adding chips in android. They mentioned input chips but i didn't find any layout or viewgroup for input chips. So i do with Chipdrawable method to add chips in edittext. Here am using AppCompatEdittext you can change to anyview which listening the text inputs. Reference.

    Step 1

    Add chip xml resource. chip.xml

    res -> xml -> chip.xml

    <?xml version="1.0" encoding="utf-8"?>
    <chip xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:textAppearance="@style/ChipTextApperance"
     app:chipBackgroundColor="@color/colorAccent"
     app:chipIcon="@drawable/ic_call_white_24dp"
     app:closeIconEnabled="true"  <!--property for close icon if no need set to false. -->
     app:closeIconTint="@android:color/white" />
    

    Then add textappearance style in style.xml(For change textStyle)

    <style name="ChipTextApperance" parent="TextAppearance.MaterialComponents.Chip">
        <item name="android:textColor">@android:color/white</item>
    </style>
    

    Step 2

    Add your view here am using AppCompatEdittext

      <android.support.v7.widget.AppCompatEditText
        android:id="@+id/phone"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvt_Contact" />
    

    Step 3
    Add this code to your view to get the desired behaviour.

     private int SpannedLength = 0,chipLength = 4;
    
     AppCompatEditText Phone = findViewById(R.id.phone);
    
     Phone.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
            }
    
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (charSequence.length() == SpannedLength - chipLength)
                {
                    SpannedLength = charSequence.length();
                }
            }
    
            @Override
            public void afterTextChanged(Editable editable) {
    
                if(editable.length() - SpannedLength == chipLength) {
                    ChipDrawable chip = ChipDrawable.createFromResource(getContext(), R.xml.chip);
                    chip.setChipText(editable.subSequence(SpannedLength,editable.length()));
                    chip.setBounds(0, 0, chip.getIntrinsicWidth(), chip.getIntrinsicHeight());
                    ImageSpan span = new ImageSpan(chip);
                    editable.setSpan(span, SpannedLength, editable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                    SpannedLength = editable.length();
                }
    
            }
        });
    

    Change chipLength according to your need when new chip need to be added in edittext.

    OUTPUT

    EDITED

    You can find more about how to align center the text with span Here.

    Here i added some code from the solution will fix for you..

    public class VerticalImageSpan extends ImageSpan {
    
    public VerticalImageSpan(Drawable drawable) {
        super(drawable);
    }
    
    @Override
    public int getSize(@NonNull Paint paint, CharSequence text, int start, int end,
                       Paint.FontMetricsInt fontMetricsInt) {
        Drawable drawable = getDrawable();
        Rect rect = drawable.getBounds();
        if (fontMetricsInt != null) {
            Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
            int fontHeight = fmPaint.descent - fmPaint.ascent;
            int drHeight = rect.bottom - rect.top;
            int centerY = fmPaint.ascent + fontHeight / 2;
    
            fontMetricsInt.ascent = centerY - drHeight / 2;
            fontMetricsInt.top = fontMetricsInt.ascent;
            fontMetricsInt.bottom = centerY + drHeight / 2;
            fontMetricsInt.descent = fontMetricsInt.bottom;
        }
        return rect.right;
    }
    
    @Override
    public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end,
                     float x, int top, int y, int bottom, @NonNull Paint paint) {
    
        Drawable drawable = getDrawable();
        canvas.save();
        Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
        int fontHeight = fmPaint.descent - fmPaint.ascent;
        int centerY = y + fmPaint.descent - fontHeight / 2;
        int transY = centerY - (drawable.getBounds().bottom - drawable.getBounds().top) / 2;
        canvas.translate(x, transY);
        drawable.draw(canvas);
        canvas.restore();
    }
    
    }
    

    And change your imagespan class like below

    VerticalImageSpan span = new VerticalImageSpan(chip);
    
    0 讨论(0)
  • 2020-12-08 00:08

    You can use material chip "com.google.android.material.chip.Chip" and "implementation 'com.google.android.material:material:1.0.0' " add in build.gradle

    Filter style="@style/Widget.MaterialComponents.Chip.Filter"

    Choice Chips style="@style/Widget.MaterialComponents.Chip.Choice"

    Entry input: style="@style/Widget.MaterialComponents.Chip.Entry"

    0 讨论(0)
  • 2020-12-08 00:12

    All of the previous solutions didn't work for me if you want to achieve a gmail like behaviour with chips on multiple lines. In order to do that I had to avoid using the ChipGroup and instead using a FlexboxLayout.

    your_recipient_layout:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
    
        <TextView
            android:id="@+id/recipient_label_TV"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp"
            android:layout_gravity="center_vertical" />
    
        <com.google.android.flexbox.FlexboxLayout
            android:id="@+id/recipient_group_FL"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_gravity="center_vertical"
            app:flexWrap="wrap"
            app:alignItems="stretch"
            app:alignContent="space_around"
            app:showDivider="beginning|middle|end"
            app:dividerDrawable="@drawable/divider">
    
            <EditText
                android:id="@+id/recipient_input_ET"
                android:layout_width="wrap_content"
                android:layout_height="32dp"
                app:layout_flexGrow="1"
                android:background="@android:color/transparent"
                android:imeOptions="actionDone"
                android:inputType="text"/>
    
        </com.google.android.flexbox.FlexboxLayout>
    
    </LinearLayout>
    
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recipients_list_RV"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone" />
    

    The trick now is adding a new chip to the group but as second last position. Something like this:

    private fun addNewChip(person: String, chipGroup: FlexboxLayout) {
        val chip = Chip(context)
        chip.text = person
        chip.chipIcon = ContextCompat.getDrawable(requireContext(), R.mipmap.ic_launcher_round)
        chip.isCloseIconEnabled = true
        chip.isClickable = true
        chip.isCheckable = false
        chipGroup.addView(chip as View, chipGroup.childCount - 1)
        chip.setOnCloseIconClickListener { chipGroup.removeView(chip as View) }
    }
    
    0 讨论(0)
提交回复
热议问题