使用xml定义制作三角形形状?


133

有没有一种方法可以在xml文件中指定三角形形状?

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="triangle">
  <stroke android:width="1dip" android:color="#FFF" />
  <solid android:color="#FFF" />
</shape>

我们可以用路径形状或其他方式做到这一点吗?我只需要一个等边三角形。

谢谢


您找到解决方案了吗?我有同样的问题。
Mike Bevz 2011年

这似乎对编写指南的人(和一些评论者)
有用

Answers:


166

这篇文章中,我描述了如何做到这一点。这是XML定义的三角形:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <rotate
            android:fromDegrees="45"
            android:toDegrees="45"
            android:pivotX="-40%"
            android:pivotY="87%" >
            <shape
                android:shape="rectangle" >
                <stroke android:color="@color/transparent" android:width="10dp"/>
                <solid
                    android:color="@color/your_color_here" />
            </shape>
        </rotate>
    </item>
</layer-list>

如果有不清楚的地方,请参考我的文章,或者您需要解释它的构建方式。它旋转了一个切口矩形:)这是一个非常聪明且效果很好的解决方案。

编辑:创建一个箭头指向->使用:

...
android:fromDegrees="45"
android:toDegrees="45"
android:pivotX="13%"
android:pivotY="-40%" >
...

并创建一个类似<-的箭头,请使用:

android:fromDegrees="45"
android:toDegrees="45"
android:pivotX="87%"
android:pivotY="140%" >

3
对不起..但是等边三角形永远不能是直角三角形。
lilbyrdie 2013年

3
@JacekMilewski-非常感谢!想要分享您的向下箭头所用的ivotX / pivotY参数吗?剩下?对?
JohnnyLambada 2014年

2
要旋转它,我更改布局xml文件中的旋转,而不更改三角形定义本身中的旋转。
Jacek Milewski 2014年

1
-1。不好 视图的实际尺寸大于屏幕上显示的尺寸。它应该已经包裹了界限。
Javanator

1
您能否分享您如何从fromDegrees,toDegrees,pivotX和pivotY导出值?我有一个用例,其中无法更改布局文件中的旋转。
帕特里克·布伦南

82
<TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="▼"/>

您可以在此处获得更多选择。


3
您如何将该值放入xml?
user531069 2015年

2
复制此TextView并将其粘贴到您的xml
Elhanan Mishraky 2015年

6
@ user531069:将其放在您的strings.xml中:<string name="bottom_arrow">&#9660;</string>

1
我想要链接中的箭头不同,我复制并粘贴&#129032; 作为文本,它显示一些未知字符。?
M. Usman Khan

2
此解决方案产生了一个新的问题,即在“文本视图”中处理字体填充。
Salman Khakwani

59

你可以vector用来做这样的三角形

ic_triangle_right.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:pathData="M0,12l0,12 11.5,-5.7c6.3,-3.2 11.5,-6 11.5,-6.3 0,-0.3 -5.2,-3.1 -11.5,-6.3l-11.5,-5.7 0,12z"
        android:strokeColor="#00000000"
        android:fillColor="#000000"/>
</vector>

然后像

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:srcCompat="@drawable/ic_triangle_right"
    />

要更改颜色和方向,请使用android:tintandroid:rotation

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:srcCompat="@drawable/ic_triangle_right"
    android:rotation="180" // change direction
    android:tint="#00f" // change color
    />

结果

在此处输入图片说明

要更改矢量的形状,可以更改矢量的宽度/高度。示例将宽度更改为10dp

<vector 
        android:width="10dp"
        android:height="24dp"
        >
       ...
</vector>

在此处输入图片说明


谢谢,我真的不知道这些向量如何工作。我需要结果
Hossein Shahdoost

如何增加和减少这些三角形的大小?通过指定高度和宽度,它不起作用
Aayushi

46

您可以使用矢量可绘制对象

如果您的最低API低于21,则Android Studio会在构建时自动为这些较低版本创建PNG位图(请参见Vector Asset Studio)。如果您使用支持库,则Android甚至可以管理API 7之下的“实际向量”(有关更多信息,请参见底部的这篇文章的更新)。

一个向上的红色三角形是:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="100dp"
    android:width="100dp"
    android:viewportHeight="100"
    android:viewportWidth="100" >
    <group
        android:name="triableGroup">
        <path
            android:name="triangle"
            android:fillColor="#FF0000"
            android:pathData="m 50,0 l 50,100 -100,0 z" />
    </group>
</vector>

将其添加到布局中,并记住如果旋转三角形则设置clipChildren =“ false”。

<?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:clipChildren="false">

    <ImageView
        android:layout_width="130dp"
        android:layout_height="100dp"
        android:rotation="0"
        android:layout_centerInParent="true"
        android:background="@drawable/triangle"/>

</RelativeLayout>

在此处输入图片说明

通过设置视图的layout_width / layout_height属性来更改三角形的大小(宽度/高度)。这样,如果数学正确的话,您也可以获得同等的三角关系。

更新25.11.2017

如果使用支持库,则可以使用最早到API 7的实向量(而不是创建位图)。只需添加:

vectorDrawables.useSupportLibrary = true

做你defaultConfig在你的模块的build.gradle。

然后像这样设置(vector xml)drawable:

<ImageView
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    app:srcCompat="@drawable/triangle" />

一切都在Vector Asset Studio页面上很好地记录了下来。

自此功能以来,我一直在完全不使用图标的位图的情况下工作。这也大大减少了APK的大小。


1
发布链接,然后有人会为您上传:-)
GabrielOshiro

1
+1 vectorDrawables.useSupportLibrary = true的额外好处是您可以使用中定义的颜色colors.xml,因为位图是在构建过程中创建的(当定义的颜色不可用时)。
罗布

39

在这种情况下,我将明确地实施View:

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

public class TriangleShapeView extends View {

    public TriangleShapeView(Context context) {
        super(context);
    }

    public TriangleShapeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int w = getWidth() / 2;

        Path path = new Path();
        path.moveTo( w, 0);
        path.lineTo( 2 * w , 0);
        path.lineTo( 2 * w , w);
        path.lineTo( w , 0);
        path.close();

        Paint p = new Paint();
        p.setColor( Color.RED );

        canvas.drawPath(path, p);
    }
}

如下在布局中使用它:

<TriangleShapeView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff487fff">
</TriangleShapeView>

使用此实现将为您提供以下结果:

在此处输入图片说明


<com.your.path.to.view.TriangleShapeView ... />
工作

太棒了。如何更改三角形的颜色。说初始颜色是灰色,但是在onTouch或onClick上变为红色?
Fshamri 2015年

这比xml中的破解要好得多
dorsz '16

@彼得嗨。您能帮我一点点的改善吗?我需要将右上角四舍五入。我怎么能做到这一点?
巴特里奥

1
如何在三角形内添加文字?
Sakiboy

38

Jacek Milewski解决方案为我工作,根据他的解决方案,如果需要和倒三角形,可以使用以下方法:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <rotate
            android:fromDegrees="45"
            android:toDegrees="45"
            android:pivotX="135%" 
            android:pivotY="15%">
            <shape android:shape="rectangle">    
                <solid android:color="@color/aquamarine" />
            </shape>
        </rotate>
    </item>
</layer-list>

-1这样,您将无法获得等边三角形。而且,无论如何,它都有很多潜在的问题。stackoverflow.com/questions/20805826/...
j_kubik

21

在此处查看答案: 无图像的自定义箭头:Android

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="32dp"
        android:height="24dp"
        android:viewportWidth="32.0"
        android:viewportHeight="24.0">
    <path android:fillColor="#e4e4e8"
          android:pathData="M0 0 h32 l-16 24 Z"/>
</vector>

箭头


11

我可以使用XML来帮助您吗?


只是,

自定义布局(切片):

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.View;

public class Slice extends View {

    Paint mPaint;

    Path mPath;

    public enum Direction {
        NORTH, SOUTH, EAST, WEST
    }

    public Slice(Context context) {
        super(context);
        create();
    }

    public Slice(Context context, AttributeSet attrs) {
        super(context, attrs);
        create();
    }

    public void setColor(int color) {
        mPaint.setColor(color);
        invalidate();
    }

    private void create() {
        mPaint = new Paint();
        mPaint.setStyle(Style.FILL);
        mPaint.setColor(Color.RED);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mPath = calculate(Direction.SOUTH);
        canvas.drawPath(mPath, mPaint);
    }

    private Path calculate(Direction direction) {
        Point p1 = new Point();
        p1.x = 0;
        p1.y = 0;

        Point p2 = null, p3 = null;

        int width = getWidth();

        if (direction == Direction.NORTH) {
            p2 = new Point(p1.x + width, p1.y);
            p3 = new Point(p1.x + (width / 2), p1.y - width);
        } else if (direction == Direction.SOUTH) {
            p2 = new Point(p1.x + width, p1.y);
            p3 = new Point(p1.x + (width / 2), p1.y + width);
        } else if (direction == Direction.EAST) {
            p2 = new Point(p1.x, p1.y + width);
            p3 = new Point(p1.x - width, p1.y + (width / 2));
        } else if (direction == Direction.WEST) {
            p2 = new Point(p1.x, p1.y + width);
            p3 = new Point(p1.x + width, p1.y + (width / 2));
        }

        Path path = new Path();
        path.moveTo(p1.x, p1.y);
        path.lineTo(p2.x, p2.y);
        path.lineTo(p3.x, p3.y);

        return path;
    }
}

您的活动(示例):

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;

public class Layout extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Slice mySlice = new Slice(getApplicationContext());
        mySlice.setBackgroundColor(Color.WHITE);
        setContentView(mySlice, new LinearLayout.LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    }
}

工作示例:

在此处输入图片说明


Calculate您可能对..感兴趣的另一个绝对简单的功能

private Path Calculate(Point A, Point B, Point C) {
    Path Pencil = new Path();
    Pencil.moveTo(A.x, A.y);
    Pencil.lineTo(B.x, B.y);
    Pencil.lineTo(C.x, C.y);
    return Pencil;
}

11
+1是,可以。谢谢你 还有,除了OP其他人,其正在寻找解决方案谁没有为XML专门询问-我也是如此
johndodo

1
onDraw将不会在派生自ViewGroup的类上调用,这不是默认设置。您必须通过setWillNotDraw(false)启用绘图,或者从View继承。
Blago 2015年

11

使用矢量可绘制:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
   android:width="24dp"
   android:height="24dp"
   android:viewportWidth="24.0"
   android:viewportHeight="24.0">
   <path
        android:pathData="M0,0 L24,0 L0,24 z"
        android:strokeColor="@color/color"
        android:fillColor="@color/color"/>
</vector>

在此处输入图片说明


使用Lz最后解决了我的问题,谢谢!
oxied

6

对于那些想要直角三角形箭头的人,这里您可以:

步骤1:创建一个可绘制的XML文件,将以下XML内容复制并粘贴到可绘制的XML中。(请注意,您可以为可绘制的XML文件使用任何名称。就我而言,我将其命名为“ v_right_arrow”)

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item >
        <rotate
            android:fromDegrees="45"
            android:toDegrees="-45"
            android:pivotX="15%"
            android:pivotY="-36%" >
            <shape
                android:shape="rectangle"  >
                <stroke android:color="@android:color/transparent" android:width="1dp"/>
                <solid
                    android:color="#000000"  />
            </shape>
        </rotate>
    </item>
</layer-list>

步骤2:在布局的XML中,创建一个View并将其背景绑定到您刚刚在STEP 1中创建的可绘制XML 。就我而言,我将v_right_arrow绑定到View的background属性。

<View
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:background="@drawable/v_right_arrow">
</View>

样本输出:

在此处输入图片说明

希望这有帮助,祝你好运!


6

您可以使用以下xml在背景中添加以下三角形

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="100dp"
    android:width="100dp"
    android:viewportHeight="100"
    android:viewportWidth="100" >
    <group
        android:name="triableGroup">
        <path
            android:name="triangle"
            android:fillColor="#848af8"
            android:pathData="M 0,20 L 0,0 L 100,0 L 100,20 L 54,55  l -1,0.6  l -1,0.4  l -1,0.2  l -1,0   l -1,-0  l -1,-0.2  l -1,-0.4  l -1,-0.6    L 46,55   L 0,20 -100,-100 Z" />
    </group>
</vector>

定制xml设计的整个逻辑在中pathData。考虑左上角为(0,0)并根据需要设计布局。检查答案。


4
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <rotate
            android:fromDegrees="45"
            android:toDegrees="45"
            android:pivotX="-40%"
            android:pivotY="87%" >
            <shape
                android:shape="rectangle" >
                <stroke android:color="@android:color/transparent" android:width="0dp"/>
                <solid
                    android:color="#fff" />
            </shape>
        </rotate>
    </item>
</layer-list>

4
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item>
            <rotate
                android:fromDegrees="45"
                android:pivotX="135%"
                android:pivotY="1%"
                android:toDegrees="45">
                <shape android:shape="rectangle">
                    <stroke
                        android:width="-60dp"
                        android:color="@android:color/transparent" />
                    <solid android:color="@color/orange" />
                </shape>
            </rotate>
        </item>
    </layer-list>

3

我从未做过此事,但是据我了解,您可以使用PathShape类:http : //developer.android.com/reference/android/graphics/drawable/shapes/PathShape.html


2
如何在XML中使用路径形状?
塞巴斯蒂安·罗斯

这对于找到合适的零件很有帮助,但没有提供足够的使用说明。尽管如此,还是谢谢你。
纳瓦拉

抱歉,塞巴斯蒂安(Sebastian)和纳瓦(Navarr)...我在回答中表示从未使用过它,因此我不确定该如何使用它。这看起来就像是可以完成工作的课程。我同意,尽管没有足够的文档。
贾斯汀2012年

3
PathShape似乎没有关联的XML语法。XML Shape标签仅支持矩形,椭圆形,直线和环形。developer.android.com/guide/topics/resources/…–
Nilzor

3

我来晚了,遇到了同样的问题,Google指出了我第一个结果是StackOverflow这个线程。

我尝试使用xml方式添加三角形,并发现一个问题,即通过xml方式的三角形占用的空间比看上去要大。

查看屏幕快照,其中包含布局边界

在此处输入图片说明

因此,最终制作了可以绘制以下任何类型的Triangle的自定义视图类:

  1. 向上指
  2. 朝下
  3. 左指向&
  4. 正确指向

阿萨斯

package com.hiteshsahu.materialupvotewidget;    
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;

public class TriangleShapeView extends View {

    private int colorCode = Color.DKGRAY;

    public int getColorCode() {
        return colorCode;
    }

    public void setColorCode(int colorCode) {
        this.colorCode = colorCode;
    }

    public TriangleShapeView(Context context) {
        super(context);
        if (isInEditMode())
            return;
    }

    public TriangleShapeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        if (isInEditMode())
            return;
    }

    public TriangleShapeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        if (isInEditMode())
            return;
    }


    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int w = getWidth() / 2;
        int h = getHeight() / 2;

        //Choose what type of triangle you want here
        Path path = getLeftTriangle(w, h);

        path.close();
        Paint p = new Paint();
        p.setColor(colorCode);
        p.setAntiAlias(true);

        canvas.drawPath(path, p);
    }

    @NonNull
    /**
     * Return Path for down facing triangle
     */
    private Path getInvertedTriangle(int w, int h) {
        Path path = new Path();
        path.moveTo(0, 0);
        path.lineTo(w, 2 * h);
        path.lineTo(2 * w, 0);
        path.lineTo(0, 0);
        return path;
    }

    @NonNull
    /**
     * Return Path for Up facing triangle
     */
    private Path getUpTriangle(int w, int h) {
        Path path = new Path();
        path.moveTo(0, 2 * h);
        path.lineTo(w, 0);
        path.lineTo(2 * w, 2 * h);
        path.lineTo(0, 2 * h);
        return path;
    }

    @NonNull
    /**
     * Return Path for Right pointing triangle
     */
    private Path getRightTriangle(int w, int h) {
        Path path = new Path();
        path.moveTo(0, 0);
        path.lineTo(2 * w, h);
        path.lineTo(0, 2 * h);
        path.lineTo(0, 0);
        return path;
    }

    @NonNull
    /**
     * Return Path for Left pointing triangle
     */
    private Path getLeftTriangle(int w, int h) {
        Path path = new Path();
        path.moveTo(2 * w, 0);
        path.lineTo(0, h);
        path.lineTo(2 * w, 2 * h);
        path.lineTo(2 * w, 0);
        return path;
    }
}

您可以像这样在xml布局中简单地使用它

 <com.hiteshsahu.materialupvote.TriangleShapeView
            android:layout_width="50dp"
            android:layout_height="50dp"></com.hiteshsahu.materialupvote.TriangleShapeView>

我知道OP需要xml解决方案中的解决方案,但是正如我指出的xml方法存在的问题。希望对您有所帮助。


2

使用Jacek Milewski的解决方案,我制作了带有透明背景的定向向下角度。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <rotate
            android:fromDegrees="135"
            android:pivotX="65%"
            android:pivotY="20%"
            android:toDegrees="135"
            >
            <shape android:shape="rectangle">
                <stroke
                    android:width="1dp"
                    android:color="@color/blue"
                    />
                <solid android:color="@color/transparent" />
            </shape>
        </rotate>
    </item>
</layer-list>

您可以更改android:pivotXandroid:pivotY移动角度。

用法:

<ImageView
    android:layout_width="10dp"
    android:layout_height="10dp"
    android:src="@drawable/ic_angle_down"
    />

在此处输入图片说明

参数取决于图像的大小。例如,如果ImageView大小为100dp * 80dp,则应使用以下常量:

<rotate
    android:fromDegrees="135"
    android:pivotX="64.5%"
    android:pivotY="19%"
    android:toDegrees="135"
    >

在此处输入图片说明


2

我尝试创建三角图像,例如android导航栏的后退按钮,但是我没有找到任何解决方案。

现在,我自己找到了解决方案,并希望与他人分享。

三角形导航栏android

在下面使用xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
    android:bottom="20dp"
    android:left="480dp"
    android:right="60dp"
    android:top="20dp">
    <shape>
        <size android:width="60dp" />
        <corners android:radius="80dp"/>
        <solid android:color="#AAA" />
    </shape>
</item>
<item
    android:bottom="480dp"
    android:right="70dp"
    android:top="20dp">
    <rotate
        android:fromDegrees="-28"
        android:pivotX="96%"
        android:pivotY="50%"
        android:toDegrees="-20">
        <shape>
            <corners android:radius="80dp"/>
            <size android:height="60dp" />
            <solid android:color="#AAA" />
        </shape>
    </rotate>
</item>

<item
    android:bottom="20dp"
    android:right="70dp"
    android:top="480dp">
    <rotate
        android:fromDegrees="28"
        android:pivotX="96%"
        android:pivotY="50%"
        android:toDegrees="-20">
        <shape>
            <corners android:radius="80dp"/>
            <size android:height="60dp" />
            <solid android:color="#AAA" />
        </shape>
    </rotate>
</item>


0
  <LinearLayout
        android:id="@+id/ly_fill_color_shape"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center"
        android:background="@drawable/shape_triangle"
        android:gravity="center"
        android:orientation="horizontal" >
    </LinearLayout>

<item>
    <rotate
        android:fromDegrees="45"
        android:pivotX="-15%"
        android:pivotY="77%"
        android:toDegrees="45" >
        <shape android:shape="rectangle" >
            <stroke
                android:width="2dp"
                android:color="@color/black_color" />

            <solid android:color="@color/white" />

            <padding android:left="1dp" />
        </shape>
    </rotate>
</item>
<item android:top="200dp">
    <shape android:shape="line" >
        <stroke
            android:width="1dp"
            android:color="@color/black_color" />

        <solid android:color="@color/white" /> 
    </shape>
</item>


-1这样,您将无法获得等边三角形。而且,无论如何,它都有很多潜在的问题。stackoverflow.com/questions/20805826/...
j_kubik

0

Google 在此处提供了一个等边三角形。
选择VectorDrawable,以便尺寸灵活。
它已作为插件集成到Android Studio中。

如果您有SVG图像,也可以使用图像将其转换为VectorDrawable。

一旦有了VectorDrawable,就像其他人提到的那样,更改其颜色和旋转很容易。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.