Skip to content

Commit 9b15b77

Browse files
committed
2 parents 1c8ca50 + d798c27 commit 9b15b77

File tree

20 files changed

+541
-697
lines changed

20 files changed

+541
-697
lines changed

android-lockpattern/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ android-lockpattern 实现原理解析
88

99
####1.1 关于
1010

11-
Android的图案密码解锁
11+
Android的图案密码解锁,基于[Android Source Code](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/com/android/internal/widget/LockPatternView.java)
1212

1313
![ScreenShot](image/ScreenShot.png)
1414

circular-floating-action-menu/README.md

Lines changed: 17 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ CircularFloatingActionMenu 实现原理解析
22
====================================
33
> 本文为 [Android 开源项目实现原理解析](https://github.com/android-cn/android-open-project-analysis) 中 circular-foating-action-menu 部分
44
> 项目地址:[CircularFloatingActionMenu](https://github.com/oguzbilgener/CircularFloatingActionMenu),分析的版本:[e9ccdad](https://github.com/android-cn/android-open-project-demo/commit/1306e632d5a7734cd8451f4e10dff763f9ab4097),Demo 地址:[circular-foating-action-menu](https://github.com/android-cn/android-open-project-demo/tree/master/CircularFloatingActionMenu-demo)
5-
> 分析者:[cpacm](https://github.com/cpacm),校对者:[${校对者}](${校对者 Github 地址}),校对状态:未完成
5+
> 分析者:[cpacm](https://github.com/cpacm),校对者:[dkmeteor](https://github.com/dkmeteor),校对状态:未完成
66
77
###1. 功能介绍
88
“一个灵感来自Path路径的Android上可定制圆形浮动菜单动画”
@@ -87,8 +87,11 @@ CircularFloatingActionMenu 实现原理解析
8787
这样子,一个简单的案例就做好了
8888

8989
![流程图](https://github.com/android-cn/android-open-project-analysis/blob/master/circular-floating-action-menu/流程图.jpg "流程图")
90-
91-
###3详细设计
90+
###3. 流程图
91+
![设计流程图](https://github.com/android-cn/android-open-project-analysis/blob/master/circular-floating-action-menu/circlemenu.jpg "流程图")
92+
93+
总体的设计流程图如上图所示,中间最复杂的可能是计算view位置的地方。
94+
###4. 详细设计
9295

9396
##SubActionButton
9497
首先是构造函数
@@ -174,7 +177,7 @@ public SubActionButton(Activity activity, LayoutParams layoutParams, int theme,
174177
}
175178
}
176179
```
177-
传入activity,视图特性配置,主题的id,背景图,imageview(子视图),mageview(子视图)的特性配置。用这些来配置选项按钮。
180+
传入activity,视图特性配置,主题的id,背景图,imageview(子视图),imageview(子视图)的特性配置。用这些来配置选项按钮。
178181

179182
##FloatingActionButton
180183
菜单按钮其实跟选项按钮的代码模式差不多,也是由设定子视图和一个建造器组成。
@@ -189,47 +192,15 @@ public SubActionButton(Activity activity, LayoutParams layoutParams, int theme,
189192
public void setPosition(int position, FrameLayout.LayoutParams layoutParams) {
190193
int gravity;
191194
switch(position) {
192-
case POSITION_TOP_CENTER:
193-
gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
194-
break;
195-
case POSITION_TOP_RIGHT:
196-
gravity = Gravity.TOP | Gravity.RIGHT;
197-
break;
198-
case POSITION_RIGHT_CENTER:
199-
gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
200-
break;
201-
case POSITION_BOTTOM_CENTER:
202-
gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
203-
break;
204-
case POSITION_BOTTOM_LEFT:
205-
gravity = Gravity.BOTTOM | Gravity.LEFT;
206-
break;
207-
case POSITION_LEFT_CENTER:
208-
gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
209-
break;
210-
case POSITION_TOP_LEFT:
211-
gravity = Gravity.TOP | Gravity.LEFT;
212-
break;
213-
case POSITION_BOTTOM_RIGHT:
214-
default:
215-
gravity = Gravity.BOTTOM | Gravity.RIGHT;
216-
break;
195+
...//具体代码请自行查看源代码
217196
}
218197
layoutParams.gravity = gravity;
219198
setLayoutParams(layoutParams);
220199
}
221200
```
222201

223202
将视图绑定到activity的主视图中。这样我们就能在activity的主视图中操作这个view了。
224-
```java
225-
/**
226-
* Attaches it to the Activity content view with specified LayoutParams.
227-
* @param layoutParams
228-
*/
229-
public void attach(FrameLayout.LayoutParams layoutParams) {
230-
((ViewGroup)getActivityContentView()).addView(this, layoutParams);
231-
}
232-
```
203+
233204

234205
FloatingActionButton的建造器
235206
```java
@@ -268,111 +239,19 @@ FloatingActionMenu rightLowerMenu = new FloatingActionMenu.Builder(this)
268239
* Builder(this)将activity传入menu中
269240
* addSubActionView 添加选项按钮到activity的视图中。在FloatingActionMenu中管理SubActionView是一个Item的list集合,每次加一个按钮就往里面添加。Item是一个辅助类,里面包括一个视图,x坐标,y坐标,长度,宽度。
270241
* setAnimationHandler 则是设定动画。
271-
* attachTo是将menu与activity的视图绑定。(即把菜单按钮的视图添加到activity的视图中)
272-
273-
item类
274-
```java
275-
/**
276-
* A simple structure to put a view and its x, y, width and height values together
277-
*/
278-
public static class Item {
279-
public int x;
280-
public int y;
281-
public int width;
282-
public int height;
283-
284-
public View view;
285-
286-
public Item(View view, int width, int height) {
287-
this.view = view;
288-
this.width = width;
289-
this.height = height;
290-
x = 0;
291-
y = 0;
292-
}
293-
}
294-
```
242+
* attachTo是将menu与activity的视图绑定。(即把菜单按钮的视图添加到activity的视图中)
243+
295244
FloatingActionMenu类主要是管理菜单按钮和选项按钮的位置和状态(开和关)
296-
(1)首先是通过view的onClick监听器来控制状态
297-
```java
298-
/**
299-
* A simple click listener used by the main action view
300-
*/
301-
public class ActionViewClickListener implements View.OnClickListener {
245+
(1)首先是通过view的onClick监听器来控制状态
302246

303-
@Override
304-
public void onClick(View v) {
305-
toggle(animated);
306-
}
307-
}
308-
309-
/**
310-
* Toggles the menu
311-
* @param animated if true, the open/close action is executed by the current {@link MenuAnimationHandler}
312-
*/
313-
public void toggle(boolean animated) {
314-
if(open) {
315-
close(animated);
316-
}
317-
else {
318-
open(animated);
319-
}
320-
}
321-
```
322247
(2)开关主要是两种状态,开的时候会获得菜单按钮的中心位置center(getActionViewCenter())和计算item的位置(calculateItemPositions())。然后发送动画的请求到AnimationHandler中(animationHandler.animateMenuOpening(center))。
323248
```java
324249
/**
325250
* Simply opens the menu by doing necessary calculations.
326251
* @param animated if true, this action is executed by the current {@link MenuAnimationHandler}
327252
*/
328253
public void open(boolean animated) {
329-
// Find the center of the action view
330-
Point center = getActionViewCenter();
331-
// populate destination x,y coordinates of Items
332-
calculateItemPositions();
333-
334-
if(animated && animationHandler != null) {
335-
// If animations are enabled and we have a MenuAnimationHandler, let it do the heavy work
336-
if(animationHandler.isAnimating()) {
337-
// Do not proceed if there is an animation currently going on.
338-
return;
339-
}
340-
341-
for (int i = 0; i < subActionItems.size(); i++) {
342-
// It is required that these Item views are not currently added to any parent
343-
// Because they are supposed to be added to the Activity content view,
344-
// just before the animation starts
345-
if (subActionItems.get(i).view.getParent() != null) {
346-
throw new RuntimeException("All of the sub action items have to be independent from a parent.");
347-
}
348-
// Initially, place all items right at the center of the main action view
349-
// Because they are supposed to start animating from that point.
350-
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(subActionItems.get(i).width, subActionItems.get(i).height, Gravity.TOP | Gravity.LEFT);
351-
params.setMargins(center.x - subActionItems.get(i).width / 2, center.y - subActionItems.get(i).height / 2, 0, 0);
352-
//
353-
((ViewGroup) getActivityContentView()).addView(subActionItems.get(i).view, params);
354-
}
355-
// Tell the current MenuAnimationHandler to animate from the center
356-
animationHandler.animateMenuOpening(center);
357-
}
358-
else {
359-
// If animations are disabled, just place each of the items to their calculated destination positions.
360-
for (int i = 0; i < subActionItems.size(); i++) {
361-
// This is currently done by giving them large margins
362-
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(subActionItems.get(i).width, subActionItems.get(i).height, Gravity.TOP | Gravity.LEFT);
363-
params.setMargins(subActionItems.get(i).x, subActionItems.get(i).y, 0, 0);
364-
subActionItems.get(i).view.setLayoutParams(params);
365-
// Because they are placed into the main content view of the Activity,
366-
// which is itself a FrameLayout
367-
((ViewGroup) getActivityContentView()).addView(subActionItems.get(i).view, params);
368-
}
369-
}
370-
// do not forget to specify that the menu is open.
371-
open = true;
372-
373-
if(stateChangeListener != null) {
374-
stateChangeListener.onMenuOpened(this);
375-
}
254+
...//具体代码请自行查看源代码
376255
}
377256
```
378257
其中item的x,y是记录视图的终点位置,然后经过动画把view移到x,y的位置上。
@@ -393,33 +272,7 @@ stateChangeListener为状态变化的监听器,开关都会响应相应的方
393272
* Calculates the desired positions of all items.
394273
*/
395274
private void calculateItemPositions() {
396-
// Create an arc that starts from startAngle and ends at endAngle
397-
// in an area that is as large as 4*radius^2
398-
Point center = getActionViewCenter();
399-
//内切弧形路径
400-
RectF area = new RectF(center.x - radius, center.y - radius, center.x + radius, center.y + radius);
401-
Path orbit = new Path();
402-
orbit.addArc(area, startAngle, endAngle - startAngle);
403-
404-
PathMeasure measure = new PathMeasure(orbit, false);
405-
406-
// Prevent overlapping when it is a full circle
407-
int divisor;
408-
if(Math.abs(endAngle - startAngle) >= 360 || subActionItems.size() <= 1) {
409-
divisor = subActionItems.size();
410-
}
411-
else {
412-
divisor = subActionItems.size() -1;
413-
}
414-
415-
// Measure this path, in order to find points that have the same distance between each other
416-
for(int i=0; i<subActionItems.size(); i++) {
417-
float[] coords = new float[] {0f, 0f};
418-
measure.getPosTan((i) * measure.getLength() / divisor, coords, null);
419-
// get the x and y values of these points and set them to each of sub action items.
420-
subActionItems.get(i).x = (int) coords[0] - subActionItems.get(i).width / 2;
421-
subActionItems.get(i).y = (int) coords[1] - subActionItems.get(i).height / 2;
422-
}
275+
...//具体代码请自行查看源代码
423276
}
424277
```
425278

@@ -435,24 +288,7 @@ stateChangeListener为状态变化的监听器,开关都会响应相应的方
435288
* @param actionType
436289
*/
437290
protected void restoreSubActionViewAfterAnimation(FloatingActionMenu.Item subActionItem, ActionType actionType) {
438-
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) subActionItem.view.getLayoutParams();
439-
subActionItem.view.setTranslationX(0);
440-
subActionItem.view.setTranslationY(0);
441-
subActionItem.view.setRotation(0);
442-
subActionItem.view.setScaleX(1);
443-
subActionItem.view.setScaleY(1);
444-
subActionItem.view.setAlpha(1);
445-
if(actionType == ActionType.OPENING) {
446-
//与父视图的边框距离,只要设置左上两个方位就能确定位置
447-
params.setMargins(subActionItem.x, subActionItem.y, 0, 0);
448-
subActionItem.view.setLayoutParams(params);
449-
}
450-
else if(actionType == ActionType.CLOSING) {
451-
Point center = menu.getActionViewCenter();
452-
params.setMargins(center.x - subActionItem.width / 2, center.y - subActionItem.height / 2, 0, 0);
453-
subActionItem.view.setLayoutParams(params);
454-
((ViewGroup) menu.getActivityContentView()).removeView(subActionItem.view);
455-
}
291+
...//具体代码请自行查看源代码
456292
}
457293
```
458294
Animator属性动画以及其他动画的实现请参考我写的博客
@@ -462,21 +298,7 @@ Animator属性动画以及其他动画的实现请参考我写的博客
462298

463299

464300

465-
###4. 杂谈
466-
动画的类型有点少,以及不支持分辨率奇葩的机型,如魅族3
467-
468-
469-
###5. 修改完善
470-
在完成了上面 5 个部分后,移动模块顺序,将
471-
`2. 详细设计` -> `2.1 核心类功能介绍` -> `2.2 类关系图` -> `3. 流程图` -> `4. 总体设计`
472-
顺序变为
473-
`2. 总体设计` -> `3. 流程图` -> `4. 详细设计` -> `4.1 类关系图` -> `4.2 核心类功能介绍`
474-
并自行校验优化一遍,确认无误后,让`校对 Buddy`进行校对,`校对 Buddy`校队完成后将
475-
`校对状态:未完成`
476-
变为:
477-
`校对状态:已完成`
301+
###5. 杂谈
302+
动画的类型有点少,以及在屏幕尺寸异常的机子上测试时(如mx3的1800x1080)会出现子选项偏离中心菜单键的问题,原因出在view的位置计算上,它没有考虑到一些特殊机型的机子。
478303

479-
**完成时间**
480-
- `两天内`完成
481304

482-
**到此便大功告成,恭喜大家^_^**
159 KB
Loading

common/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ ${项目名} 实现原理解析
1313
- `一天内`完成
1414

1515
###2. 详细设计
16-
###2.1 核心类功能介绍
16+
###2.1 类详细介绍
1717
核心类、函数功能介绍及核心功能流程图,流程图可使用 StartUML、Visio 或 Google Drawing。
1818
###2.2 类关系图
1919
类关系图,类的继承、组合关系图,可是用 StartUML 工具。

0 commit comments

Comments
 (0)