如何将 Material Components 库中的芯片添加到 android 中的输入字段?

新手上路,请多包涵

我已经看到在 android-P 谷歌中添加了包含材料芯片的新材料组件库:

安卓材料组件

Material.io芯片使用

GitHub 上的材料组件

所以我决定在我的项目中添加材质输入芯片,但遗憾的是没有找到任何制作教程。我想创建类似 Gmail 芯片的东西,但一开始没有图像。

因为我正在使用 appcompat 库,所以我尝试通过 android.support.design.chip.Chipandroid.support.design.chip.ChipGroup 使用材料芯片。但结果只是没有任何输入字段的芯片。我还尝试创建一个独立的 ChipDrawable,然后将其添加到 EditText 使用

Editable text = editText.getText();

text.setSpan(span, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

但是我得到了没有任何筹码的空 EditText。那么如何使用这个材料组件库创建像在 Gmail 中一样的筹码输入呢?也许有人有经验或知道我可以看到如何创建它的任何教程?

提前致谢!

原文由 IDmikael 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 262
2 个回答

回答

没有用于在 android 中添加筹码的默认输入字段。他们提到了输入芯片,但我没有找到输入芯片的任何布局或视图组。所以我用 Chipdrawable 方法在edittext中添加筹码。这里正在使用 AppCompatEdittext ,您可以更改为监听文本输入的任何视图。 参考

步骤1

添加芯片 xml 资源。 芯片.xml

res -> xml -> 芯片.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/ChipTextAppearance"
 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" />

然后在style.xml中添加textappearance样式(用于改变textStyle)

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

第2步

使用 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" />

步骤 3

将此代码添加到您的视图以获得所需的行为。

  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();
            }

        }
    });

当需要在 edittext 中添加新芯片时,根据需要更改 chipLength。

输出

在此处输入图像描述

已编辑

您可以 在此处 找到有关如何将文本与 span 居中对齐的更多信息。

在这里,我从解决方案中添加了一些代码将为您修复..

 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();
}

}

并像下面这样更改您的 imagespan 类

VerticalImageSpan span = new VerticalImageSpan(chip);

原文由 Mohamed Mohaideen AH 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果您想在多行上使用芯片实现类似于 gmail 的行为,那么所有以前的解决方案都不适合我。为了做到这一点,我不得不避免使用 ChipGroup 而是使用 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" />

现在的诀窍是向组中添加一个新筹码,但作为倒数第二个位置。是这样的:

 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) }
}

原文由 br00 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题