长方形
<?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