android TextView下划线,圆角边框,数逐字显示,虚线边框, 渐变色背景框, 阴影背景框

 长方形

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <size android:width="10dp" android:height="5dp" />
    <corners android:radius="2dp"/>
    <solid android:color="@color/app_white" />
</shape>

#cccccc#E1E1E1#e5e5e5#dddddd#F5F5F5#F8F8F8#FAFAFA#E6E6E6

xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"

<?xml version="1.0" encoding="utf-8"?>

 阴影背景框

内View 样式drawable

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@color/white" />
    <corners android:topLeftRadius="7dp" android:topRightRadius="7dp"
        android:bottomLeftRadius="7dp" android:bottomRightRadius="7dp" />
</shape>

样式文件

<declare-styleable name="ShadowContainer">
    <attr name="containerShadowColor" format="color"/>
    <attr name="containerShadowRadius" format="dimension"/>
    <attr name="containerDeltaLength" format="dimension"/>
    <attr name="containerCornerRadius" format="dimension"/>
    <attr name="deltaX" format="dimension"/>
    <attr name="deltaY" format="dimension"/>
    <attr name="enable" format="boolean"/>
</declare-styleable>

自定义阴影View

/**
 阴影效果
 */
public class ShadowContainerAllEdge extends ViewGroup {
    private final float deltaLength;
    private final float cornerRadius;
    private final Paint mShadowPaint;
    private boolean drawShadow;

    public ShadowContainerAllEdge(Context context) {
        this(context, null);
    }

    public ShadowContainerAllEdge(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ShadowContainerAllEdge(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ShadowContainer);
        int shadowColor = a.getColor(R.styleable.ShadowContainer_containerShadowColor, Color.RED);
//        int shadowColor = Color.RED;
        float shadowRadius = a.getDimension(R.styleable.ShadowContainer_containerShadowRadius, 0);
        deltaLength = a.getDimension(R.styleable.ShadowContainer_containerDeltaLength, 0);
        cornerRadius = a.getDimension(R.styleable.ShadowContainer_containerCornerRadius, 0);
        float dx = a.getDimension(R.styleable.ShadowContainer_deltaX, 0);
        float dy = a.getDimension(R.styleable.ShadowContainer_deltaY, 0);
        drawShadow = a.getBoolean(R.styleable.ShadowContainer_enable, true);
        a.recycle();
        mShadowPaint = new Paint();
        mShadowPaint.setStyle(Paint.Style.FILL);
        mShadowPaint.setAntiAlias(true);
        mShadowPaint.setColor(shadowColor);
        mShadowPaint.setShadowLayer(shadowRadius, dx, dy, shadowColor);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (drawShadow) {
            if (getLayerType() != LAYER_TYPE_SOFTWARE) {
                setLayerType(LAYER_TYPE_SOFTWARE, null);
            }
            View child = getChildAt(0);
            int left = child.getLeft();
            int top = child.getTop();
            int right = child.getRight();
            int bottom = child.getBottom();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                canvas.drawRoundRect(left, top, right, bottom, cornerRadius, cornerRadius, mShadowPaint);
            } else {
                Path drawablePath = new Path();
                drawablePath.moveTo(left + cornerRadius, top);
                drawablePath.arcTo(new RectF(left, top, left + 2 * cornerRadius, top + 2 * cornerRadius), -90, -90, false);
                drawablePath.lineTo(left, bottom - cornerRadius);
                drawablePath.arcTo(new RectF(left, bottom - 2 * cornerRadius, left + 2 * cornerRadius, bottom), 180, -90, false);
                drawablePath.lineTo(right - cornerRadius, bottom);
                drawablePath.arcTo(new RectF(right - 2 * cornerRadius, bottom - 2 * cornerRadius, right, bottom), 90, -90, false);
                drawablePath.lineTo(right, top + cornerRadius);
                drawablePath.arcTo(new RectF(right - 2 * cornerRadius, top, right, top + 2 * cornerRadius), 0, -90, false);
                drawablePath.close();
                canvas.drawPath(drawablePath, mShadowPaint);
            }
        }
        super.dispatchDraw(canvas);
    }

    public void setDrawShadow(boolean drawShadow){
        if (this.drawShadow == drawShadow){
            return;
        }
        this.drawShadow = drawShadow;
        postInvalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (getChildCount() != 1) {
            throw new IllegalStateException("子View只能有一个");
        }
        int measuredWidth = getMeasuredWidth();
        int measuredHeight = getMeasuredHeight();
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        View child = getChildAt(0);
        LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
        int childBottomMargin = (int) (Math.max(deltaLength, layoutParams.bottomMargin) + 1);
        int childLeftMargin = (int) (Math.max(deltaLength, layoutParams.leftMargin) + 1);
        int childRightMargin = (int) (Math.max(deltaLength, layoutParams.rightMargin) + 1);
        int childTopMargin = (int) (Math.max(deltaLength, layoutParams.topMargin) + 1);
        int widthMeasureSpecMode;
        int widthMeasureSpecSize;
        int heightMeasureSpecMode;
        int heightMeasureSpecSize;
        if (widthMode == MeasureSpec.UNSPECIFIED){
            widthMeasureSpecMode = MeasureSpec.UNSPECIFIED;
            widthMeasureSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        }else {
            if (layoutParams.width == LayoutParams.MATCH_PARENT) {
                widthMeasureSpecMode = MeasureSpec.EXACTLY;
                widthMeasureSpecSize = measuredWidth - childLeftMargin - childRightMargin;
            } else if (LayoutParams.WRAP_CONTENT == layoutParams.width) {
                widthMeasureSpecMode = MeasureSpec.AT_MOST;
                widthMeasureSpecSize = measuredWidth - childLeftMargin - childRightMargin;
            } else {
                widthMeasureSpecMode = MeasureSpec.EXACTLY;
                widthMeasureSpecSize = layoutParams.width;
            }
        }
        if (heightMode == MeasureSpec.UNSPECIFIED){
            heightMeasureSpecMode = MeasureSpec.UNSPECIFIED;
            heightMeasureSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        }else {
            if (layoutParams.height == LayoutParams.MATCH_PARENT) {
                heightMeasureSpecMode = MeasureSpec.EXACTLY;
                heightMeasureSpecSize = measuredHeight - childBottomMargin - childTopMargin;
            } else if (LayoutParams.WRAP_CONTENT == layoutParams.height) {
                heightMeasureSpecMode = MeasureSpec.AT_MOST;
                heightMeasureSpecSize = measuredHeight - childBottomMargin - childTopMargin;
            } else {
                heightMeasureSpecMode = MeasureSpec.EXACTLY;
                heightMeasureSpecSize = layoutParams.height;
            }
        }
        measureChild(child, MeasureSpec.makeMeasureSpec(widthMeasureSpecSize, widthMeasureSpecMode), MeasureSpec.makeMeasureSpec(heightMeasureSpecSize, heightMeasureSpecMode));
        int parentWidthMeasureSpec = MeasureSpec.getMode(widthMeasureSpec);
        int parentHeightMeasureSpec = MeasureSpec.getMode(heightMeasureSpec);
        int height = measuredHeight;
        int width = measuredWidth;
        int childHeight = child.getMeasuredHeight();
        int childWidth = child.getMeasuredWidth();
        if (parentHeightMeasureSpec == MeasureSpec.AT_MOST){
            height = childHeight + childTopMargin + childBottomMargin;
        }
        if (parentWidthMeasureSpec == MeasureSpec.AT_MOST){
            width = childWidth + childRightMargin + childLeftMargin;
        }
        if (width < childWidth + 2 * deltaLength){
            width = (int) (childWidth + 2 * deltaLength);
        }
        if (height < childHeight + 2 * deltaLength){
            height = (int) (childHeight + 2 * deltaLength);
        }
        if (height != measuredHeight || width != measuredWidth){
            setMeasuredDimension(width, height);
        }
    }

    static class LayoutParams extends MarginLayoutParams{

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }
    }

    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new LayoutParams(p);
    }

    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        View child = getChildAt(0);
        int measuredWidth = getMeasuredWidth();
        int measuredHeight = getMeasuredHeight();
        int childMeasureWidth = child.getMeasuredWidth();
        int childMeasureHeight = child.getMeasuredHeight();
        child.layout((measuredWidth - childMeasureWidth) / 2, (measuredHeight - childMeasureHeight) / 2, (measuredWidth + childMeasureWidth) / 2, (measuredHeight + childMeasureHeight) / 2);
    }
}

 调用

app:containerDeltaLength——外围距离

app:containerCornerRadius——内内容半径

app:containerShadowRadius——阴影半径

<com.dlc.observabletest.ShadowContainerAllEdge
    android:layout_width="200dp"
    android:layout_height="100dp"
    app:containerDeltaLength="2dp"
    app:containerShadowColor="#4D00C8D2"
    app:containerCornerRadius="7dp"
    app:containerShadowRadius="2dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/shape_radius_14_white"
        android:text="aabb"></TextView>

</com.dlc.observabletest.ShadowContainerAllEdge>

设置上下圆角

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/white" />
    <stroke android:width="1dp" android:color="@color/white"/>
    <corners   android:topLeftRadius="10dp"
        android:topRightRadius="10dp"
        android:bottomRightRadius="0dp"
        android:bottomLeftRadius="0dp" />

</shape>

中空框

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <stroke android:width="@dimen/normal_1dp" android:color="@color/color_EF611E"/>
    <corners android:radius="@dimen/normal_5dp"/>

</shape>

 渐变色背景框

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="2pt" />

    <padding
        android:bottom="0dp"
        android:left="0dp"
        android:right="0dp"
        android:top="0dp" />

    <gradient
        android:angle="180"
        android:endColor="@color/top_endc"
        android:startColor="@color/top_startc"
        android:type="linear"/>

</shape>

虚线边框

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#ffffff" />
    <corners android:radius="10dp" />
    <stroke
        android:width="1dp"
        android:color="@color/color_linexulv"
        android:dashGap="3pt"
        android:dashWidth="6pt"/>
    <padding
        android:bottom="0dp"
        android:left="0dp"
        android:right="0dp"
        android:top="0dp" />

</shape>

drawable文件下创建 border_red.xml样式
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#ffffff" />
    <corners android:radius="30dp" />
    <stroke
        android:width="1dp"
        android:color="#c416ff" />
    <padding
        android:bottom="5dp"
        android:left="10dp"
        android:right="10dp"
        android:top="5dp" />

</shape>

选中样式

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid android:color="#56eccb" />
            <corners android:radius="@dimen/normal_10dp" />
        </shape>

    </item>
    <item android:state_pressed="false">
        <shape android:shape="rectangle">
            <solid android:color="@color/public_color" />
            <corners android:radius="@dimen/normal_10dp" />
        </shape>
    </item>
</selector>

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="40dp"/>
    <solid android:color="@color/item_gank_grey"/>
</shape>

引用

<TextView

    android:id="@+id/item_gank_who"
    android:layout_width="50dp"
    android:layout_height="16dp"
    android:text="推荐"
    android:textColor="@color/item_gank_white"
    android:textSize="12sp"
    android:gravity="center"
    android:background="@drawable/border_red"
    />

无背景

holder.status.setBackgroundDrawable(null);

固定在顶部

android:layout_alignParentTop="true"

边框颜色

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke
        android:color="@color/company_info_blue"
        android:width="1dp"/>
    <solid android:color="@color/white"/>
    <corners android:radius="5dp"
        />
</shape>

人民币  

获取URL键值

final String epId = TextUtil.URLRequest(link).get("param");

public class TextUtil {

    public static boolean isEmpty(String str) {

        return TextUtils.isEmpty(str) || "null".equals(str);
    }

    //判断是否有表情
    public static boolean isEmojiCharacter(char codePoint) {
        return !(((codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA) || (codePoint == 0xD) || ((codePoint >= 0x20) && codePoint <= 0xD7FF)) || ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF)));
    }

    // 设置下划线
    public static TextView setBelowLine(TextView textView) {
        textView.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG); // 下划线
        return textView;
    }

    // 设置斜体字
    public static SpannableString setSpanWord(String word) {
        SpannableString sp = new SpannableString(word);
        // 设置斜体
        sp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC), 0,
                word.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        return sp;
    }

    // 设置字体颜色
    public static SpannableStringBuilder setStringColor(String word,
                                                        String changePart, String color) {
        char[] c = changePart.toCharArray();
        int lastIndex = c.length - 1;
        int start = word.indexOf(c[0]);
        int end = start + lastIndex + 1;
        SpannableStringBuilder style = new SpannableStringBuilder(word);
        style.setSpan(new ForegroundColorSpan(Color.parseColor(color)), start,
                end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return style;
    }

    /**
     * 格式化要显示的字符串,做非空判断
     * 该方法主要做用在ui显示这一块,用于更好地显示字符,防止null字符出现和空指针
     *
     * @param str 要验证的字符串
     * @return 参数若为空或“”或null字符串,则返回空,反之直接返回原有值
     */
    public static String formatString(String str) {
        if (TextUtils.isEmpty(str))
            return null;
        if ("null".equalsIgnoreCase(str))
            return null;
        return str;
    }
    /**
     * 去掉url中的路径,留下请求参数部分
     * @param strURL url地址
     * @return url请求参数部分
     */
    private static String TruncateUrlPage(String strURL)
    {
        String strAllParam=null;
        String[] arrSplit=null;

        strURL=strURL.trim().toLowerCase();

        arrSplit=strURL.split("[?]");
        if(strURL.length()>1)
        {
            if(arrSplit.length>1)
            {
                if(arrSplit[1]!=null)
                {
                    strAllParam=arrSplit[1];
                }
            }
        }

        return strAllParam;
    }
    /**
     * 解析出url参数中的键值对
     * 如 "index.jsp?Action=del&id=123",解析出Action:del,id:123存入map中
     * @param URL  url地址
     * @return  url请求参数部分
     */
    public static Map<String, String> URLRequest(String URL)
    {
        Map<String, String> mapRequest = new HashMap<String, String>();

        String[] arrSplit=null;

        String strUrlParam=TruncateUrlPage(URL);
        if(strUrlParam==null)
        {
            return mapRequest;
        }
        //每个键值为一组 www.2cto.com
        arrSplit=strUrlParam.split("[&]");
        for(String strSplit:arrSplit)
        {
            String[] arrSplitEqual=null;
            arrSplitEqual= strSplit.split("[=]");

            //解析出键值
            if(arrSplitEqual.length>1)
            {
                //正确解析
                mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);

            }
            else
            {
                if(arrSplitEqual[0]!="")
                {
                    //只有参数没有值,不加入
                    mapRequest.put(arrSplitEqual[0], "");
                }
            }
        }
        return mapRequest;
    }
}

逐字显示

/**
 * 作者:created by meixi
 * 邮箱:15913707499@163.com
 * 日期:2019/4/23 11
 */

public class FadeInTextView extends TextView {

    private Rect textRect = new Rect();

    private StringBuffer stringBuffer = new StringBuffer();

    private String[] arr;

    private int textCount;

    private int currentIndex = -1;

    /**
     * 每个字出现的时间
     */
    private int duration = 300;
    private ValueAnimator textAnimation;

    private TextAnimationListener textAnimationListener;


    public FadeInTextView setTextAnimationListener(TextAnimationListener textAnimationListener) {
        this.textAnimationListener = textAnimationListener;
        return this;
    }

    public FadeInTextView(Context context) {
        this(context, null);
    }

    public FadeInTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    protected void onDraw(final Canvas canvas) {
        super.onDraw(canvas);
//        使用setText代替重绘就不用自己去绘制text了
//        if (stringBuffer != null) {
//            drawText(canvas, stringBuffer.toString());
//        }
    }

    /**
     * 绘制文字
     *
     * @param canvas 画布
     */
    private void drawText(Canvas canvas, String textString) {
        textRect.left = getPaddingLeft();
        textRect.top = getPaddingTop();
        textRect.right = getWidth() - getPaddingRight();
        textRect.bottom = getHeight() - getPaddingBottom();
        Paint.FontMetricsInt fontMetrics = getPaint().getFontMetricsInt();
        int baseline = (textRect.bottom + textRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        //文字绘制到整个布局的中心位置
        canvas.drawText(textString, getPaddingLeft(), baseline, getPaint());
    }

    /**
     * 文字逐个显示动画  通过插值的方式改变数据源
     */
    private void initAnimation() {

        //从0到textCount - 1  是设置从第一个字到最后一个字的变化因子
        textAnimation = ValueAnimator.ofInt(0, textCount - 1);
        //执行总时间就是每个字的时间乘以字数
        textAnimation.setDuration(textCount * duration);
        //匀速显示文字
        textAnimation.setInterpolator(new LinearInterpolator());
        textAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int index = (int) valueAnimator.getAnimatedValue();
                //过滤去重,保证每个字只重绘一次
                if (currentIndex != index) {
                    stringBuffer.append(arr[index]);
                    currentIndex = index;
                    //所有文字都显示完成之后进度回调结束动画
                    if (currentIndex == (textCount - 1)) {
                        if (textAnimationListener != null) {
                            textAnimationListener.animationFinish();
                        }
                    }

                    //新思路的做法
                    setText(stringBuffer.toString());

                    /**
                     * 之前的做法刷新重绘text,需要自己控制文字的绘制,
                     * 看到网友的评论开拓了思路,既然是直接集成TextView
                     * 就可以直接使用setText()方法进行设置值了
                     */
                    //invalidate();老思路的做法
                }
            }
        });
    }

    /**
     * 设置逐渐显示的字符串
     *
     * @param textString
     * @return
     */
    public FadeInTextView setTextString(String textString) {
        if (textString != null) {
            //总字数
            textCount = textString.length();
            //存放单个字的数组
            arr = new String[textCount];
            for (int i = 0; i < textCount; i++) {
                arr[i] = textString.substring(i, i + 1);
            }
            initAnimation();
        }

        return this;
    }

    /**
     * 开启动画
     *
     * @return
     */
    public FadeInTextView startFadeInAnimation() {
        if (textAnimation != null) {
            stringBuffer.setLength(0);
            currentIndex = -1;
            textAnimation.start();
        }
        return this;
    }

    /**
     * 停止动画
     *
     * @return
     */
    public FadeInTextView stopFadeInAnimation() {
        if (textAnimation != null) {
            textAnimation.end();
        }
        return this;
    }

    /**
     * 回调接口
     */
    public interface TextAnimationListener {
        void animationFinish();
    }
}

fadeInTextView = (FadeInTextView)findViewById(R.id.fadete);
fadeInTextView.setTextString("自定义view实现字符串逐字显示!");
fadeInTextView.startFadeInAnimation();

view边框控制:https://blog.csdn.net/meixi_android/article/details/77374362

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值