Android实现梯形TextView效果

效果图:

自定义代码实现逻辑:

public class LadderTextView extends android.support.v7.widget.AppCompatTextView {
    private static final String TAG = "LadderView";
    private Path linePath;
    private Paint paint, textPaint;
    private int width, height;
    private float strokeWidth = 2;
    private Region mRegion;
    private String textContent;
    private int lineOffset = 0;//划线的偏移量
    private int textOffset = 0;//文本的偏移量
    private float offsetScale = 1;//梯高与(梯顶与梯底)之差的比例(梯底比梯顶长)
    private boolean isLeft = true;//分为左和右两种斜角梯形模式
    private boolean isSelected = false;//是否是选定
    private int selectedColor = Color.BLACK;

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

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

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

    private void initAttributes(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LadderTextView);
        textContent = typedArray.getString(R.styleable.LadderTextView_textContent);
        offsetScale = typedArray.getFloat(R.styleable.LadderTextView_offsetScale, 0.5f);
        isLeft = typedArray.getBoolean(R.styleable.LadderTextView_isLeft, true);
        isSelected = typedArray.getBoolean(R.styleable.LadderTextView_isSelected, true);
        selectedColor = typedArray.getColor(R.styleable.LadderTextView_selectedColor, Color.GREEN);
        strokeWidth = typedArray.getDimension(R.styleable.LadderTextView_strokeWidth, 1);
        typedArray.recycle();
    }

    private void init() {
        Log.v(TAG, "init");
        mRegion = new Region();
        paint = new Paint();
        textPaint = new Paint();
        linePath = new Path();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(dp2px(getContext(), strokeWidth));
        paint.setColor(selectedColor);
        paint.setStyle(isSelected ? Paint.Style.FILL_AND_STROKE : Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);

        textPaint.setAntiAlias(true);
        textPaint.setTextSize(getTextSize());//传递TextSize(px)
        textPaint.setColor(isSelected ? Color.WHITE : selectedColor);
        setText("");//去除掉原有的Text内容
        lineOffset = dp2px(getContext(), strokeWidth) / 2;
        textOffset = (int) (getTextSize() / 2) + getBaseline() * 2;
        Log.v(TAG, "lineOffset textOffset ->" + lineOffset + " " + textOffset);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        width = getWidth();
        height = getHeight();
        Log.v(TAG, "width height->" + width + " " + height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.v(TAG, "onDraw");
        if (isLeft) {
            linePath.moveTo(0 + lineOffset, 0 + lineOffset);
            linePath.lineTo(width, 0 + lineOffset);
            linePath.lineTo((int) (width - offsetScale * height), height - lineOffset);
            linePath.lineTo(0 + lineOffset, height - lineOffset);
            linePath.close();
            setTextAlignment(TEXT_ALIGNMENT_TEXT_START);
            canvas.drawPath(linePath, paint);
            canvas.drawText(textContent == null ? "" : textContent,
                    getPaddingStart() + lineOffset,
                    height / 2 + textOffset, textPaint);
        } else {
            linePath.moveTo(0 + lineOffset + offsetScale * height, 0 + lineOffset);
            linePath.lineTo(width - lineOffset, 0 + lineOffset);
            linePath.lineTo(width - lineOffset, height - lineOffset);
            linePath.lineTo(0, height - lineOffset);
            linePath.close();
            setTextAlignment(TEXT_ALIGNMENT_TEXT_END);
            canvas.drawPath(linePath, paint);
            canvas.drawText(textContent == null ? "" : textContent,
                    getWidth() - lineOffset - getPaddingEnd() - getDrawTextWidth(textPaint, textContent),
                    height / 2 + textOffset, textPaint);
        }

    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (!isInRegion(event)) {//点击的点的位置不在范围内则不响应
                return false;
            }
        }
        return super.dispatchTouchEvent(event);
    }

    /**
     * 判断点击的位置是否在要求的范围内
     * @param event
     * @return
     */
    public boolean isInRegion(MotionEvent event) {
        RectF rectF = new RectF();
        linePath.computeBounds(rectF, true);
        mRegion.setPath(linePath, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));
        return mRegion.contains((int) event.getX(), (int) event.getY());
    }

    /**
     * 获取要画的字符串的宽度
     *
     * @param paint
     * @param textContent
     * @return
     */
    private int getDrawTextWidth(Paint paint, String textContent) {
        float totalWidth = 0f;
        if (textContent != null && textContent.length() > 0) {
            int len = textContent.length();
            float[] widths = new float[len];
            paint.getTextWidths(textContent, widths);
            for (int j = 0; j < len; j++) {
                totalWidth += widths[j];
            }
        }
        return (int) Math.ceil(totalWidth);
    }

    /**
     * @param dpValue (DisplayMetrics类中属性density)
     * @return
     */
    private int dp2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    public void setTextContent(String textContent) {
        this.textContent = textContent;
        invalidate();
    }

    public void setMSelected(boolean isSelected) {
        textPaint.setColor(isSelected ? Color.WHITE : selectedColor);
        paint.setStyle(isSelected ? Paint.Style.FILL_AND_STROKE : Paint.Style.STROKE);
        this.isSelected = isSelected;
        invalidate();
    }

    @Override
    public boolean isSelected() {
        return isSelected;
    }
}

要点分析

1.背景与文本内容的绘制

计算好四个点的位置连线,TextView默认的文本内容则设置为空字符串,采用drawText的方式来实现文本的显示。需要注意的是计算文本的字号长度大小、颜色以及位于整个view的位置、偏移量等。

2.梯形范围内外的点击事件处理

依照于设计,梯形内的点击才有响应,则要计算点击的位置是否在梯形内,然后通过dispatchTouchEvent来做事件的分发。

 /**
     * 判断点击的位置是否在要求的范围内
     * @param event
     * @return
     */
    public boolean isInRegion(MotionEvent event) {
        RectF rectF = new RectF();
        linePath.computeBounds(rectF, true);
        mRegion.setPath(linePath, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));
        return mRegion.contains((int) event.getX(), (int) event.getY());
    }

3.其它自定义属性

依据于需求来定,注意invalidate。

最后,完整代码

https://github.com/ganshenml/LadderTextView

以上就是Android实现梯形TextView效果的详细内容,更多关于Android 梯形TextView的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android文本视图TextView实现跑马灯效果

    本文实例为大家分享了Android文本视图TextView实现跑马灯效果的具体代码,供大家参考,具体内容如下 MainActivity package com.example.junior; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import android.view.View; import android.widget.TextView; public class MarqueeA

  • android TextView中识别多个url并分别点击跳转方法详解

    实现方案: 我们直接参考实例代码: private String pattern = "((http|ftp|https)://)(([a-zA-Z0-9\\._-]+\\.[a-zA-Z]{2,6})|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\\&%_\\./-~-]*)?|(([a-zA-Z0-9\\._-]+\\.[a-zA-Z]{2,6})|([0-9]{1,3}\

  • Android使用TypeFace设置TextView的文字字体

    在Android里面设置一个TextView的文字颜色和文字大小,都很简单,也是一个常用的基本功能.但很少有设置文字字体的,今天要分享的是通过TypeFace去设置TextView的文字字体,布局里面有两个Button,总共包含两个小功能:换字体和变大. 功能的核心部分主要是两点: 创建assets外部资源文件夹,将ttf格式的字体文件放在该目录下 通过TypeFace类的createFromAsset方法,让TextView通过setTypeFace来改变字体 完整源码如下: 1.主Activ

  • Android使用AutoCompleteTextView实现自动填充功能的案例

    (1)首先实现AutoCompleteTextView功能所需要的适配器数据源共有两种方法,一种结果是手工配置的,另一汇总是通过xml文件制定的数据(当然也可以通过网上资源获得) 这里只讲前两种! (2)布局的页面代码都一样如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools&

  • Flutter中嵌入Android 原生TextView实例教程

    前言 本篇文章 中写到的是 flutter 调用了Android 原生的 TextView 案例 添加原生组件的流程基本上可以描述为: 1 android 端实现原生组件PlatformView提供原生view 2 android 端创建PlatformViewFactory用于生成PlatformView 3 android 端创建FlutterPlugin用于注册原生组件 4 flutter 平台嵌入 原生view 1 创建原生组件 创建在fLutter工程时会生成几个文件夹,lib是放fl

  • Android开发实现TextView超链接5种方式源码实例

    Android实现TextView超链接一共有五种方式:推荐第四种.第五种 1. 直接在xml文件中配置autoLink属性(简单易用,效果单一) autoLink属性一共有六个值,分别是none(正常),web(将文本识别为一个网址),phone(将文本识别为一个电话号码),mail(将文本识别为一个邮件地址),map(这个,呃,该怎么表述呢?会打开地图应用),all(根据文本自动识别).一般情况下我们设置为all即可,我们看看,这个时候它就会自动将TextView中的电话号码.邮件地址.网页

  • Android为textView设置setText的时候报错的讲解方案

    在对中TextView setText 覆值int 时报错,网上查下原因是setText整型表明是设值R.id.xxx,当然找不到. 解决方法是将int转化为string,用String.valueOf(xxx) 一.我的代码如下:就是我textView设置值 if (list != null) { for (Student stu : list) { //如果一下子赋值的话是不正确的 tv_name.setText(stu.getName()); tv_sex.setText(stu.getS

  • 在Android TextView中显示图片的4种方式详解

    我们知道,TextView控件一般是用来显示文本的,而图片一般是用ImageView控件来显示. 那TextView能否显示图片呢?答案是肯定的!下面列出常见的4种方式. 1.XML文件中指定属性值 这种方式应该是最常用的了,在TextView的左上右下显示图片,可用  android:drawableLeft  android:drawableTop  android:drawableRight  android:drawableBottom 比如我们要在TextView的顶部设置图片,代码如

  • android使用TextView实现跑马灯效果

    本文实例为大家分享了android使用TextView实现跑马灯效果的具体代码,供大家参考,具体内容如下 先上效果图:此为静态图,实际动态中文字匀速向左滑动. 实现步骤: 第一步:创建好布局页面 <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.c

  • 详解Android TextView属性ellipsize多行失效的解决思路

    本文介绍了Android TextView属性ellipsize多行失效的解决思路,分享给大家,具体如下: 多余文字显示省略号的常规做法 android:ellipsize="end" //省略号显示在末尾 android:ellipsize="middle" //省略号显示在中间 但是设置android:maxLines="2" 以后,ellipsize的值end有效,middle无效,本方法解决middle无效的问题 /** * 字符串显示到

  • Android开发中TextView各种常见使用方法小结

    本文实例讲述了Android开发中TextView各种常见使用方法.分享给大家供大家参考,具体如下: 效果图: XML布局文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@+id/root" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:

  • Android文本视图TextView实现聊天室效果

    本文实例为大家分享了Android文本视图TextView实现聊天室的具体代码,供大家参考,具体内容如下 Math.random()生成随机数的范围是 0 到 1 之间的 日期时间格式new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); //年-月-日 时:分:秒  : HH大写24小时, String类的format()方法用于创建格式化的字符串以及连接多个字符串对象. MainActivity package com.example.junior

  • Android开发之TextView使用intent传递信息,实现注册界面功能示例

    本文实例讲述了Android开发之TextView使用intent传递信息,实现注册界面功能.分享给大家供大家参考,具体如下: 使用intent在活动间传递值 首先是 MainActuvity 活动(注册界面 写完个人信息点击注册 ) 跳转到 In 活动 (通过 intent 获得 MainActivity 中的信息 ) 效果图如下: MainActivity 实现: Java代码: public class Home extends AppCompatActivity { //用于存放个人注册

随机推荐