jjzjj

android - 如何将文本添加到 float 操作按钮?

coder 2023-12-20 原文

我想在 float 操作按钮上显示文本而不是图像。我尝试使用 android:contentDescription="string"但操作按钮似乎是空的,我需要设置一些颜色或做任何其他事情吗?请让我知道。

最佳答案

在我们的项目中,我们使用了一个名为 TextDrawable 的自定义类。此类扩展了 Drawable 并在其方法 draw(Canvas) 中简单地在 Canvas 上绘制文本。该类适合我们的特定需求,但我认为,想法(主要在 draw() 方法中)将帮助您:

public class TextDrawable extends Drawable {

protected final Paint textPaint;
protected ColorStateList color;
protected String text;
protected int iHeight;
protected int iWidth;
protected int measuredWidth, measuredHeight;
private float ascent;
/**
 * A flag whether the drawable is stateful - whether to redraw if the state of view has changed
 */
protected boolean stateful;
/**
 * Vertical alignment of text
 */
private VerticalAlignment verticalAlignment;

.... some constructors...
public TextDrawable(Context ctx, String text, ColorStateList color, float textSize, VerticalAlignment verticalAlignment) {
    textPaint = new Paint();
    this.text = text;
    initPaint();
    this.textPaint.setTextSize(textSize);
    measureSize();
    setBounds(0, 0, iWidth, iHeight);
    this.color = color;
    textPaint.setColor(color.getDefaultColor());
    this.verticalAlignment = verticalAlignment;
}

/**
 * Set bounds of drawable to start on coordinate [0,0] and end on coordinate[measuredWidth,
 * measuredHeight]
 */
public final void setBoundsByMeasuredSize() {
    setBounds(0, 0, measuredWidth, measuredHeight);
    invalidateSelf();
}

@Override
public boolean isStateful() {
    return stateful;
}

public void setStateful(boolean stateful) {
    this.stateful = stateful;
}

private void initPaint() {
    textPaint.setAntiAlias(true);
    textPaint.setTextAlign(Paint.Align.CENTER);
}

/**
 * Vertical alignment of text within the drawable (Horizontally it is always aligned to center
 */
public VerticalAlignment getVerticalAlignment() {
    return verticalAlignment;
}

/**
 * Vertical alignment of text within the drawable (Horizontally it is always aligned to center
 */
public void setVerticalAlignment(VerticalAlignment verticalAlignment) {
    if (this.verticalAlignment != verticalAlignment) {
        this.verticalAlignment = verticalAlignment;
        invalidateSelf();
    }
}

/**
 * Displayed text
 */
public String getText() {
    return text;
}

/**
 * Displayed text
 */

public void setText(String text) {
    if (this.text == null || !this.text.equals(text)) {
        this.text = text;
        invalidateSelf();
    }
}

/**
 * The color of text
 */
public ColorStateList getColor() {
    return color;
}

/**
 * The color of text
 */
public void setColor(ColorStateList colorStateList) {
    if (this.color == null || !this.color.equals(colorStateList)) {
        this.color = colorStateList;
        invalidateSelf();
    }
}

/**
 * The color of text
 */
public void setColor(int color) {
    setColor(ColorStateList.valueOf(color));
}

/**
 * Text size
 */
public void setTextSize(float size) {
    if (this.textPaint.getTextSize() != size) {
        this.textPaint.setTextSize(size);
        measureSize();
        invalidateSelf();
    }
}

/**
 * Text size
 */
public void setTextSize(int unit, float size, Context context) {
    setTextSize(TypedValue.applyDimension(unit, size, context.getResources().getDisplayMetrics()));
}

/**
 * This method is called by default when any property that may have some influence on the size
 * of drawable This method should use measuredWidth and measuredHeight properties to store the
 * measured walues By default the measuredWIdth and measuredHeight are set to iWidth and iHeight
 * (size of text) by this method.
 */
protected void measureSize() {
    ascent = -textPaint.ascent();
    iWidth = (int) (0.5f + textPaint.measureText(text));
    iHeight = (int) (0.5f + textPaint.descent() + ascent);
    measuredWidth = iWidth;
    measuredHeight = iHeight;
}

public float getTextSize() {
    return textPaint.getTextSize();
}

@Override
protected boolean onStateChange(int[] state) {
    int clr = color != null ? color.getColorForState(state, 0) : 0;
    if (textPaint.getColor() != clr) {
        textPaint.setColor(clr);
        return true;
    } else {
        return false;
    }
}

public Typeface getTypeface() {
    return textPaint.getTypeface();
}

public void setTypeface(Typeface typeface) {
    if (!textPaint.getTypeface().equals(typeface)) {
        textPaint.setTypeface(typeface);
        invalidateSelf();
    }
}

/**
 * The method is called before the text is drawn. This method can be overridden to draw some background (by default this method does nothing).
 * @param canvas The canvas where to draw.
 * @param bounds The bounds of the drawable.
 */
protected void drawBefore(Canvas canvas, Rect bounds) {

}

/**
 * The method is called after the text is drawn. This method can be overriden to draw some more graphics over the text (by default this method does nothing).
 * @param canvas The canvas where to draw.
 * @param bounds The bound of the drawable.
 */
protected void drawAfter(Canvas canvas, Rect bounds) {

}

@Override
public void draw(Canvas canvas) {
    if (text == null || text.isEmpty()) {
        return;
    }
    final Rect bounds = getBounds();
    int stack = canvas.save();
    canvas.translate(bounds.left, bounds.top);
    drawBefore(canvas, bounds);
    if (text != null && !text.isEmpty()) {
        final float x = bounds.width() >= iWidth ? bounds.centerX() : iWidth * 0.5f;
        float y = 0;
        switch (verticalAlignment) {
            case BASELINE:
                y = (bounds.height() - iHeight) * 0.5f + ascent;
                break;
            case TOP:
                y = bounds.height();
                break;
            case BOTTOM:
                y = bounds.height();
                break;
        }
        canvas.drawText(text, x, y, textPaint);
    }
    drawAfter(canvas, bounds);
    canvas.restoreToCount(stack);

}

@Override
public void setAlpha(int alpha) {
    if (textPaint.getAlpha() != alpha) {
        textPaint.setAlpha(alpha);
        invalidateSelf();
    }
}

@Override
public void setColorFilter(ColorFilter cf) {
    if (textPaint.getColorFilter() == null || !textPaint.getColorFilter().equals(cf)) {
        textPaint.setColorFilter(cf);
        invalidateSelf();
    }
}

@Override
public int getOpacity() {
    return PixelFormat.TRANSLUCENT;
}

public enum VerticalAlignment {
    TOP, BOTTOM, BASELINE
}

以及如何使用它:

fab.setImageDrawable(new TextDrawable(fab.getContext(), "FAB", ColorStateList.valueOf(Color.BLACK), 32.f, VerticalAlignment.BASELINE));

(fab 是 Fl​​oatingActionButton)

关于android - 如何将文本添加到 float 操作按钮?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33878629/

有关android - 如何将文本添加到 float 操作按钮?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  7. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  8. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  9. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

随机推荐