jjzjj

android - 如何为 ImageView 赋予六边形形状

coder 2023-06-06 原文

如何为 ImageView 赋予六边形形状。有可能以同样的方式做吗?如果是这样,那么如何。如果这是不可能的,那么如何实现呢?

<shape xmlns:android="http//schemas.android.com/apk/res/android"
       android:shape="hexagon">
  <solid android:color="#ffffffff" />
  <size android:width="60dp"
        android:height="40dp" />
</shape>

截图

这里我不能做 mask 图像,因为我无法检测到我应该裁剪位图的哪个部分以获得六边形位图。所以我正在寻找将六边形形状赋予 ImageView

的答案

最佳答案

试试这个 View 。您可能希望根据您的特定需求对其进行调整,但它会在 View 顶部绘制一个带有边框的六边形蒙版。背景资源位于掩码下方。

结果:

代码:

HexagonMaskView.java

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Path;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.View;

public class HexagonMaskView extends View {
    private Path hexagonPath;
    private Path hexagonBorderPath;
    private float radius;
    private float width, height;
    private int maskColor;

public HexagonMaskView(Context context) {
    super(context);
    init();
}

public HexagonMaskView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public HexagonMaskView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

private void init() {
    hexagonPath = new Path();
    hexagonBorderPath = new Path();
    maskColor = 0xFF01FF77;
}

public void setRadius(float r) {
    this.radius = r;
    calculatePath();
}

public void setMaskColor(int color) {
    this.maskColor = color;
    invalidate();
}

private void calculatePath() {
    float triangleHeight = (float) (Math.sqrt(3) * radius / 2);
    float centerX = width/2;
    float centerY = height/2;
    hexagonPath.moveTo(centerX, centerY + radius);
    hexagonPath.lineTo(centerX - triangleHeight, centerY + radius/2);
    hexagonPath.lineTo(centerX - triangleHeight, centerY - radius/2);
    hexagonPath.lineTo(centerX, centerY - radius);
    hexagonPath.lineTo(centerX + triangleHeight, centerY - radius/2);
    hexagonPath.lineTo(centerX + triangleHeight, centerY + radius/2);
    hexagonPath.moveTo(centerX, centerY + radius);

    float radiusBorder = radius - 5;    
    float triangleBorderHeight = (float) (Math.sqrt(3) * radiusBorder / 2);
    hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
    hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY + radiusBorder/2);
    hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY - radiusBorder/2);
    hexagonBorderPath.lineTo(centerX, centerY - radiusBorder);
    hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY - radiusBorder/2);
    hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY + radiusBorder/2);
    hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
    invalidate();
}

@Override
public void onDraw(Canvas c){
    super.onDraw(c);
    c.clipPath(hexagonBorderPath, Region.Op.DIFFERENCE);
    c.drawColor(Color.WHITE);
    c.save();
    c.clipPath(hexagonPath, Region.Op.DIFFERENCE);
    c.drawColor(maskColor);
    c.save();
}

// getting the view size and default radius
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    width = MeasureSpec.getSize(widthMeasureSpec);
    height =  MeasureSpec.getSize(heightMeasureSpec);
    radius = height / 2 - 10;
    calculatePath();
}
}

29.07.2016 更新

一种更好的方法,只剪辑源图像而不绘制整个 View 的背景。切换到 ImageView 作为基类以受益于 scaleType。我还做了一些代码重构。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Region;
import android.util.AttributeSet;
import android.widget.ImageView;

public class HexagonMaskView extends ImageView {
    private Path hexagonPath;
    private Path hexagonBorderPath;
    private Paint mBorderPaint;

    public HexagonMaskView(Context context) {
        super(context);
        init();
    }

    public HexagonMaskView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public HexagonMaskView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        this.hexagonPath = new Path();
        this.hexagonBorderPath = new Path();

        this.mBorderPaint = new Paint();
        this.mBorderPaint.setColor(Color.WHITE);
        this.mBorderPaint.setStrokeCap(Paint.Cap.ROUND);
        this.mBorderPaint.setStrokeWidth(50f);
        this.mBorderPaint.setStyle(Paint.Style.STROKE);
    }

    public void setRadius(float radius) {
        calculatePath(radius);
    }

    public void setBorderColor(int color) {
        this.mBorderPaint.setColor(color);
        invalidate();
    }

    private void calculatePath(float radius) {
        float halfRadius = radius / 2f;
        float triangleHeight = (float) (Math.sqrt(3.0) * halfRadius);
        float centerX = getMeasuredWidth() / 2f;
        float centerY = getMeasuredHeight() / 2f;

        this.hexagonPath.reset();
        this.hexagonPath.moveTo(centerX, centerY + radius);
        this.hexagonPath.lineTo(centerX - triangleHeight, centerY + halfRadius);
        this.hexagonPath.lineTo(centerX - triangleHeight, centerY - halfRadius);
        this.hexagonPath.lineTo(centerX, centerY - radius);
        this.hexagonPath.lineTo(centerX + triangleHeight, centerY - halfRadius);
        this.hexagonPath.lineTo(centerX + triangleHeight, centerY + halfRadius);
        this.hexagonPath.close();

        float radiusBorder = radius - 5f;
        float halfRadiusBorder = radiusBorder / 2f;
        float triangleBorderHeight = (float) (Math.sqrt(3.0) * halfRadiusBorder);

        this.hexagonBorderPath.reset();
        this.hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
        this.hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY + halfRadiusBorder);
        this.hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY - halfRadiusBorder);
        this.hexagonBorderPath.lineTo(centerX, centerY - radiusBorder);
        this.hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY - halfRadiusBorder);
        this.hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY + halfRadiusBorder);
        this.hexagonBorderPath.close();
        invalidate();
    }

    @Override
    public void onDraw(Canvas c) {
        c.drawPath(hexagonBorderPath, mBorderPaint);
        c.clipPath(hexagonPath, Region.Op.INTERSECT);
        c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        super.onDraw(c);
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width, height);
        calculatePath(Math.min(width / 2f, height / 2f) - 10f);
    }
}

示例布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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"
    android:background="@android:color/holo_green_dark">

    <com.scelus.hexagonmaskimproved.HexagonMaskView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/bear"
        android:background="@android:color/holo_green_light"/>

</RelativeLayout>

关于android - 如何为 ImageView 赋予六边形形状,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22601400/

有关android - 如何为 ImageView 赋予六边形形状的更多相关文章

  1. ruby - 如何为 emacs 安装 ruby​​-mode - 2

    我刚刚为fedora安装了emacs。我想用emacs编写ruby。为ruby​​提供代码提示、代码完成类型功能所需的工具、扩展是什么? 最佳答案 ruby-mode已经包含在Emacs23之后的版本中。不过,它也可以通过ELPA获得。您可能感兴趣的其他一些事情是集成RVM、feature-mode(Cucumber)、rspec-mode、ruby-electric、inf-ruby、rinari(用于Rails)等。这是我当前用于Ruby开发的Emacs配置:https://github.com/citizen428/emacs

  2. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  3. ruby-on-rails - 如何为空白字段编写 rspec? [Rails3.1] - 2

    我使用rails3.1+rspec和factorygirl。我对必填字段(validates_presence_of)的验证工作正常。我如何让测试将该事实用作“成功”而不是“失败”规范是:describe"Addanindustrywithnoname"docontext"Unabletocreatearecordwhenthenameisblank"dosubjectdoind=Factory.create(:industry_name_blank)endit{shouldbe_invalid}endend但是我失败了:Failures:1)Addanindustrywithnona

  4. ruby - 如何为 pbcopy 生成富文本链接 - 2

    我一直在玩一个脚本,它在Chrome中获取选定的文本并在Google中查找它,提供四个最佳选择,然后粘贴相关链接。它以不同的格式粘贴,具体取决于当前在Chrome中打开的页面-DokuWiki打开的DokuWiki格式,普通网站的HTML,我想要我的WordPress所见即所得编辑器的富文本。我尝试使用pbpaste-Preferrtf来查看没有其他样式的富文本链接在粘贴板上的样子,但它仍然输出纯文本。在文本编辑中保存文件并进行试验后,我想出了以下内容text=%q|{\rtf1{\field{\*\fldinst{HYPERLINK"URL"}}{\fldrsltTEXT}}}|te

  5. ruby - 如何为字母、元音和辅音等德语字符类编写正则表达式? - 2

    例如,我设置了这些:L=/[a-z,A-Z,ßäüöÄÖÜ]/V=/[äöüÄÖÜaeiouAEIOU]/K=/[ßb-zBZ&&[^#{V}]]/因此/(#{K}#{V}{2})/匹配"azAZßäÜ"中的"ßäÜ"。有没有更好的方法来处理它们?我能否将这些常量放在我的Ruby安装文件夹中某个文件中的模块中,这样我就可以在我在计算机上编写的任何新脚本中包含/要求它们?(我是新手,我知道我混淆了这个术语;请纠正我。)此外,我能否只获取元字符\L、\V和\K(或任何尚未在Ruby中设置)以在正则表达式中代表它们,所以我不必一直做字符串插值? 最佳答案

  6. ruby-on-rails - Ruby on Rails PostGIS - 将多边形记录插入数据库 - 2

    我将RoR与PostGIS结合使用来存储位置数据。我正在尝试使用圆(例如,带半径的中心点)来存储估计位置。我试过类似的东西,但它不起作用:@location=Location.new(:place_id=>place.id,:circle=>%{ST_Buffer(ST_MakePoint(#{latitude},#{longitude})::geography,#{accuracy})})我也尝试过使用RGeo,它是出厂设置,但不确定如何准确使用它。任何帮助将不胜感激。谢谢。编辑1:我取得了一些进步。factory=RGeo::Cartesian.factorycenter_poin

  7. ruby-on-rails - 具有六边形架构和 DCI 模式的框架和数据库适配器 - 2

    我尝试用Ruby设计一个基于Web的应用程序。我开发了一个简单的核心应用程序,在没有框架和数据库的情况下在六边形架构中实现DCI范例。核心六边形中有小六边形和网络,数据库,日志等适配器。每个六边形都在没有数据库和框架的情况下自行运行。在这种方法中,我如何提供与数据库模型和实体类的关系作为独立于数据库的关系。我想在将来将框架从Rails更改为Sinatra或数据库。事实上,我如何在这个核心Hexagon中实现完全隔离的rails和mongodb的数据库适配器或框架适配器。有什么想法吗? 最佳答案 ROM呢?(Ruby对象映射器)。还有

  8. ruby-on-rails - Rails 如何为 Google Charts 构建数据结构 - 2

    我想使用googlecharts创建一个如下所示的图表:GoogleChart.pie_400x200('TacoBell'=>0,'Mediterranean'=>2,'Shivas'=>5)给定一个对象Results(name,count)。如何为GoogleCharts的结构创建一个对象,如上所示?谢谢 最佳答案 从您在评论中列为@results的结果对象开始,以下应该有效:GoogleChart.pie_400x200(@results.map{|r|{r[:title]=>r[:percentage]}})

  9. ruby - 如何为类方法动态定义别名方法? - 2

    我有一个名为“计算器”的模块,我想将其包含在“产品”类中。Calculator将扩展“Product”,它将类方法复制到Product上。这些类方法之一是“memoize”。我的想法是我可以做这样的事情:moduleCalculatordefself.extended(base)base.memoize:foo_barendend以内存方法(特别是类方法)为目的:foo_bar。在memoize内部,我调用方法“alias_method”,它试图将类方法别名为不同的名称(此处为:foo_bar)。这失败了。Memoize看起来像这样:moduleCalculator(theextend

  10. ruby - 如何为命名空间类定义 Fabricator - 2

    我想为类定义Fabricator,其命名空间类似于“Foo::Bar”。告诉我它的工作方式。这是我的代码。模型/foo.rbclassFooincludeMongoid::Documentembedded_in:foo_container,polymorphic:truefield:xxx....end模型/foo/bar.rbclassFoo::Bar数据/制造商/foo_bar_fabricator.rbFabricator(:foo_bar,class_name:'Foo::Bar')doyyy'MyString'zzz'MyString'end当我尝试在parino控制台上创建

随机推荐