以编程方式绘制气泡

2024-03-28

I would like to have a bubble with a precentage value in my app, I can't use 9 patches as i want it to be customizable and its background color should be changeble. It should look something like this enter image description here

我该怎么做?这个气泡内部的视图会膨胀,比如这个百分比或一些更大的布局。 另外,根据布局(手机或平板电脑),它的一侧可能比另一侧大(箭头不在中心),所以这是我更喜欢以编程方式执行此操作的另一个原因


创建一个自定义 Drawable 并将其用作您要放入文本或其他视图的任何容器的背景。
您将需要修改背景的填充以考虑气泡的指针。
下面的代码允许您将指针的对齐方式设置为左对齐、居中对齐或右对齐。
这只是一个基本版本,仅供您参考。您可以轻松地添加气泡颜色的设置器,或者向“mPaint”添加描边属性以获得额外的灵活性。

public class BubbleDrawable extends Drawable {

    // Public Class Constants
    ////////////////////////////////////////////////////////////

    public static final int LEFT = 0;
    public static final int CENTER = 1;
    public static final int RIGHT = 2;

    // Private Instance Variables
    ////////////////////////////////////////////////////////////

    private Paint mPaint;
    private int mColor;

    private RectF mBoxRect;
    private int mBoxWidth;
    private int mBoxHeight;
    private float mCornerRad;
    private Rect mBoxPadding = new Rect();

    private Path mPointer;
    private int mPointerWidth;
    private int mPointerHeight;
    private int mPointerAlignment;

    // Constructors
    ////////////////////////////////////////////////////////////

    public BubbleDrawable(int pointerAlignment) {
        setPointerAlignment(pointerAlignment);
        initBubble();
    }

    // Setters
    ////////////////////////////////////////////////////////////

    public void setPadding(int left, int top, int right, int bottom) {
        mBoxPadding.left = left;
        mBoxPadding.top = top;
        mBoxPadding.right = right;
        mBoxPadding.bottom = bottom;
    }

    public void setCornerRadius(float cornerRad) {
        mCornerRad = cornerRad;
    }

    public void setPointerAlignment(int pointerAlignment) {
        if (pointerAlignment < 0 || pointerAlignment > 3) {
            Log.e("BubbleDrawable", "Invalid pointerAlignment argument");
        } else {
            mPointerAlignment = pointerAlignment;
        }
    }

    public void setPointerWidth(int pointerWidth) {
        mPointerWidth = pointerWidth;
    }

    public void setPointerHeight(int pointerHeight) {
        mPointerHeight = pointerHeight;
    }

    // Private Methods
    ////////////////////////////////////////////////////////////

    private void initBubble() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mColor = Color.RED;
        mPaint.setColor(mColor);
        mCornerRad = 0;
        setPointerWidth(40);
        setPointerHeight(40);
    }

    private void updatePointerPath() {
        mPointer = new Path();
        mPointer.setFillType(Path.FillType.EVEN_ODD);

        // Set the starting point
        mPointer.moveTo(pointerHorizontalStart(), mBoxHeight);

        // Define the lines
        mPointer.rLineTo(mPointerWidth, 0);
        mPointer.rLineTo(-(mPointerWidth / 2), mPointerHeight);
        mPointer.rLineTo(-(mPointerWidth / 2), -mPointerHeight);
        mPointer.close();
    }

    private float pointerHorizontalStart() {
        float x = 0;
        switch (mPointerAlignment) {
        case LEFT:
            x = mCornerRad;
            break;
        case CENTER:
            x = (mBoxWidth / 2) - (mPointerWidth / 2);
            break;
        case RIGHT:
            x = mBoxWidth - mCornerRad - mPointerWidth;
        }
        return x;
    }

    // Superclass Override Methods
    ////////////////////////////////////////////////////////////

    @Override
    public void draw(Canvas canvas) {
        mBoxRect = new RectF(0.0f, 0.0f, mBoxWidth, mBoxHeight);
        canvas.drawRoundRect(mBoxRect, mCornerRad, mCornerRad, mPaint);
        updatePointerPath();
        canvas.drawPath(mPointer, mPaint);
    }

    @Override
    public int getOpacity() {
        return 255;
    }

    @Override
    public void setAlpha(int alpha) {
        // TODO Auto-generated method stub

    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean getPadding(Rect padding) {
        padding.set(mBoxPadding);

        // Adjust the padding to include the height of the pointer
        padding.bottom += mPointerHeight;
        return true;
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        mBoxWidth = bounds.width();
        mBoxHeight = getBounds().height() - mPointerHeight;
        super.onBoundsChange(bounds);
    }
}

Usage
下面的示例展示了如何使用 BubbleDrawable。

MainActivity.java

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LinearLayout linearLayout = (LinearLayout)findViewById(R.id.myLayout);
        BubbleDrawable myBubble = new BubbleDrawable(BubbleDrawable.CENTER);
        myBubble.setCornerRadius(20);
        myBubble.setPointerAlignment(BubbleDrawable.RIGHT);
        myBubble.setPadding(25, 25, 25, 25);
        linearLayout.setBackgroundDrawable(myBubble);
    }
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/myLayout"
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Some Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Some Other Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />
        </LinearLayout>

</RelativeLayout>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

以编程方式绘制气泡 的相关文章

  • 从状态栏中删除通知图标

    我在状态栏中显示一个图标 现在我想在打开该内容时立即删除该图标 一段时间后如果我们收到任何警报 该图标将再次显示 我怎样才能做到这一点 使用NotificationManager取消您的通知 您只需提供您的通知 ID https devel
  • android.view.InflateException:二进制 XML 文件第 6 行:膨胀类片段时出错

    应用程序启动时出现此错误 我收到主题中显示的许多此类错误 这些错误似乎是偶然的 我无法重现它们 从堆栈中我可以了解到 我的不同布局资源可能会发生此类错误 XML 的行也各不相同 谁能解释为什么会出现这个错误 我能做些什么来解决这个问题 09
  • 如何 adb 提取 SD 卡中文件夹中的所有文件

    我的 SD 卡中有一个文件夹 mnt sdcard Folder1 Folder2 Folder3 jpg 文件夹 1 和文件夹 2 的名称保持不变 文件夹 2 内有文件夹 3 4 5 等 我想使用 adb 将所有 jpeg 文件而不是所有
  • 小部件预览图像

    My app preview image looks like this 我怎样才能让它看起来像 WhatsApp 聊天预览 小有阴影 我手机中的其他应用程序也使用相同类型的预览 我的小部件 xml
  • 减少 OpenGL ES 1.1 中纹理的内存使用

    我在 OpenGL ES 中的场景需要几个大分辨率纹理 但它们是灰度的 因为我仅将它们用于蒙版 我需要减少内存使用 我尝试使用 Bitmap Config ALPHA 8 和 RGB 565 加载这些纹理 ALPHA 8 似乎实际上增加了内
  • 如何更改 Android 设备上的 MAC 地址? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 有没有一种简单的方法可以手动更改 A
  • NullPointerException 自定义列表视图适配器

    你好 stackoverflow 社区 我在扩展 BaseAdapter 的自定义适配器类的 getView 方法中得到了一个 NPE 我希望你可以帮助我 这是我的 getView 方法 Override public View getVi
  • AppBarLayout 滚动时 RecyclerView fling 导致延迟

    我的布局如下
  • 有人可以解释一下 arcTo 的最后两个参数吗?

    我正在尝试绘制一个带圆角的矩形 我有一个 javascript 路径可以执行此操作 但 javascript arcTo 方法采用一个矩形 定义其椭圆形 然后采用一个参数来设置扫描 然而 在Android版本中有三个参数 矩形椭圆形 我认为
  • ActionBar 上的自定义主页按钮

    我正在使用 ActionBar Sherlock 库 所以 要更改默认的主页按钮 我这样做了 这不起作用 所以 我也添加了这个
  • 在 Jenkins 上编译 Android 项目时如何修复此 ZipException?

    我最近将 Jenkins 机器上的 Android SDK 从 rev13 更新到 rev15 并且必须重做一些自定义构建内容build xml以适应 rev14 中所做的更改 我在我的工作站上解决了这个问题 并检查了它 期望一切顺利 相反
  • Android 模拟器出现错误:冷启动:快照不存在

    我在使用 Android 模拟器 7 8 天后就遇到了问题 起初它根本没有运行 现在重新安装模拟器解决了这个问题 但又产生了新的问题 每当我运行模拟器时 都会花费很长时间 大约 5 6 分钟 然后显示错误 Cold Boot Snapsho
  • Android:实时图像处理

    我有一个应用程序 它进行相机预览 对每一帧执行一些基本的图像处理功能 例如边缘检测 颜色变化 图像扭曲等 并 实时 将修改后的帧显示到屏幕上 类似于Android Market中的 Paper Camera 应用程序 我的方法总结 我也做过
  • 如何在ubuntu服务器上安装android SDK

    我在 ubuntu 服务器中有一个 React Native 项目 我想构建一个用于生产的 Android 应用程序 为此 我首先必须生成 Gradle Wrapper 文件 因此我在中运行此命令android目录 gradle wrapp
  • 对齐顶部两个具有不同字体大小的文本视图

    我使用约束布局 我想实现以下目标 app layout constraintBaseline toBaselineOf 属性底部对齐两个文本视图 有什么方法可以使两个顶部对齐吗 由于大小差异 常规的 app layout constrain
  • 在 Google Play 中更新 APK 而不更改扩展文件

    我的 Google Play 控制台中有一个 草稿 APK 它已连接到 APK 扩展文件 版本号为9 扩展文件为 main 9 com something something obb 现在 我正在尝试在发布之前更新 APK 我增加了版本代码
  • 在自定义 BaseAdapter 子类中使用 Butter Knife 会导致“无法注入视图”错误

    我正在尝试使用 Butter Knife 来简化自定义 BaseAdapter 类的创建 我正在遵循这里的示例 http jakewharton github io butterknife http jakewharton github i
  • 如何在android中实现表面视图的双击

    请告诉我如何实现双击SurfaceView在 Android 中使用手势检测器 有人可以提供代码示例吗 你可以尝试以下 实际上我测试了这个并且效果很好 1 Extend GestureDetector SimpleOnGestureList
  • Android 每个 Activity 中的通用进度条

    我已经修改了解决方案 我可以获得进度条 但进度条永远不会隐藏 这是创建具有相对布局的进度条的类 public class ProgressBarHandler private ProgressBar mProgressBar private
  • 监控当前运行的应用程序

    我遇到了一个暂时无法解决的问题 该代码的目的是监视当前正在运行哪些应用程序 我使用了以下代码并记录了生成的包名称 它起作用了 ActivityManager am ActivityManager context getSystemServi

随机推荐

  • Mysqli 查询返回空结果

    我试图使用以下代码从我的数据库获取一些数据
  • Jetpack 撰写预览因 hiltViewModel<>() 崩溃

    我使用 compose 版本 1 1 0 beta03 和 hilt navigation compose 1 0 0 beta01 这是我的可组合代码 fun EngagementBotChart modifier Modifier Mo
  • 两条线相交的算法?

    我有2行 两条线都包含 X 和 Y 两个点 这意味着它们都有长度 我看到两个公式 一个使用行列式 一个使用普通代数 哪个计算效率最高 公式是什么样的 我很难在代码中使用矩阵 这就是我目前所拥有的 它可以更有效吗 public static
  • spring-cloud-starter-config POST /env 不起作用

    我有一个小的 Spring Boot Web 应用程序 可执行 jar 它在 application properties 文件中有一些自定义属性 我的目标是能够在运行时动态更改这些属性 而无需运行构建 部署或重新启动 java 进程 sp
  • 从 kdb 中的字符串中提取数字

    我对 kdb q 很陌生 我遇到过从字符串中提取数字的问题 有什么建议么 Example AZXER 1234 MARKET should output 1234 Assume that there is only one number i
  • JOIN 语法中缺少关键字

    在提出问题之前我已经搜索过该网站 但没有遇到相关的内容 我确信这是一个荒谬的基本错误 我只从 0 计算机背景学习 Oracle SQL 大约 4 个月 我计划在本月底学习 1z0 051 所以复习一下所有章节 在这个子句中 我试图获取工资高
  • 要嵌入 .NET 应用程序的 XPS 或 XAML 查看器?

    是否有查看器对象或 ActiveX 控件可用于在我的 NET 应用程序中嵌入 XPS 文档或 XAML GUI 您可以使用元素主机控制 http msdn microsoft com en us library system windows
  • 使用express模块​​时找不到模块“cookie”

    我需要你的帮助来使用express构建rest API 我已经尝试了很多版本的express 也有 CookieParser 中间件 但我刚刚收到上述错误 Error Cannot find module cookie at Functio
  • 无法在本地或远程找到“开发”或“主”分支。 - 语义gitversion

    我在 azure 中有一个存储库 它有默认分支 main 另外 我在 yml 文件中有一项用于语义版本控制的任务 task gittools gitversion gitversion task GitVersion 5 displayNa
  • TypeError:注册不是在React中使用React Hook Form的函数

    The Error Message If i dont use the Inputs inside div then it works perfectly but when i use Input inside div it shows m
  • Spring SseEmitter 导致响应提交后无法转发异常

    给定一个简单的控制器 其方法如下 RequestMapping method RequestMethod GET value id update public ResponseEntity
  • 如何使用 karma 在测试文件之间共享模拟?

    我正在一个有角度的应用程序中工作 其中许多测试文件共享相同的模拟 我想知道如何提取这些模拟并将它们放入单独的文件中 我尝试创建一个对象并在测试中重用它 但出现异常 ReferenceError 找不到变量 需要 业力文件 module ex
  • 使用 jQuery 检查 div 是否隐藏

    这是我的div div style display none div 然后我有一个显示按钮 当您单击时将显示 div show click function car2 show 所以现在我想检查 div 是否 car2在表单提交之前仍然隐藏
  • 如何使用键盘快捷键转到 VS Code 中的下一个错误(不是下一个问题)?

    In VS Code the F8 keyboard shortcut takes you to the next problem Problems can be errors warnings or info I want to cycl
  • 每组平均值以及组中变量的数量[重复]

    这个问题在这里已经有答案了 我想生成一个表 其中包含每个范围的组 每个组中变量的平均值和计数 我有一个如下所示的 data frame Variable Shap 1 0 10 6 0 50 7 0 30 5 0 40 9 0 10 9 0
  • 在后台停止音频

    有一个名为 IHeartRadio 的应用程序 可让您设置睡眠计时器 该计时器将在指定的时间间隔后关闭音频 您首先选择要收听的电台 然后选择睡眠时间 之后广播电台将停止播放 应用程序不需要位于前台即可发生这种情况 应用程序如何在后台停止音频
  • 在 Gatsby 上运行 SASS 不起作用

    昨天 我能够设置 gatsby 的入门包实例并部署到 github 页面 从那时起 我在本地更新了我的react js 文件 这似乎在本地运行良好 现在我想编译我的 sass 我找不到有效的解决方案 这是我尝试安装的 sass 编译器 sa
  • Python 定时脚本

    如何让 python 脚本每天在设定的时间运行 确切地说是下午 2 00每天 有没有办法让它每天运行两次 不太确定从哪里开始 谢谢您的帮助 不要重新发明和使用任何系统上已有数十年的功能 cron 除此之外 PyPI 列出了一堆与 cron
  • 如何使用 imaplib 创建电子邮件并将其发送到特定邮箱

    我正在尝试使用 python 的 imaplib 创建一封电子邮件并将其发送到具有特定名称的邮箱 例如收件箱 任何人都有一些很好的建议 IMAP 协议不是为发送电子邮件而设计的 它旨在操纵邮箱 要创建电子邮件并发送它 您可以使用 SMTP
  • 以编程方式绘制气泡

    I would like to have a bubble with a precentage value in my app I can t use 9 patches as i want it to be customizable an