17 | * 贝塞尔动画
18 | * 参考:http://www.jcodecraeer.com/a/anzhuokaifa/2017/0105/6936.html
19 | * http://blog.csdn.net/z82367825/article/details/51599245
20 | */
21 |
22 | public class BezierAnimView extends View {
23 |
24 | private Paint mPaint;
25 | private int mHeight;
26 | private int mWidth;
27 | private Path mPath;
28 | private int mColor1;
29 | private int mColor2;
30 | private int mRadiu;
31 | //Y轴偏移量
32 | private int mYOffset;
33 | private ValueAnimator mValueAnimator;
34 | private int Y_OFFSET = 10;
35 |
36 | public BezierAnimView(Context context) {
37 | this(context, null);
38 | }
39 |
40 | public BezierAnimView(Context context, @Nullable AttributeSet attrs) {
41 | this(context, attrs, 0);
42 | }
43 |
44 | public BezierAnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
45 | super(context, attrs, defStyleAttr);
46 | init(context);
47 | }
48 |
49 | private void init(Context context) {
50 | mPaint = new Paint();
51 | mColor1 = context.getResources().getColor(R.color.my_color);
52 | mColor2 = context.getResources().getColor(R.color.my_color2);
53 | mPaint.setAntiAlias(true);
54 | mPaint.setDither(true);
55 | mPaint.setStyle(Paint.Style.FILL);
56 |
57 | mPath = new Path();
58 |
59 | mRadiu = 60;
60 | }
61 |
62 | // TODO: 17/4/1 QQ未读粘脸效果
63 |
64 |
65 | @Override
66 | protected void onDraw(Canvas canvas) {
67 | super.onDraw(canvas);
68 | mPath.reset();
69 | mPath.moveTo(0, mHeight / 2);
70 | mPath.lineTo(mWidth, mHeight / 2);
71 | mPath.lineTo(mWidth, mHeight);
72 | mPath.lineTo(0, mHeight);
73 | mPath.close();
74 | //画正方形
75 | mPaint.setColor(mColor1);
76 | canvas.drawPath(mPath, mPaint);
77 |
78 | //画水滴
79 | mPaint.setColor(mColor2);
80 | canvas.drawCircle(mWidth / 2, mHeight * 3 / 5 + mRadiu * 2 - mYOffset, mRadiu, mPaint);
81 | }
82 |
83 | @Override
84 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
85 | super.onSizeChanged(w, h, oldw, oldh);
86 | mWidth = w;
87 | mHeight = h;
88 |
89 | mValueAnimator = ValueAnimator.ofInt(0, mHeight / 2);
90 | mValueAnimator.setDuration(2000);
91 | mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
92 | @Override
93 | public void onAnimationUpdate(ValueAnimator animation) {
94 | mYOffset = (int) animation.getAnimatedValue();
95 | postInvalidate();
96 | }
97 | });
98 |
99 | }
100 |
101 | public void start() {
102 | mValueAnimator.start();
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/eleme_button/ElemeBtnActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.eleme_button;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 |
6 | import com.yazhi1992.practice.R;
7 |
8 | public class ElemeBtnActivity extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_eleme_btn);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/flowlayout/FlowLayoutActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.flowlayout;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 |
6 | import com.yazhi1992.practice.R;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | public class FlowLayoutActivity extends AppCompatActivity {
12 |
13 | List
21 | * 仿支付宝支付成功打钩动画
22 | */
23 |
24 | public class HookIcon extends View {
25 |
26 | private Paint mPaint;
27 | private int mCircleRadiu;
28 | private Context mContext;
29 | private int mWidth;
30 | private int mHeight;
31 | private ValueAnimator mValueAnimator;
32 | //已绘制的角度
33 | private int mRealAngle;
34 | //起始旋转角度
35 | private int mBeginAngle;
36 | //圆是否已绘制完成
37 | private boolean mCompletePaint;
38 | private RectF mRect;
39 | //钩的绘制进度 0-1
40 | private float mDrawProgress;
41 | private float mDrawHookProgress;
42 | //钩长短比例为1:2,故小段的绘制时间占总时长的1/3
43 | private float mFirstHookPercent = 0.33f;
44 | private float mSecondHookPercent = 0.66f;
45 | private float mPaintWidth;
46 |
47 | public HookIcon(Context context) {
48 | this(context, null);
49 | }
50 |
51 | public HookIcon(Context context, @Nullable AttributeSet attrs) {
52 | this(context, attrs, 0);
53 | }
54 |
55 | public HookIcon(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
56 | super(context, attrs, defStyleAttr);
57 | mContext = context;
58 | init();
59 | initAnim();
60 | }
61 |
62 | private void init() {
63 | //圆的半径默认20
64 | mCircleRadiu = (int) Utils.dp2px(mContext, 30);
65 |
66 | mPaint = new Paint();
67 | mPaint.setStyle(Paint.Style.STROKE);
68 | mPaint.setAntiAlias(true);
69 |
70 | mPaint.setColor(Color.BLUE);
71 | mPaint.setStrokeCap(Paint.Cap.SQUARE);
72 | mPaintWidth = 7;
73 | mPaint.setStrokeWidth(mPaintWidth);
74 |
75 | //从270度处开始绘制
76 | mBeginAngle = 270;
77 | }
78 |
79 | /**
80 | * 初始化动画
81 | */
82 | private void initAnim() {
83 | mValueAnimator = ValueAnimator.ofFloat(0, 2);
84 | mValueAnimator.setDuration(1000);
85 | mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
86 | @Override
87 | public void onAnimationUpdate(ValueAnimator animation) {
88 | mDrawProgress = (Float) animation.getAnimatedValue();
89 | postInvalidate();
90 | }
91 | });
92 | mValueAnimator.setInterpolator(new LinearInterpolator());
93 | }
94 |
95 | public void startAnim() {
96 | mValueAnimator.start();
97 | }
98 |
99 | @Override
100 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
101 | super.onSizeChanged(w, h, oldw, oldh);
102 | mWidth = w;
103 | mHeight = h;
104 |
105 | mRect = new RectF();
106 | mRect.left = mWidth / 2 - mCircleRadiu;
107 | mRect.top = mHeight / 2 - mCircleRadiu;
108 | mRect.right = mWidth / 2 + mCircleRadiu;
109 | mRect.bottom = mHeight / 2 + mCircleRadiu;
110 | }
111 |
112 | @Override
113 | protected void onDraw(Canvas canvas) {
114 | super.onDraw(canvas);
115 | if (mPaint != null && mRect != null) {
116 | //绘制圆
117 | canvas.save();
118 | if (mDrawProgress > 1) {
119 | //圆已绘制完成
120 | canvas.rotate(360 + mBeginAngle, mWidth / 2, mHeight / 2);
121 | canvas.drawArc(mRect, 0, 360, false, mPaint);
122 | } else {
123 | //根据百分比应绘制计算扇形的弧度
124 | int realAngle = (int) (360 * mDrawProgress);
125 | canvas.rotate(realAngle + mBeginAngle, mWidth / 2, mHeight / 2);
126 | canvas.drawArc(mRect, 360 - realAngle, realAngle, false, mPaint);
127 | }
128 | canvas.restore();
129 | if (mDrawProgress > 1) {
130 | mDrawHookProgress = mDrawProgress - 1;
131 | //绘制钩
132 | Path path = new Path();
133 | //圆心 mWidth/2 ,mHeight/2
134 | //钩的左边起点
135 | float startPointX = (float) (mWidth / 2 - 0.53d * mCircleRadiu);
136 | float startPointY = (float) (mHeight / 2 + 0.05d * mCircleRadiu);
137 | path.moveTo(startPointX, startPointY);
138 | //钩的转折点
139 | //从左起点到转折点 x/y 移动的距离(因为是45度,所以x/y 移动距离相等)
140 | float firstHookMoveDistance = (float) (0.35d * mCircleRadiu);
141 | float secondHookMoveDistance = 2 * firstHookMoveDistance;
142 | if (mDrawHookProgress >= mFirstHookPercent) {
143 | //开始绘制第二段了
144 | path.lineTo(startPointX + firstHookMoveDistance, startPointY + firstHookMoveDistance);
145 | //转折点到右终点的移动距离
146 | float secondPercent = (mDrawHookProgress - mFirstHookPercent) / (1 - mFirstHookPercent);
147 | path.lineTo(startPointX + firstHookMoveDistance + secondHookMoveDistance * secondPercent
148 | , startPointY + firstHookMoveDistance - secondHookMoveDistance * secondPercent);
149 | //绘制钩第二段
150 | canvas.drawPath(path, mPaint);
151 | } else {
152 | //还在绘制钩的第一段
153 | path.lineTo(startPointX + firstHookMoveDistance * (mDrawHookProgress / mFirstHookPercent), startPointY + firstHookMoveDistance * (mDrawHookProgress / mFirstHookPercent));
154 | canvas.drawPath(path, mPaint);
155 | }
156 | }
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/hook_icon/HookIconActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.hook_icon;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.yazhi1992.practice.R;
8 |
9 | /**
10 | * 仿支付宝支付成功打钩动画
11 | */
12 | public class HookIconActivity extends AppCompatActivity {
13 |
14 | private HookIcon mHookIcon;
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.activity_hook_icon);
20 |
21 | mHookIcon = (HookIcon) findViewById(R.id.hookIcon);
22 |
23 | findViewById(R.id.btnStart).setOnClickListener(new View.OnClickListener() {
24 | @Override
25 | public void onClick(View v) {
26 | mHookIcon.startAnim();
27 | }
28 | });
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/immersion_status_bar/ImmersionActionBarActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.immersion_status_bar;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 |
6 | import com.yazhi1992.practice.R;
7 |
8 |
9 | public class ImmersionActionBarActivity extends AppCompatActivity {
10 |
11 | @Override
12 | protected void onCreate(Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | setContentView(R.layout.activity_immersion_action_bar);
15 |
16 | StatusBarUtils.with(this)
17 | .setIsActionBar(true)
18 | .clearActionBarShadow()
19 | .setDrawable(getResources().getDrawable(R.drawable.shape))
20 | .init();
21 |
22 | getSupportActionBar().setBackgroundDrawable(getResources().getDrawable(R.drawable.shape));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/immersion_status_bar/ImmersionBarActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.immersion_status_bar;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 |
6 | import com.yazhi1992.practice.R;
7 |
8 | public class ImmersionBarActivity extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 |
14 | setContentView(R.layout.activity_immersion_bar);
15 |
16 | StatusBarUtils.with(this)
17 | .setColor(getResources().getColor(R.color.blue))
18 | // .setDrawable(getResources().getDrawable(R.drawable.shape))
19 | .init();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/immersion_status_bar/ImmersionImageActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.immersion_status_bar;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 |
6 | import com.yazhi1992.practice.R;
7 |
8 | /**
9 | * 沉浸式图片
10 | */
11 | public class ImmersionImageActivity extends AppCompatActivity {
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_immersion_image);
17 |
18 | StatusBarUtils.with(this)
19 | .init();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/immersion_status_bar/ImmersionNavActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.immersion_status_bar;
2 |
3 | import android.os.Bundle;
4 | import android.support.design.widget.NavigationView;
5 | import android.support.v4.view.GravityCompat;
6 | import android.support.v4.widget.DrawerLayout;
7 | import android.support.v7.app.ActionBarDrawerToggle;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.support.v7.widget.Toolbar;
10 | import android.view.Menu;
11 | import android.view.MenuItem;
12 |
13 | import com.yazhi1992.practice.R;
14 |
15 | public class ImmersionNavActivity extends AppCompatActivity
16 | implements NavigationView.OnNavigationItemSelectedListener {
17 |
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_immersion_nav);
22 |
23 | StatusBarUtils.with(this)
24 | .setDrawerLayoutContentId(true, R.id.rl_content)
25 | .setColor(getResources().getColor(R.color.blue))
26 | .init();
27 |
28 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
29 |
30 | setSupportActionBar(toolbar);
31 |
32 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
33 | ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
34 | this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
35 | drawer.setDrawerListener(toggle);
36 | toggle.syncState();
37 |
38 | NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
39 | navigationView.setNavigationItemSelectedListener(this);
40 | }
41 |
42 | @Override
43 | public void onBackPressed() {
44 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
45 | if (drawer.isDrawerOpen(GravityCompat.START)) {
46 | drawer.closeDrawer(GravityCompat.START);
47 | } else {
48 | super.onBackPressed();
49 | }
50 | }
51 |
52 | @Override
53 | public boolean onCreateOptionsMenu(Menu menu) {
54 | // Inflate the menu; this adds items to the action bar if it is present.
55 | getMenuInflater().inflate(R.menu.immersion_nav, menu);
56 | return true;
57 | }
58 |
59 | @Override
60 | public boolean onOptionsItemSelected(MenuItem item) {
61 | // Handle action bar item clicks here. The action bar will
62 | // automatically handle clicks on the Home/Up button, so long
63 | // as you specify a parent activity in AndroidManifest.xml.
64 | int id = item.getItemId();
65 |
66 | //noinspection SimplifiableIfStatement
67 | if (id == R.id.action_settings) {
68 | return true;
69 | }
70 |
71 | return super.onOptionsItemSelected(item);
72 | }
73 |
74 | @SuppressWarnings("StatementWithEmptyBody")
75 | @Override
76 | public boolean onNavigationItemSelected(MenuItem item) {
77 | // Handle navigation view item clicks here.
78 | int id = item.getItemId();
79 |
80 | if (id == R.id.nav_camera) {
81 | // Handle the camera action
82 | } else if (id == R.id.nav_gallery) {
83 |
84 | } else if (id == R.id.nav_slideshow) {
85 |
86 | } else if (id == R.id.nav_manage) {
87 |
88 | } else if (id == R.id.nav_share) {
89 |
90 | } else if (id == R.id.nav_send) {
91 |
92 | }
93 |
94 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
95 | drawer.closeDrawer(GravityCompat.START);
96 | return true;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/immersion_status_bar/MainImmersionActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.immersion_status_bar;
2 |
3 | import android.content.Intent;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.os.Bundle;
6 | import android.view.View;
7 |
8 | import com.yazhi1992.practice.R;
9 |
10 |
11 | public class MainImmersionActivity extends AppCompatActivity implements View.OnClickListener {
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 |
17 | setContentView(R.layout.activity_immersion_status_bar);
18 |
19 | findViewById(R.id.immersion_img_btn).setOnClickListener(this);
20 | findViewById(R.id.immersion_normal_btn).setOnClickListener(this);
21 | findViewById(R.id.immersion_nav_btn).setOnClickListener(this);
22 | findViewById(R.id.immersion_actionbar_btn).setOnClickListener(this);
23 | }
24 |
25 | @Override
26 | public void onClick(View v) {
27 | switch (v.getId()) {
28 | case R.id.immersion_img_btn:
29 | startActivity(new Intent(this, ImmersionImageActivity.class));
30 | break;
31 | case R.id.immersion_normal_btn:
32 | startActivity(new Intent(this, ImmersionBarActivity.class));
33 | break;
34 | case R.id.immersion_nav_btn:
35 | startActivity(new Intent(this, ImmersionNavActivity.class));
36 | break;
37 | case R.id.immersion_actionbar_btn:
38 | startActivity(new Intent(this, ImmersionActionBarActivity.class));
39 | break;
40 | default:
41 | break;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/immersion_status_bar/StatusBarUtils.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.immersion_status_bar;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.Color;
6 | import android.graphics.drawable.Drawable;
7 | import android.os.Build;
8 | import android.support.v4.widget.DrawerLayout;
9 | import android.support.v7.app.ActionBar;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.util.Log;
12 | import android.util.TypedValue;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.view.Window;
16 | import android.view.WindowManager;
17 | import android.widget.LinearLayout;
18 |
19 | /**
20 | * Created by zengyazhi on 2017/8/17.
21 | */
22 |
23 | public class StatusBarUtils {
24 | private Activity mActivity;
25 | //状态栏颜色
26 | private int mColor = -1;
27 | //状态栏drawble
28 | private Drawable mDrawable;
29 | //是否是最外层布局是 DrawerLayout 的侧滑菜单
30 | private boolean mIsDrawerLayout;
31 | //是否包含 ActionBar
32 | private boolean mIsActionBar;
33 | //侧滑菜单页面的内容视图
34 | private int mContentResourseIdInDrawer;
35 |
36 | public StatusBarUtils(Activity activity) {
37 | mActivity = activity;
38 | }
39 |
40 | public static StatusBarUtils with(Activity activity) {
41 | return new StatusBarUtils(activity);
42 | }
43 |
44 | public int getColor() {
45 | return mColor;
46 | }
47 |
48 | public StatusBarUtils setColor(int color) {
49 | mColor = color;
50 | return this;
51 | }
52 |
53 | public Drawable getDrawable() {
54 | return mDrawable;
55 | }
56 |
57 | public StatusBarUtils setDrawable(Drawable drawable) {
58 | mDrawable = drawable;
59 | return this;
60 | }
61 |
62 | public boolean isDrawerLayout() {
63 | return mIsDrawerLayout;
64 | }
65 |
66 | public boolean isActionBar() {
67 | return mIsActionBar;
68 | }
69 |
70 | public StatusBarUtils setIsActionBar(boolean actionBar) {
71 | mIsActionBar = actionBar;
72 | return this;
73 | }
74 |
75 | /**
76 | * 是否是最外层布局为 DrawerLayout 的侧滑菜单
77 | *
78 | * @param drawerLayout 是否最外层布局为 DrawerLayout
79 | * @param contentId 内容视图的 id
80 | * @return
81 | */
82 | public StatusBarUtils setDrawerLayoutContentId(boolean drawerLayout, int contentId) {
83 | mIsDrawerLayout = drawerLayout;
84 | mContentResourseIdInDrawer = contentId;
85 | return this;
86 | }
87 |
88 | public void init() {
89 | fullScreen(mActivity);
90 | if (mColor != -1) {
91 | //设置了状态栏颜色
92 | addStatusViewWithColor(mActivity, mColor);
93 | }
94 | if (mDrawable != null) {
95 | //设置了状态栏 drawble,例如渐变色
96 | addStatusViewWithDrawble(mActivity, mDrawable);
97 | }
98 | if (isDrawerLayout()) {
99 | //未设置 fitsSystemWindows 且是侧滑菜单,需要设置 fitsSystemWindows 以解决 4.4 上侧滑菜单上方白条问题
100 | fitsSystemWindows(mActivity);
101 | }
102 | if (isActionBar()) {
103 | //要增加内容视图的 paddingTop,否则内容被 ActionBar 遮盖
104 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
105 | ViewGroup rootView = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content);
106 | rootView.setPadding(0, getStatusBarHeight(mActivity) + getActionBarHeight(mActivity), 0, 0);
107 | }
108 | }
109 | }
110 |
111 | /**
112 | * 去除 ActionBar 阴影
113 | */
114 | public StatusBarUtils clearActionBarShadow() {
115 | if (Build.VERSION.SDK_INT >= 21) {
116 | ActionBar supportActionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
117 | if (supportActionBar != null) {
118 | supportActionBar.setElevation(0);
119 | }
120 | }
121 | return this;
122 | }
123 |
124 | /**
125 | * 设置页面最外层布局 FitsSystemWindows 属性
126 | *
127 | * @param activity
128 | */
129 | private void fitsSystemWindows(Activity activity) {
130 | ViewGroup contentFrameLayout = (ViewGroup) activity.findViewById(android.R.id.content);
131 | View parentView = contentFrameLayout.getChildAt(0);
132 | if (parentView != null && Build.VERSION.SDK_INT >= 14) {
133 | parentView.setFitsSystemWindows(true);
134 | //布局预留状态栏高度的 padding
135 | if (parentView instanceof DrawerLayout) {
136 | DrawerLayout drawer = (DrawerLayout) parentView;
137 | //将主页面顶部延伸至status bar;虽默认为false,但经测试,DrawerLayout需显示设置
138 | drawer.setClipToPadding(false);
139 | }
140 | }
141 | }
142 |
143 | /**
144 | * 利用反射获取状态栏高度
145 | *
146 | * @return
147 | */
148 | public static int getStatusBarHeight(Activity activity) {
149 | int result = 0;
150 | //获取状态栏高度的资源id
151 | int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
152 | if (resourceId > 0) {
153 | result = activity.getResources().getDimensionPixelSize(resourceId);
154 | }
155 | Log.e("getStatusBarHeight", result + "");
156 | return result;
157 | }
158 |
159 | /**
160 | * 获得 ActionBar 的高度
161 | *
162 | * @param context
163 | * @return
164 | */
165 | public static int getActionBarHeight(Context context) {
166 | int result = 0;
167 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
168 | TypedValue tv = new TypedValue();
169 | context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
170 | result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics());
171 | }
172 | return result;
173 | }
174 |
175 | /**
176 | * 添加状态栏占位视图
177 | *
178 | * @param activity
179 | */
180 | private void addStatusViewWithColor(Activity activity, int color) {
181 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
182 | if (isDrawerLayout()) {
183 | //要在内容布局增加状态栏,否则会盖在侧滑菜单上
184 | ViewGroup rootView = (ViewGroup) activity.findViewById(android.R.id.content);
185 | //DrawerLayout 则需要在第一个子视图即内容试图中添加padding
186 | View parentView = rootView.getChildAt(0);
187 | LinearLayout linearLayout = new LinearLayout(activity);
188 | linearLayout.setOrientation(LinearLayout.VERTICAL);
189 | View statusBarView = new View(activity);
190 | ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
191 | getStatusBarHeight(activity));
192 | statusBarView.setBackgroundColor(color);
193 | //添加占位状态栏到线性布局中
194 | linearLayout.addView(statusBarView, lp);
195 | //侧滑菜单
196 | DrawerLayout drawer = (DrawerLayout) parentView;
197 | //内容视图
198 | View content = activity.findViewById(mContentResourseIdInDrawer);
199 | //将内容视图从 DrawerLayout 中移除
200 | drawer.removeView(content);
201 | //添加内容视图
202 | linearLayout.addView(content, content.getLayoutParams());
203 | //将带有占位状态栏的新的内容视图设置给 DrawerLayout
204 | drawer.addView(linearLayout, 0);
205 | } else {
206 | //设置 paddingTop
207 | ViewGroup rootView = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content);
208 | rootView.setPadding(0, getStatusBarHeight(mActivity), 0, 0);
209 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
210 | //直接设置状态栏颜色
211 | activity.getWindow().setStatusBarColor(color);
212 | } else {
213 | //增加占位状态栏
214 | ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView();
215 | View statusBarView = new View(activity);
216 | ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
217 | getStatusBarHeight(activity));
218 | statusBarView.setBackgroundColor(color);
219 | decorView.addView(statusBarView, lp);
220 | }
221 | }
222 | }
223 | }
224 |
225 | /**
226 | * 添加状态栏占位视图
227 | *
228 | * @param activity
229 | */
230 | private void addStatusViewWithDrawble(Activity activity, Drawable drawable) {
231 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
232 | //占位状态栏
233 | View statusBarView = new View(activity);
234 | ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
235 | getStatusBarHeight(activity));
236 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
237 | statusBarView.setBackground(drawable);
238 | } else {
239 | statusBarView.setBackgroundDrawable(drawable);
240 | }
241 | if (isDrawerLayout()) {
242 | //要在内容布局增加状态栏,否则会盖在侧滑菜单上
243 | ViewGroup rootView = (ViewGroup) activity.findViewById(android.R.id.content);
244 | //DrawerLayout 则需要在第一个子视图即内容试图中添加padding
245 | View parentView = rootView.getChildAt(0);
246 | LinearLayout linearLayout = new LinearLayout(activity);
247 | linearLayout.setOrientation(LinearLayout.VERTICAL);
248 | //添加占位状态栏到线性布局中
249 | linearLayout.addView(statusBarView, lp);
250 | //侧滑菜单
251 | DrawerLayout drawer = (DrawerLayout) parentView;
252 | //内容视图
253 | View content = activity.findViewById(mContentResourseIdInDrawer);
254 | //将内容视图从 DrawerLayout 中移除
255 | drawer.removeView(content);
256 | //添加内容视图
257 | linearLayout.addView(content, content.getLayoutParams());
258 | //将带有占位状态栏的新的内容视图设置给 DrawerLayout
259 | drawer.addView(linearLayout, 0);
260 | } else {
261 | //增加占位状态栏,并增加状态栏高度的 paddingTop
262 | ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView();
263 | decorView.addView(statusBarView, lp);
264 | //设置 paddingTop
265 | ViewGroup rootView = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content);
266 | rootView.setPadding(0, getStatusBarHeight(mActivity), 0, 0);
267 | }
268 | }
269 | }
270 |
271 | /**
272 | * 通过设置全屏,设置状态栏透明
273 | *
274 | * @param activity
275 | */
276 | private void fullScreen(Activity activity) {
277 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
278 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
279 | //5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色
280 | Window window = activity.getWindow();
281 | View decorView = window.getDecorView();
282 | //两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间
283 | int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
284 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
285 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
286 | decorView.setSystemUiVisibility(option);
287 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
288 | window.setStatusBarColor(Color.TRANSPARENT);
289 | //导航栏颜色也可以正常设置
290 | // window.setNavigationBarColor(Color.TRANSPARENT);
291 | } else {
292 | Window window = activity.getWindow();
293 | WindowManager.LayoutParams attributes = window.getAttributes();
294 | int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
295 | int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
296 | attributes.flags |= flagTranslucentStatus;
297 | // attributes.flags |= flagTranslucentNavigation;
298 | window.setAttributes(attributes);
299 | }
300 | }
301 | }
302 |
303 | /**
304 | * 通过设置全屏,设置状态栏透明 导航栏黑色
305 | *
306 | * @param activity
307 | */
308 | public static void setStatusTransparent(Activity activity) {
309 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
310 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
311 | Window window = activity.getWindow();
312 |
313 | WindowManager.LayoutParams attributes = window.getAttributes();
314 | int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
315 | int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
316 | // attributes.flags |= flagTranslucentStatus;
317 | attributes.flags |= flagTranslucentNavigation;
318 | window.setAttributes(attributes);
319 |
320 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
321 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
322 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
323 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
324 | window.setStatusBarColor(Color.TRANSPARENT);
325 | window.setNavigationBarColor(Color.TRANSPARENT);
326 | } else {
327 | Window window = activity.getWindow();
328 | WindowManager.LayoutParams attributes = window.getAttributes();
329 | int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
330 | int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
331 | attributes.flags |= flagTranslucentStatus;
332 | attributes.flags |= flagTranslucentNavigation;
333 | window.setAttributes(attributes);
334 | }
335 | }
336 | }
337 | }
338 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/line_chart_view/LineChart.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.line_chart_view;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.graphics.Path;
9 | import android.graphics.PorterDuff;
10 | import android.graphics.PorterDuffXfermode;
11 | import android.graphics.RectF;
12 | import android.graphics.Region;
13 | import android.support.annotation.Nullable;
14 | import android.util.AttributeSet;
15 | import android.util.TypedValue;
16 | import android.view.MotionEvent;
17 | import android.view.View;
18 |
19 | import com.yazhi1992.practice.R;
20 | import com.yazhi1992.practice.utils.Utils;
21 |
22 | import java.math.BigDecimal;
23 | import java.util.ArrayList;
24 | import java.util.HashMap;
25 | import java.util.List;
26 | import java.util.Map;
27 |
28 | /**
29 | * Created by zengyazhi on 17/4/11.
30 | *
31 | * 折线图
32 | * 参考:https://github.com/xiaoyunfei/LineChart
33 | */
34 |
35 | public class LineChart extends View {
36 |
37 | //屏幕宽高
38 | private int mWidth;
39 | private int mHeight;
40 | //坐标轴字体大小
41 | private float mAxisTextSize;
42 | //坐标轴颜色
43 | private int mAxisColor;
44 | //坐标轴文字颜色
45 | private int mAxisTextColor;
46 | //折线颜色
47 | private int mChartColor;
48 | //绘制坐标轴画笔
49 | private Paint mAxisPaint;
50 | //绘制坐标轴文字画笔
51 | private Paint mAxisTextPaint;
52 | //绘制折线画笔
53 | private Paint mChartPaint;
54 | //坐标轴画笔宽度
55 | private int mAxisWidth;
56 | //数值
57 | private List
19 | * 涟漪
20 | */
21 |
22 | public class RippleView extends View {
23 |
24 | //内部圆的半径
25 | private int ORIGINAL_RADIU;
26 | //最大半径
27 | private int MAX_RADIU;
28 | //三个不断散开的圆的半径
29 | private int mRadiu = ORIGINAL_RADIU;
30 | private int mRadiu2 = -1;
31 | private int mRadiu3 = -1;
32 | private Paint mPaint;
33 | //屏幕宽高
34 | private int mHeight;
35 | private int mWidth;
36 | //是否已绘制完成,进入旋转阶段
37 | private Thread mThread;
38 | private int mColor;
39 | private boolean mStartAnim;
40 |
41 | public RippleView(Context context) {
42 | super(context);
43 | init(context);
44 | }
45 |
46 | public RippleView(Context context, @Nullable AttributeSet attrs) {
47 | super(context, attrs);
48 | init(context);
49 | }
50 |
51 | public RippleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
52 | super(context, attrs, defStyleAttr);
53 | init(context);
54 | }
55 |
56 | private void init(Context context) {
57 | //关闭GPU硬件加速
58 | setLayerType(View.LAYER_TYPE_SOFTWARE, null);
59 | mColor = context.getResources().getColor(R.color.my_color);
60 | }
61 |
62 | @Override
63 | protected void onDraw(Canvas canvas) {
64 | super.onDraw(canvas);
65 | if (mPaint != null) {
66 | mPaint.setColor(mColor);
67 | //绘制外部圆
68 | drawCircle(canvas, mRadiu);
69 | drawCircle(canvas, mRadiu2);
70 | drawCircle(canvas, mRadiu3);
71 | //绘制内部白色圆
72 | mPaint.setColor(Color.WHITE);
73 | mPaint.setShader(null);
74 | canvas.drawCircle(mWidth / 2, mHeight / 2, ORIGINAL_RADIU, mPaint);
75 | }
76 | }
77 |
78 | /**
79 | * 绘制圆
80 | * @param canvas
81 | * @param radiu
82 | */
83 | private void drawCircle(Canvas canvas, int radiu) {
84 | if (radiu > ORIGINAL_RADIU && radiu < MAX_RADIU) {
85 | setAlpha(radiu);
86 | canvas.drawCircle(mWidth / 2, mHeight / 2, radiu, mPaint);
87 | }
88 | }
89 |
90 | /**
91 | * 设置内部空白圆圈的半径
92 | * @param width
93 | */
94 | public void setOriginalRadiu(int width) {
95 | ORIGINAL_RADIU = width - 10;
96 | mRadiu = ORIGINAL_RADIU;
97 | postInvalidate();
98 | }
99 |
100 | /**
101 | * 根据半径设置透明度
102 | * @param radiu
103 | */
104 | private void setAlpha(int radiu) {
105 | double v = (radiu - ORIGINAL_RADIU) * 1d / (MAX_RADIU - ORIGINAL_RADIU);
106 | double v1 = (1 - v) * 255;
107 | if (v1 > 255) {
108 | v1 = 255;
109 | }
110 | if (v1 < 0) {
111 | v1 = 0;
112 | }
113 | mPaint.setAlpha((int) v1);
114 | }
115 |
116 | /**
117 | * 开始执行动画
118 | */
119 | public void star() {
120 | mStartAnim = true;
121 | if (mThread == null) {
122 | mThread = new Thread(new Runnable() {
123 | @Override
124 | public void run() {
125 | while (mStartAnim) {
126 | //当最外圈圆到达1/3出时开始绘制第二圈圆
127 | if (mRadiu2 == -1 && mRadiu > ((MAX_RADIU - ORIGINAL_RADIU) / 3)) {
128 | mRadiu2 = mRadiu - ((MAX_RADIU - ORIGINAL_RADIU) / 3);
129 | }
130 | //当最外圈圆到达2/3出时开始绘制第三圈圆
131 | if (mRadiu3 == -1 && mRadiu > ((MAX_RADIU - ORIGINAL_RADIU) / 3)) {
132 | mRadiu3 = mRadiu - 2 * ((MAX_RADIU - ORIGINAL_RADIU) / 3);
133 | }
134 |
135 | //三圈圆到达最大半径时则自动从最小半径开始重新绘制,不断重复
136 | if (mRadiu >= MAX_RADIU) {
137 | mRadiu = ORIGINAL_RADIU;
138 | } else if (mRadiu2 >= MAX_RADIU) {
139 | mRadiu2 = ORIGINAL_RADIU;
140 | } else if (mRadiu3 >= MAX_RADIU) {
141 | mRadiu3 = ORIGINAL_RADIU;
142 | }
143 |
144 | //半径加大,不断外散
145 | if (mRadiu < MAX_RADIU) {
146 | mRadiu++;
147 | }
148 | if (mRadiu2 != -1 && mRadiu2 < MAX_RADIU) {
149 | mRadiu2++;
150 | }
151 | if (mRadiu3 != -1 && mRadiu3 < MAX_RADIU) {
152 | mRadiu3++;
153 | }
154 | postInvalidate();
155 | try {
156 | Thread.sleep(12);
157 | } catch (InterruptedException e) {
158 | e.printStackTrace();
159 | }
160 | }
161 | }
162 | });
163 | mThread.start();
164 | }
165 | }
166 |
167 | /**
168 | * 停止动画
169 | */
170 | public void stop() {
171 | mStartAnim = false;
172 | mThread = null;
173 | mRadiu = ORIGINAL_RADIU;
174 | mRadiu2 = -1;
175 | mRadiu3 = -1;
176 | postInvalidate();
177 | }
178 |
179 | @Override
180 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
181 | super.onSizeChanged(w, h, oldw, oldh);
182 | mWidth = w;
183 | mHeight = h;
184 | mPaint = new Paint();
185 | mPaint.setDither(true);
186 | mPaint.setAntiAlias(true);
187 | mPaint.setStyle(Paint.Style.FILL);
188 | mPaint.setStrokeJoin(Paint.Join.ROUND);
189 | mPaint.setStrokeCap(Paint.Cap.ROUND);
190 | mPaint.setColor(mColor);
191 | MAX_RADIU = mWidth / 2;
192 | postInvalidate();
193 |
194 | ValueAnimator valueAnimator = ValueAnimator.ofInt(0, MAX_RADIU);
195 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
196 | @Override
197 | public void onAnimationUpdate(ValueAnimator animation) {
198 | mRadiu = (int) animation.getAnimatedValue();
199 | if (mRadiu2 == -1 && mRadiu > ((MAX_RADIU - ORIGINAL_RADIU) / 3)) {
200 | mRadiu2 = mRadiu - ((MAX_RADIU - ORIGINAL_RADIU) / 3);
201 | }
202 | }
203 | });
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/rotate_circle/RotateCircleActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.rotate_circle;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.yazhi1992.practice.R;
8 |
9 | public class RotateCircleActivity extends AppCompatActivity {
10 |
11 | private RotateCircleView mView;
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_rotate_circle);
17 |
18 | mView = (RotateCircleView) findViewById(R.id.rotateCircelView);
19 | findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
20 | @Override
21 | public void onClick(View v) {
22 | mView.star();
23 | }
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/rotate_circle/RotateCircleView.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.rotate_circle;
2 |
3 | import android.animation.Animator;
4 | import android.animation.ValueAnimator;
5 | import android.content.Context;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Paint;
9 | import android.graphics.RectF;
10 | import android.graphics.SweepGradient;
11 | import android.support.annotation.Nullable;
12 | import android.util.AttributeSet;
13 | import android.util.TypedValue;
14 | import android.view.View;
15 | import android.view.animation.LinearInterpolator;
16 |
17 | import com.yazhi1992.practice.R;
18 |
19 |
20 | /**
21 | * Created by zengyazhi on 17/3/21.
22 | *
23 | * 旋转圆弧动画
24 | */
25 |
26 | public class RotateCircleView extends View {
27 |
28 | //直径
29 | private int mRadiu = 40;
30 | private RectF mRect;
31 | private Paint mPaint;
32 | private int mHeight;
33 | private int mWidth;
34 | private int mRealAngle;
35 | private SweepGradient mSweepGradient;
36 | //是否已绘制完成,进入旋转阶段
37 | private boolean mCompletePaint;
38 | private int mColor;
39 | private ValueAnimator mValueAnimator;
40 |
41 | public RotateCircleView(Context context) {
42 | this(context, null);
43 | }
44 |
45 | public RotateCircleView(Context context, @Nullable AttributeSet attrs) {
46 | this(context, attrs, 0);
47 | }
48 |
49 | public RotateCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
50 | super(context, attrs, defStyleAttr);
51 | init(context);
52 | }
53 |
54 | private void init(Context context) {
55 | mColor = context.getResources().getColor(R.color.my_color);
56 |
57 | mPaint = new Paint();
58 | mPaint.setDither(true);
59 | mPaint.setAntiAlias(true);
60 | mPaint.setColor(mColor);
61 | mPaint.setStyle(Paint.Style.STROKE);
62 | mPaint.setStrokeJoin(Paint.Join.ROUND);
63 | mPaint.setStrokeCap(Paint.Cap.ROUND);
64 |
65 | mRadiu = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, context.getResources().getDisplayMetrics());
66 |
67 | initAnim();
68 | }
69 |
70 | /**
71 | * 初始化动画
72 | */
73 | private void initAnim() {
74 | mValueAnimator = ValueAnimator.ofInt(0, 360);
75 | mValueAnimator.setDuration(1800);
76 | mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
77 | @Override
78 | public void onAnimationUpdate(ValueAnimator animation) {
79 | mRealAngle = (int) animation.getAnimatedValue();
80 | postInvalidate();
81 | }
82 | });
83 | mValueAnimator.setInterpolator(new LinearInterpolator());
84 | mValueAnimator.addListener(new Animator.AnimatorListener() {
85 | @Override
86 | public void onAnimationStart(Animator animation) {
87 |
88 | }
89 |
90 | @Override
91 | public void onAnimationEnd(Animator animation) {
92 | }
93 |
94 | @Override
95 | public void onAnimationCancel(Animator animation) {
96 |
97 | }
98 |
99 | @Override
100 | public void onAnimationRepeat(Animator animation) {
101 | mCompletePaint = true;
102 | }
103 | });
104 | mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
105 | mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
106 | }
107 |
108 | @Override
109 | protected void onDraw(Canvas canvas) {
110 | super.onDraw(canvas);
111 | if (mPaint != null) {
112 | int paintAngle;
113 | if (mCompletePaint) {
114 | paintAngle = 360;
115 | } else {
116 | paintAngle = mRealAngle;
117 | }
118 | canvas.rotate(mRealAngle, mWidth / 2, mHeight / 2);
119 | mPaint.setShader(mSweepGradient);
120 | mPaint.setStrokeWidth(mRadiu);
121 | mPaint.setStyle(Paint.Style.STROKE);
122 | mPaint.setStrokeCap(Paint.Cap.ROUND);
123 | canvas.drawArc(mRect, 360 - paintAngle, paintAngle, false, mPaint);
124 |
125 | //画被白色盖住的半个头部
126 | if (paintAngle > 2) {
127 | mPaint.setShader(null);
128 | mPaint.setStyle(Paint.Style.FILL);
129 | mPaint.setStrokeCap(Paint.Cap.SQUARE);
130 | mPaint.setStrokeWidth(1);
131 | RectF oval2 = new RectF(mWidth - mRadiu * 3 / 2, mHeight / 2 - mRadiu / 2 - 2
132 | , mWidth - mRadiu / 2, mHeight / 2 + mRadiu / 2 - 2);
133 | canvas.drawArc(oval2, 0, 180, true, mPaint);
134 | }
135 |
136 | }
137 | }
138 |
139 | //开始执行动画
140 | public void star() {
141 | if (mValueAnimator != null) {
142 | if (mValueAnimator.isRunning()) {
143 | mValueAnimator.cancel();
144 | } else {
145 | mCompletePaint = false;
146 | mValueAnimator.start();
147 | }
148 | }
149 | }
150 |
151 | @Override
152 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
153 | super.onSizeChanged(w, h, oldw, oldh);
154 | mWidth = w;
155 | mHeight = h;
156 |
157 | mRect = new RectF();
158 | mRect.left = mRadiu;
159 | mRect.top = mRadiu;
160 | mRect.right = mWidth - mRadiu;
161 | mRect.bottom = mHeight - mRadiu;
162 |
163 | int[] ints = new int[]{Color.WHITE, mColor};
164 | mSweepGradient = new SweepGradient(mWidth / 2, mHeight / 2, ints, null);
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/streak_progress_bar/StreakProgressbar.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.streak_progress_bar;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Path;
8 | import android.graphics.PixelFormat;
9 | import android.graphics.RectF;
10 | import android.util.AttributeSet;
11 | import android.util.Log;
12 | import android.view.SurfaceHolder;
13 | import android.view.SurfaceView;
14 |
15 | /**
16 | * Created by zengyazhi on 17/2/13.
17 | * 条纹进度条
18 | */
19 |
20 | public class StreakProgressbar extends SurfaceView implements SurfaceHolder.Callback{
21 |
22 | private Canvas canvas;
23 | // 条纹宽度
24 | private int hig = 35;
25 | private int a = 0;
26 | private SurfaceHolder surfaceHolder;
27 | private boolean isThreadRunning = true;
28 | private Thread Loadingthread = null;
29 |
30 | private void initview(Context context) {
31 | context = context;
32 | setZOrderOnTop(true);
33 | surfaceHolder = this.getHolder();
34 | surfaceHolder.setFormat(PixelFormat.TRANSPARENT);
35 | surfaceHolder.addCallback(this);
36 | }
37 |
38 | public StreakProgressbar(Context context) {
39 | super(context);
40 | initview(context);
41 | }
42 |
43 | public StreakProgressbar(Context context, AttributeSet attrs) {
44 | super(context, attrs);
45 | initview(context);
46 | }
47 |
48 | public StreakProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {
49 | super(context, attrs, defStyleAttr);
50 | initview(context);
51 | }
52 |
53 | @Override
54 | public void surfaceCreated(SurfaceHolder holder) {
55 |
56 | }
57 |
58 | @Override
59 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
60 |
61 | }
62 |
63 | @Override
64 | public void surfaceDestroyed(SurfaceHolder holder) {
65 |
66 | }
67 |
68 | // 开启动画线程
69 | public void start2() {
70 | isThreadRunning = true;
71 | Loadingthread = new Thread() {
72 | @Override
73 | public void run() {
74 | while (isThreadRunning) {
75 | try {
76 | if (surfaceHolder != null) {
77 | canvas = surfaceHolder.lockCanvas();
78 | if (canvas != null) {
79 | drawView();
80 | surfaceHolder.unlockCanvasAndPost(canvas);
81 | }
82 | // 动画执行间隔,即滚动速度
83 | Thread.sleep(100);
84 | a++;
85 | }
86 | } catch (InterruptedException e) {
87 | Thread.currentThread().interrupt();
88 | Log.d("InstallView", "InterruptedException");
89 | }
90 | }
91 | }
92 | };
93 | Loadingthread.start();
94 | }
95 |
96 | // 绘制动画
97 | private void drawView() {
98 | final Paint paint_green = generatePaint(Color.parseColor("#F1C2C1"),
99 | Paint.Style.FILL, 1);
100 | final Paint paint_red = generatePaint(Color.parseColor("#ffffff"),
101 | Paint.Style.FILL, 1);
102 | canvas.clipRect(new RectF(0, 0, getWidth(), 100));
103 | int i;
104 | for (i = 0; i < getWidth() + 100; i = i + hig * 2) {
105 | // 画出第一个粉色梯形
106 | Path path = new Path();
107 | path.moveTo(i, 0);
108 | path.lineTo(i + hig, 0);
109 | path.lineTo(-60 + i, getHeight());
110 | path.lineTo(-(60 + hig) + i, getHeight());
111 | // 第二个白色梯形
112 | Path path2 = new Path();
113 | path2.moveTo(i + hig, 0);
114 | path2.lineTo(i + hig * 2, 0);
115 | path2.lineTo(-60 + i + hig, getHeight());
116 | path2.lineTo(-(60 + hig) + i + hig, getHeight());
117 | // 死循环来控制梯形交错显示
118 | if (a % 2 == 0) {
119 | canvas.drawPath(path, paint_green);
120 | canvas.drawPath(path2, paint_red);
121 | } else {
122 | canvas.drawPath(path, paint_red);
123 | canvas.drawPath(path2, paint_green);
124 | }
125 | }
126 | }
127 |
128 | private Paint generatePaint(int color, Paint.Style style, int width) {
129 | Paint paint = new Paint();
130 | paint.setColor(color);
131 | paint.setStyle(style);
132 | paint.setAntiAlias(true);
133 | paint.setStrokeWidth(width);
134 | return paint;
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/swipelayout/SideMenuLayout.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.swipelayout;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.Nullable;
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 | import android.view.VelocityTracker;
8 | import android.view.View;
9 | import android.view.ViewConfiguration;
10 | import android.widget.LinearLayout;
11 | import android.widget.Scroller;
12 |
13 | public class SideMenuLayout extends LinearLayout {
14 |
15 | private View viewContent;
16 | private View viewMenu;
17 | private int menuWidth;
18 |
19 | private Scroller mScroller;//用于滑动
20 | private VelocityTracker mVelocityTracker; //用于侦测速度的
21 | //开始位置
22 | private float xStart;
23 | private float yStart;
24 | //坐标位置
25 | private float xMove;
26 | private float yMove;
27 | //记录上次坐标位置
28 | private float xLast;
29 |
30 | private int touchSlop;
31 |
32 | public SideMenuLayout(Context context) {
33 | this(context, null);
34 | }
35 |
36 | public SideMenuLayout(Context context, @Nullable AttributeSet attrs) {
37 | super(context, attrs);
38 | //设置水平显示,初始化Scroller
39 | setOrientation(HORIZONTAL);
40 | mScroller = new Scroller(getContext());
41 | mVelocityTracker = VelocityTracker.obtain();
42 | touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
43 | }
44 |
45 | @Override
46 | protected void onFinishInflate() {
47 | super.onFinishInflate();
48 | //初始化两个View
49 | if (getChildCount() != 2) {
50 | throw new IllegalArgumentException("子view的数量必须为2个");
51 | }
52 | viewContent = getChildAt(0);
53 | viewMenu = getChildAt(1);
54 | }
55 |
56 | //设置两个子View的位置
57 | @Override
58 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
59 | super.onLayout(changed, l, t, r, b);
60 | //设置内容的位置
61 | //设置菜单的位置
62 | menuWidth = viewMenu.getMeasuredWidth();
63 | viewContent.layout(0, 0, r, b - t);
64 | viewMenu.layout(r - l, 0, r - l + menuWidth, b - t);
65 | }
66 |
67 | // @Override
68 | // protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
69 | // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
70 | // int width = MeasureSpec.getSize(widthMeasureSpec);
71 | // int widthMode = MeasureSpec.getMode(widthMeasureSpec);
72 | // int height = MeasureSpec.getSize(heightMeasureSpec);
73 | // int heightMode = MeasureSpec.getMode(heightMeasureSpec);
74 | //
75 | // WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
76 | // int setWidth = windowManager.getDefaultDisplay().getWidth();
77 | // int setHeight = windowManager.getDefaultDisplay().getHeight();
78 | //
79 | // if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
80 | // setMeasuredDimension(setWidth, setHeight);
81 | // } else if (widthMode == MeasureSpec.AT_MOST) {
82 | // setMeasuredDimension(setWidth, height);
83 | // } else if (heightMode == MeasureSpec.AT_MOST) {
84 | // setMeasuredDimension(width, setHeight);
85 | // }
86 | // }
87 |
88 |
89 | // @Override
90 | // protected void onSizeChanged(int w, int h, int oldw, int oldh) {
91 | // super.onSizeChanged(w, h, oldw, oldh);
92 | // menuWidth = viewMenu.getWidth();
93 | // }
94 |
95 | @Override
96 | public boolean onInterceptTouchEvent(MotionEvent ev) {
97 | boolean intercept = false;
98 | xMove = ev.getRawX();
99 | yMove = ev.getRawY();
100 | switch (ev.getAction()) {
101 | case MotionEvent.ACTION_DOWN:
102 | //记录点下的位置
103 | if (!mScroller.isFinished()) {
104 | mScroller.abortAnimation();
105 | }
106 | xStart = xMove;
107 | yStart = yMove;
108 | xLast = xMove;
109 | break;
110 | case MotionEvent.ACTION_MOVE:
111 | //当前位置与下,x,y位置比较
112 | float xDistance = Math.abs(xMove - xStart);
113 | float yDistance = Math.abs(yMove - yStart);
114 | //横向滑动大于纵向,触发条目的滑动,否则,交给子View去处理
115 | if (xDistance > yDistance && xDistance > touchSlop) {
116 | requestDisallowInterceptTouchEvent(true);
117 | intercept = true;
118 | } else {
119 | requestDisallowInterceptTouchEvent(false);
120 | intercept = false;
121 | }
122 |
123 | }
124 | return intercept;
125 | }
126 |
127 | @Override
128 | public boolean onTouchEvent(MotionEvent event) {
129 | mVelocityTracker.addMovement(event);
130 | xMove = event.getRawX();
131 | //处理横向滑动
132 | switch (event.getAction()) {
133 | case MotionEvent.ACTION_DOWN:
134 | return true;
135 | case MotionEvent.ACTION_MOVE:
136 | float viewX = -getScrollX();
137 | float viewToX = viewX + xMove - xLast;
138 | int viewToXDec = (int) (Math.min(Math.max(viewToX, -menuWidth), 0));
139 | scrollTo(-viewToXDec, 0);
140 | xLast = xMove;
141 | //滑动时新坐标
142 | break;
143 | case MotionEvent.ACTION_UP:
144 | //手指抬起时,根据目前位置判断如何滚动
145 | mVelocityTracker.computeCurrentVelocity(1000);
146 | float xVelocity = mVelocityTracker.getXVelocity();
147 | //先根据速度,当速度很快时根据速度方向判断收起还是展开,当速度小时,根据位置判断收起还是展开
148 | if (Math.abs(xVelocity) >= 50) {
149 | if (xVelocity > 0) {
150 | close();
151 | } else {
152 | open();
153 | }
154 | } else {
155 | float viewUpX = getScrollX();
156 | if (viewUpX > 0 && viewUpX < menuWidth / 2) {
157 | //隐藏菜单
158 | close();
159 | } else if (viewUpX >= menuWidth / 2 && viewUpX < menuWidth) {
160 | //全部展示菜单
161 | open();
162 | }
163 | }
164 | break;
165 | }
166 | return super.onTouchEvent(event);
167 | }
168 |
169 | //获取当前是否是打开的
170 | public boolean isOpen() {
171 | boolean isOpen = getScrollX() > 0;
172 | return isOpen;
173 | }
174 |
175 | //全部打开
176 | public void open() {
177 | smoothScrollTo(menuWidth);
178 | }
179 |
180 | //全部关闭
181 | public void close() {
182 | smoothScrollTo(0);
183 | }
184 |
185 | private void smoothScrollTo(int destX) {
186 | int scrollX = getScrollX();
187 | int deltaX = destX - scrollX;;
188 | mScroller.startScroll(scrollX, getScrollY(), deltaX, 0, 500);
189 | invalidate();
190 | }
191 |
192 | @Override
193 | public void computeScroll() {
194 | if (mScroller.computeScrollOffset()) {
195 | scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
196 | postInvalidate();
197 | }
198 | }
199 |
200 | }
201 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/swipelayout/SwipeLayout.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.swipelayout;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.util.Log;
6 | import android.view.MotionEvent;
7 | import android.view.VelocityTracker;
8 | import android.view.View;
9 | import android.view.ViewConfiguration;
10 | import android.view.ViewGroup;
11 | import android.widget.Scroller;
12 |
13 | /**
14 | * Created by zengyazhi on 2017/12/15.
15 | */
16 |
17 | public class SwipeLayout extends ViewGroup {
18 |
19 | private View mContentView;
20 | private View mMenuLayout;
21 | //默认横向
22 | private int mGravity;
23 | //用于抬手时平滑滚动,也可以用animator实现
24 | private Scroller mScroller;
25 | //侦测滑动速度
26 | private VelocityTracker mVelocityTracker;
27 | private float mTouchX;
28 | private int mMenuWidth;
29 | private int mMoveDistance;
30 | private float mStartX;
31 | private int mScaledTouchSlop;
32 |
33 | public SwipeLayout(Context context) {
34 | super(context);
35 | }
36 |
37 | public SwipeLayout(Context context, AttributeSet attrs) {
38 | super(context, attrs);
39 | mScroller = new Scroller(context);
40 | mVelocityTracker = VelocityTracker.obtain();
41 | mScaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
42 | }
43 |
44 | @Override
45 | protected void onFinishInflate() {
46 | super.onFinishInflate();
47 | mContentView = getChildAt(0);
48 | mMenuLayout = getChildAt(1);
49 | }
50 |
51 | @Override
52 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
53 | mMenuWidth = mMenuLayout.getMeasuredWidth();
54 | mContentView.layout(0, 0, r, b);
55 | mMenuLayout.layout(r - l, 0, r - l + mMenuWidth, b);
56 | }
57 |
58 | @Override
59 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
60 | int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
61 | int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
62 | int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
63 | int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
64 |
65 | int width = 0;
66 | int height = 0;
67 |
68 | for (int i = 0; i < getChildCount(); i++) {
69 | View child = getChildAt(i);
70 | measureChild(child, widthMeasureSpec, heightMeasureSpec);
71 | int measuredWidth = child.getMeasuredWidth();
72 | int measuredHeight = child.getMeasuredHeight();
73 | width += measuredWidth;
74 | height = Math.max(height, measuredHeight);
75 | }
76 |
77 | //测量完后报告最终计算的宽高
78 | setMeasuredDimension(
79 | modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(),
80 | modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()//
81 | );
82 | }
83 |
84 | @Override
85 | public boolean onInterceptTouchEvent(MotionEvent ev) {
86 | switch (ev.getAction()) {
87 | case MotionEvent.ACTION_DOWN:
88 | mStartX = ev.getX();
89 | mTouchX = ev.getX() + mMoveDistance;
90 | break;
91 | case MotionEvent.ACTION_MOVE:
92 | float x = ev.getX();
93 | if (Math.abs(mStartX - x) > mScaledTouchSlop) {
94 | //判断为左右滑动,拦截交由 onTouchEvent 处理侧滑逻辑
95 | return true;
96 | } else {
97 | return false;
98 | }
99 | default:
100 | break;
101 | }
102 | return super.onInterceptTouchEvent(ev);
103 | }
104 |
105 | @Override
106 | public boolean onTouchEvent(MotionEvent event) {
107 | mVelocityTracker.addMovement(event);
108 | switch (event.getAction()) {
109 | case MotionEvent.ACTION_MOVE:
110 | float moveX = event.getX() - mTouchX;
111 | Log.e("zyz", moveX + " " + mMenuWidth);
112 | if (moveX < 0) {
113 | //内容栏被左滑
114 | mMoveDistance = (int) -moveX;
115 | //左滑最大距离为菜单宽度
116 | if (mMoveDistance > mMenuWidth) {
117 | mMoveDistance = mMenuWidth;
118 | }
119 | } else {
120 | mMoveDistance = 0;
121 | }
122 | //手指拖动时实时滑动
123 | scrollTo(mMoveDistance, 0);
124 | break;
125 | case MotionEvent.ACTION_UP:
126 | //如果滑动速度快,根据滑动方向判断是打开还是关闭,如果速度慢,根据滑动位置判断
127 | mVelocityTracker.computeCurrentVelocity(1000);
128 | float xVelocity = mVelocityTracker.getXVelocity();
129 | if (Math.abs(xVelocity) > 50) {
130 | if (xVelocity > 0) {
131 | //右滑关闭
132 | close();
133 | } else {
134 | //左滑打开
135 | open();
136 | }
137 | } else {
138 | //根据位置判断是打开还是关闭
139 | if (mMoveDistance > mMenuWidth / 2) {
140 | //打开
141 | open();
142 | } else {
143 | //关闭
144 | close();
145 | }
146 | }
147 | invalidate();
148 | break;
149 | default:
150 | break;
151 | }
152 | return true;
153 | }
154 |
155 | private void close() {
156 | int move = -mMoveDistance;
157 | mMoveDistance = 0;
158 | smoothScroll(move);
159 | }
160 |
161 | private void open() {
162 | int move = mMenuWidth - mMoveDistance;
163 | mMoveDistance = mMenuWidth;
164 | smoothScroll(move);
165 | }
166 |
167 | private void smoothScroll(int distance) {
168 | //平滑滚动
169 | mScroller.startScroll(getScrollX(), 0, distance, 0);
170 | }
171 |
172 | @Override
173 | public void computeScroll() {
174 | if (mScroller.computeScrollOffset()) {
175 | scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
176 | postInvalidate();
177 | }
178 | }
179 |
180 | }
181 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/swipelayout/SwipeLayoutActivity.kt:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.swipelayout
2 |
3 | import android.support.v7.app.AppCompatActivity
4 | import android.os.Bundle
5 | import android.view.View
6 | import android.widget.Toast
7 | import com.yazhi1992.practice.R
8 | import kotlinx.android.synthetic.main.activity_swipe_layout.*
9 |
10 | class SwipeLayoutActivity : AppCompatActivity() {
11 |
12 | override fun onCreate(savedInstanceState: Bundle?) {
13 | super.onCreate(savedInstanceState)
14 | setContentView(R.layout.activity_swipe_layout)
15 |
16 | tv_content.setOnClickListener(View.OnClickListener { Toast.makeText(this, "内容", Toast.LENGTH_SHORT).show() })
17 | tvMenu1.setOnClickListener(View.OnClickListener { Toast.makeText(this, "菜单1", Toast.LENGTH_SHORT).show() })
18 | tvMenu2.setOnClickListener(View.OnClickListener { Toast.makeText(this, "菜单2", Toast.LENGTH_SHORT).show() })
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/utils/Utils.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.utils;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.graphics.Matrix;
8 | import android.util.TypedValue;
9 |
10 | /**
11 | * Created by zengyazhi on 17/3/31.
12 | */
13 |
14 | public class Utils {
15 | /**
16 | * 根据drawble文件名得到bitmap
17 | *
18 | * @param context 用来获得Resources
19 | * @param width 想要获得的bitmap的宽
20 | * @param height 想要获得的bitmap的高
21 | * @param drawble drawble图片名称
22 | * @return
23 | */
24 | public static Bitmap getBitmap(Context context, int width, int height, int drawble) {
25 | // 得到图像
26 | Resources resources = context.getResources();
27 | Bitmap bitmap = BitmapFactory.decodeResource(resources, drawble);
28 |
29 | int bWidth = bitmap.getWidth();
30 | int bHeight = bitmap.getHeight();
31 |
32 | float scaleX = (float) width / bWidth;
33 | float scaleY = (float) height / bHeight;
34 |
35 | Matrix matrix = new Matrix();
36 | matrix.setScale(scaleX, scaleY);
37 |
38 | return Bitmap.createBitmap(bitmap, 0, 0, bWidth, bHeight, matrix, true);
39 | }
40 |
41 | public static float dp2px(Context Context, int dp) {
42 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Context.getResources().getDisplayMetrics());
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/vertical_text/VerticalText.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.vertical_text;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.support.annotation.Nullable;
8 | import android.util.AttributeSet;
9 | import android.util.TypedValue;
10 | import android.view.View;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 |
16 | /**
17 | * Created by zengyazhi on 17/3/31.
18 | *
19 | * 竖直排列的文字控件
20 | *
21 | * 参考:https://github.com/lybeat/PlumbTextView
22 | */
23 |
24 | public class VerticalText extends View {
25 |
26 | private String mText = "世间所有的相遇,都是久别重逢";
27 | //分割符号
28 | private String mSubStringStr = ",";
29 | private Paint mTextPaint;
30 | private float mTextSize;
31 | //屏幕宽高
32 | private int mWidth;
33 | private int mHeight;
34 | //单个字符高度
35 | private float mCharHeight;
36 | //单个字符宽度
37 | private int mCharWidth;
38 | //上下字间距
39 | private float mTopBottomSpacing;
40 | //左右行间距
41 | private float mLeftRightSpacing;
42 | //每列需要绘制的文字列表
43 | private List
23 | * 波浪效果进度条
24 | */
25 |
26 | public class SinWave extends View {
27 |
28 | private Paint mPaint;
29 | private Path mPath;
30 | private int mHeight;
31 | private int mWidth;
32 | private static final int X_OFFSET = 15;
33 | //坡度值,越小曲线越平缓
34 | private double mGrade = 0.2;
35 | //开启动画时x方向的偏移
36 | float mXOffset;
37 | //开启动画时y方向的偏移
38 | float mYOffset;
39 | private Context mContext;
40 | private Bitmap mBitmap;
41 | private AnimatorSet mAnimatorSet;
42 | //波浪高度
43 | private int mWaveHeight;
44 |
45 | public SinWave(Context context) {
46 | this(context, null);
47 | }
48 |
49 | public SinWave(Context context, @Nullable AttributeSet attrs) {
50 | this(context, attrs, 0);
51 | }
52 |
53 | public SinWave(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
54 | super(context, attrs, defStyleAttr);
55 | init(context);
56 | }
57 |
58 | private void init(Context context) {
59 | //关闭GPU硬件加速
60 | setLayerType(View.LAYER_TYPE_SOFTWARE, null);
61 |
62 | mPaint = new Paint();
63 | mPaint.setColor(context.getResources().getColor(R.color.my_color));
64 | mPaint.setStyle(Paint.Style.FILL);
65 | mPaint.setAntiAlias(true);
66 |
67 | mPath = new Path();
68 |
69 | mContext = context;
70 |
71 | }
72 |
73 | @Override
74 | protected void onDraw(Canvas canvas) {
75 | super.onDraw(canvas);
76 | mPaint.setXfermode(null);
77 | if (mBitmap != null) {
78 | //调低背景图片高度,以防进度=0或进度=100时波浪够不到图片,或进度满了波浪没有充满图片
79 | canvas.drawBitmap(mBitmap, mWaveHeight, 2 * mWaveHeight, mPaint);
80 | }
81 |
82 | mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); //只截取前景里和背景重合的部分
83 | canvas.drawPath(getSinPath(), mPaint);
84 | }
85 |
86 | /**
87 | * 获得正弦函数的path
88 | */
89 | private Path getSinPath() {
90 | mPath.reset();
91 | //注意,view的原点(0,0)是左上角,向右x轴正方向,向下y轴正方向
92 | mPath.moveTo(0, mHeight);
93 | for (float x = 0; x <= mWidth; x += X_OFFSET) {
94 | float y = (float) ((Math.sin(degreeToRad(mGrade * x + mXOffset)) + 1) * mWaveHeight);
95 | mPath.lineTo(x, y + mYOffset);
96 | }
97 | mPath.lineTo(mWidth, mHeight);
98 | mPath.lineTo(0, mHeight);
99 | mPath.close();
100 | return mPath;
101 | }
102 |
103 | /**
104 | * 启动动画
105 | */
106 | public void start() {
107 | mAnimatorSet.start();
108 | }
109 |
110 | /**
111 | * 角度转弧度
112 | *
113 | * @param degree
114 | * @return
115 | */
116 | private double degreeToRad(double degree) {
117 | return degree * Math.PI / 180;
118 | }
119 |
120 | @Override
121 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
122 | super.onSizeChanged(w, h, oldw, oldh);
123 | mWidth = w;
124 | mHeight = h;
125 | mWaveHeight = mHeight / 10;
126 | mYOffset = mHeight - mWaveHeight;
127 |
128 | mBitmap = Utils.getBitmap(mContext, mHeight - 2 * mWaveHeight, mHeight - 2 * mWaveHeight, R.mipmap.ic_launcher);
129 |
130 | initAnim();
131 | }
132 |
133 | private void initAnim() {
134 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 3000);
135 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
136 | @Override
137 | public void onAnimationUpdate(ValueAnimator animation) {
138 | mXOffset = (float) animation.getAnimatedValue();
139 | postInvalidate();
140 | }
141 | });
142 |
143 | ValueAnimator valueAnimator2 = ValueAnimator.ofFloat(mYOffset, 0);
144 | valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
145 | @Override
146 | public void onAnimationUpdate(ValueAnimator animation) {
147 | mYOffset = (float) animation.getAnimatedValue();
148 | postInvalidate();
149 | }
150 | });
151 |
152 | mAnimatorSet = new AnimatorSet();
153 | mAnimatorSet.playTogether(valueAnimator, valueAnimator2);
154 | mAnimatorSet.setDuration(10000);
155 | mAnimatorSet.setInterpolator(new LinearInterpolator());
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/wave_view/WaveViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.wave_view;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.yazhi1992.practice.R;
8 |
9 | public class WaveViewActivity extends AppCompatActivity {
10 |
11 | private SinWave mWave;
12 | private BezierWave mBezierWave;
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_wave_view);
18 |
19 | mWave = (SinWave) findViewById(R.id.waveView);
20 | mBezierWave = (BezierWave) findViewById(R.id.bezierWave);
21 |
22 | findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
23 | @Override
24 | public void onClick(View v) {
25 | mWave.start();
26 | }
27 | });
28 |
29 | findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
30 | @Override
31 | public void onClick(View v) {
32 | mBezierWave.start();
33 | }
34 | });
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/wheel_view/WheelView.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.wheel_view;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.Nullable;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 |
8 | /**
9 | * Created by zengyazhi on 17/4/21.
10 | * 滚轮
11 | * 参考:https://github.com/Bigkoo/Android-PickerView
12 | */
13 |
14 | public class WheelView extends View {
15 | public WheelView(Context context) {
16 | this(context, null);
17 | }
18 |
19 | public WheelView(Context context, @Nullable AttributeSet attrs) {
20 | this(context, attrs, 0);
21 | }
22 |
23 | public WheelView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
24 | super(context, attrs, defStyleAttr);
25 | init();
26 | }
27 |
28 | private void init() {
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yazhi1992/practice/wheel_view/WheelViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.yazhi1992.practice.wheel_view;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.yazhi1992.practice.R;
8 |
9 | public class WheelViewActivity extends AppCompatActivity {
10 |
11 | @Override
12 | protected void onCreate(Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | setContentView(R.layout.activity_wheel_view);
15 |
16 | findViewById(R.id.wheelViewBtn).setOnClickListener(new View.OnClickListener() {
17 | @Override
18 | public void onClick(View v) {
19 |
20 | }
21 | });
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_camera.xml:
--------------------------------------------------------------------------------
1 | > mAllViews = new ArrayList
>();
25 | protected List