如下图,角标在移动设备中是比较常见的ui元素。各种“最新”、“vip”、“最热”之类的层出不穷。

71130773_1.jpg

在展现上最简单的做法是让ui同学ps一张角标图片输入“最新”、“vip”、“最热”等盖在要特别醒目提醒的控件上面即可。当然偷懒是没有一劳永逸的做法的,图片实现带文字的角标在当下android设备如此繁荣的情形下,码工们必然会为千奇百怪的适配而劳碌成大牛的,如果频繁更换图片中的文字ui设计师也会烦滴。

下文探讨第一种角标的代码实现方式,其他三种还有比较少见的右下角、左下角的角标也可以照着做了。

   把第一种角标71130773_2.jpg直观化卸妆,那么她是这样的

       71130773_3.png

而这个图形我们可以看作是一个小长方形旋转某个角度后,底边两点刚好和大长方形左边和顶边链接叠加所成的直角三角形。

在android中TextView、LinearLayout是方形的控件。那么,如果我们用TextView替代小长方形、LinearLayout替代大长方形,在TextView靠顶部左对齐的情况下,由下图看到这个几何图形可从A->B->C变换而成。

71130773_4.png

最终的图形那么是

71130773_5.png

其中点d坐标即是TextView的位移点,而∠bah则是TextView反方向旋转的角度。

剩下的就是中学几何计算了。忘了吧!我们复习下要用到的公式:

sinA=对边/斜边

cosA=邻边/斜边

A角角度=arcsinA/π*180°

勾股定理 c^2=a^2+b^2

好了,这几个公式够我们用了。

根据UI同学的设计图,那么eb、ea两三角边是可以量出来滴(需要注意的是eb不一定=ea)。

通过垂直三角形、长方形的各种垂直、平衡关系

可得∠bah=∠ebf=∠deg=∠gad

ab=√(eb^2+ab^2)

ef=sin(∠ebf)*eb

dg=sin(∠gad)*da=sin(∠ebf)*ef

ga=cos(∠gad)*da=cos(∠ebf)*ef

eg=ea-ga

到这里就是怎么在代码中对TextView做移动和旋转动作了。由于多次尝试直接对Canvas做移动旋转失败,所以我采用Animation来完成这一系列动作。下面是实现控件的代码。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95package com.droidwolf.superscript;

import android.content.Context;

import android.graphics.Matrix;

import android.util.AttributeSet;

import android.util.DisplayMetrics;

import android.util.TypedValue;

import android.view.View;

import android.view.animation.Animation;

import android.view.animation.Transformation;

import android.widget.TextView;

public class SuperscriptViewextends TextView {

private float mDegress,mX,mY;

private int mHeight,mWidth;

public SuperscriptView(Context context) {

super(context);

init(context,null);

}

public SuperscriptView(Context context, AttributeSet attrs) {

super(context, attrs);

init(context, attrs);

}

public SuperscriptView(Context context, AttributeSet attrs,int defStyle) {

super(context, attrs, defStyle);

init(context, attrs);

}

@Override

public void setVisibility(int visibility) {

setAnimation(visibility == View.VISIBLE? mAnimation:null);

super.setVisibility(visibility);

}

private void init(Context context, AttributeSet attrs) {

DisplayMetrics dm = getResources().getDisplayMetrics();

int topEdge = Math.round(TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP,41.333f, dm));

int  leftEdge= Math.round(TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP,41.333f, dm));

calc(leftEdge, topEdge);

mAnimation.setFillBefore(true);

mAnimation.setFillAfter(true);

mAnimation.setFillEnabled(true);

startAnimation(mAnimation);

}

@Override

protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {

if (mHeight <1 || mWidth <1) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}else {

setMeasuredDimension(mWidth, mHeight);

}

}

@Override

protected void onLayout(boolean changed,int left,int top,int right,int bottom) {

super.onLayout(changed, left, top, right, bottom);

int vi= getVisibility();

setAnimation(null);

setVisibility(vi);

}

private void calc(int leftEdge,int topEdge) {

final double ab = Math.sqrt(Math.pow(topEdge, 2d)+ Math.pow(leftEdge, 2d));

final double sinB = leftEdge / ab;

mDegress = -(float) Math.toDegrees(Math.asin(sinB));

// ef=da=sin(∠ebf)*eb

mHeight = Math.round((float) (sinB * topEdge));

// de=sin(∠ead)*ea=sin(∠ebf)*ea

final double de = sinB * leftEdge;

// dg=cos(∠ead)*de=cos(∠ebf)*de

mX = -(float) ((topEdge / ab) * de);

// eg==sin(∠edg)*de=sin(∠ebf)*de

mY = (float) (sinB * de);

mWidth = Math.round((float) ab);

}

private Animation mAnimation =new Animation() {

protected void applyTransformation(float interpolatedTime,Transformation t) {

if (mHeight <1 || mWidth <1) {

return;

}

Matrix tran = t.getMatrix();

tran.setTranslate(mX, mY);

tran.postRotate(mDegress, mX, mY);

}

};

}

实现demo。我还实现了第一张图的另外三种角标到一个控件,请移步到我的bitbucket。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐