acc8226 的博客

(2017 下半年) 价格区间主要集中在 5000 到 8000 左右

处理器,显卡,内存高性能 8G 起步(以后有需要可以升级到 16G)

  • 单机游戏不在话下, 程序员有需要也可参考
  • 根据 2017 年 10 月初到中旬收集到的信息, 整理了一下(共挑了 3 款笔记本)。

戴尔 游匣 15PR

从靠谱这个角度来说,没有比内置金属防滚架的它更强悍了,GTX 1050 4GB 独显在全高清分辨率下应对大多大型单机或电竟游戏也都没有什么问题。

15.6 寸屏幕比普通 14 寸屏幕稍微大点儿,我还是推荐屏稍微大点儿的体验会更好点,便携性差点儿,但可接受。

屏幕为 IPS 面板(IPS 面板的优势是可视角度高、响应速度快,色彩还原准确,是液晶面板里的高端产品),扬声器表现也相当不错。

阅读全文 »

安卓自定义 ViewGroup 需要注意的地方

至少需要提供 width, 和 height 两个属性

同样地,如果要使用自定义的属性,那么就需要创建自己的名字空间,在 Android Studio 中,第三方的控件都使用如下代码来引入名字空间。

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

流动布局手写精简版

  • 增加了 ‘center’ 居中等三种排列方式
  • 额外支持 padding 属性
  • layout_newline 属性支持自定义换行(类似’\n’的换行效果)

参考

下一步升级

  • 逆序排列子 view
  • 倒序排列子 view
  • 使每行 view 均分剩余空间
  • 可尝试增加目前流行的 tag 效果

FlowLayout.java

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
package cn.lik.view;

import java.util.ArrayList;
import java.util.List;

import cn.lik.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

/**
* 流式布局
*
* @author l1k
*/
public class FlowLayout extends ViewGroup {
private static final String TAG = FlowLayout.class.getSimpleName();
private static final boolean DEBUG = false;

/**
* 存储所有的View,按行记录
*/
private ArrayList<List<View>> mAllViews = new ArrayList<List<View>>();
/**
* 记录每一行的最大高度
*/
private ArrayList<Integer> mLineHeight = new ArrayList<Integer>();


/**
* The current value of the {@link AlignItems}, the default value is
* {@link AlignItems#CENTER}.
*
* @see AlignItems
*/
private int mAlignItems;

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

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

public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlexLayout, defStyleAttr, 0);
mAlignItems = a.getInt(R.styleable.FlexLayout_alignItems, AlignItems.CENTER);
a.recycle();
}

@AlignItems
public int getAlignItems() {
return mAlignItems;
}

public void setAlignItems(@AlignItems int alignItems) {
if (mAlignItems != alignItems) {
mAlignItems = alignItems;
requestLayout();
}
}

@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 ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}

/**
* 负责设置子控件的测量模式和大小 根据所有子控件设置自己的宽和高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获得它的父容器为它设置的测量模式和大小
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

if (DEBUG) {
Log.i(TAG, "onMeasure: sizeWidth = " + sizeWidth + ", sizeHeight = " + sizeHeight);
}

// 如果是warp_content情况下,记录宽和高
int width = 0;
int height = 0;
/**
* 记录每一行的宽度,width不断取最大宽度
*/
int lineWidth = 0;
/**
* 每一行的高度,累加至height
*/
int lineHeight = 0;

int cCount = getChildCount();

final int paddingHorizontal = getPaddingLeft() + getPaddingRight();

// 遍历每个子元素
for (int i = 0; i < cCount; i++) {
final View child = getChildAt(i);
// 测量每一个child的宽和高
measureChild(child, widthMeasureSpec, heightMeasureSpec);
// 得到child的lp
final LayoutParams lp = (LayoutParams) child.getLayoutParams();

// 当前子空间实际占据的宽度
int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
// 当前子空间实际占据的高度
int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
/**
* 如果加入当前child,则超出最大宽度,则的到目前最大宽度给width,累加height 然后开启新行
*/
if ((i!=0) && (lp.newline || (lineWidth + childWidth > sizeWidth - paddingHorizontal))) {
width = Math.max(Math.max(lineWidth, childWidth), width);// 取最大
lineWidth = childWidth; // 开启新行,记录宽度
// 叠加当前高度,
height += lineHeight;
// 开启记录下一行的高度
lineHeight = childHeight;// 开启新行, 记录高度
} else { // 否则累加值lineWidth,lineHeight取最大高度
lineWidth += childWidth;
lineHeight = Math.max(lineHeight, childHeight);
}
// 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较
if (i == cCount - 1) {
width = Math.max(width, lineWidth);
height += lineHeight;
}
}

super.setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth
: width + getPaddingLeft() + getPaddingRight(),
(modeHeight == MeasureSpec.EXACTLY) ? sizeHeight
: height + getPaddingTop() + getPaddingBottom());
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mAllViews.clear();
mLineHeight.clear();

int width = getWidth();
int lineWidth = 0;
int lineHeight = 0;

int left = getPaddingLeft();
int top = getPaddingTop();
final int paddingHorizontal = left + getPaddingRight();

// 存储每一行所有的childView
List<View> lineViews = new ArrayList<View>();
int cCount = getChildCount();
// 遍历所有的孩子
for (int i = 0; i < cCount; i++) {
final View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
// 当前子空间实际占据的高度
int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;

// 如果已经需要换行
if ((i!=0) && (lp.newline || (childWidth + lineWidth > width - paddingHorizontal))) {
// 记录这一行所有的View以及最大高度
mLineHeight.add(lineHeight);
// 将当前行的childView保存,然后开启新的ArrayList保存下一行的childView
mAllViews.add(lineViews);

lineWidth = 0;// 重置宽
lineHeight = 0;//重置高
lineViews = new ArrayList<View>();
}
/**
* 如果不需要换行,则累加
*/
lineWidth += childWidth;
lineHeight = Math.max(lineHeight, childHeight);
lineViews.add(child);
}
// 记录最后一行
mLineHeight.add(lineHeight);
mAllViews.add(lineViews);

// 得到总行数
int lineNums = mAllViews.size();
for (int i = 0; i < lineNums; i++) {
// 每一行的所有的views
lineViews = mAllViews.get(i);
// 当前行的最大高度
lineHeight = mLineHeight.get(i);

if (DEBUG) {
Log.e(TAG, "第" + i + "行 :" + lineViews.size() + " , " + lineViews);
Log.e(TAG, "第" + i + "行, :" + lineHeight);
}

// 遍历当前行所有的View
for (int j = 0; j < lineViews.size(); j++) {
View child = lineViews.get(j);
if (child.getVisibility() == View.GONE) {
continue;
}
MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

// 计算childView的left,top,right,bottom
int lc = 0;
int tc = 0;
int rc = 0;
int bc = 0;

switch (mAlignItems) {
case AlignItems.FLEX_START:
lc = left + lp.leftMargin;
tc = top + lp.topMargin;
rc = lc + child.getMeasuredWidth();
bc = tc + child.getMeasuredHeight();
break;
case AlignItems.FLEX_END:
lc = left + lp.leftMargin;
tc = top + lineHeight - child.getMeasuredHeight() - lp.bottomMargin;
rc = lc + child.getMeasuredWidth();
bc = tc + child.getMeasuredHeight();
break;
case AlignItems.CENTER:
lc = left + lp.leftMargin;
tc = top + lp.topMargin
+ (lineHeight - lp.topMargin - child.getMeasuredHeight() - lp.bottomMargin) / 2;
rc = lc + child.getMeasuredWidth();
bc = tc + child.getMeasuredHeight();
break;
default:
throw new IllegalStateException("Invalid alignItems is set: " + mAlignItems);
}

child.layout(lc, tc, rc, bc);

left += child.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
}
left = getPaddingLeft();
top += lineHeight;
}

}

public static class LayoutParams extends ViewGroup.MarginLayoutParams {
/**
* need newline or not
*/
public boolean newline = false;

public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
final TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FlexLayout_Layout);
newline = a.getBoolean(R.styleable.FlexLayout_Layout_layout_newline, false);
a.recycle();
}

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

public LayoutParams(ViewGroup.MarginLayoutParams lp) {
super(lp);
}

/**
* Copy constructor. Clones the width, height, margin values, newline
*
* @param lp The layout params to copy from.
*/
public LayoutParams(LayoutParams lp) {
super(lp);
this.newline = lp.newline;
}

/**
* Copy constructor. Clones the width, height
*
* @param lp The layout params to copy from.
*/
public LayoutParams(int width, int height) {
super(width, height);
}

/**
* Copy constructor. Clones the width, height, newline
*
* @param lp The layout params to copy from.
*/
public LayoutParams(int width, int height, boolean newline) {
super(width, height);
this.newline = newline;
}

}

}

AlignItems.java

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
/*
* Copyright 2016 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package cn.lik.view.flexbox;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/** This attribute controls the alignment along the cross axis. */
@Retention(RetentionPolicy.SOURCE)
public @interface AlignItems {

/** Flex item's edge is placed on the cross start line. */
int FLEX_START = 0;

/** Flex item's edge is placed on the cross end line. */
int FLEX_END = 1;

/** Flex item's edge is centered along the cross axis. */
int CENTER = 2;
}

res/values/attrs.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FlexLayout">
<attr name="alignItems">
<enum name="flex_start" value="0" />
<enum name="flex_end" value="1" />
<enum name="center" value="2" />
</attr>
</declare-styleable>
<declare-styleable name="FlexLayout_Layout">
<attr name="layout_newline" format="boolean" />
</declare-styleable>
</resources>

官网

下载地址 Eclipse Packages | The Eclipse Foundation - home to a global community, the Eclipse IDE, Jakarta EE and over 350 open source projects… https://www.eclipse.org/downloads/packages/

使用前基本配置

将工作区 Text 文件编码改为 UTF-8。

默认编辑区域的字体太小,优先推荐调节为 14 或者 16 号。

阅读全文 »

型号 分辨率 尺寸 densityDpi density 屏幕级别 逻辑分辨率 屏幕比例
iPhone6 1334*750像素 4.7" 326(≈320) 2(320/160) xhdpi 667*375 16:9
Nexus5 1920*1080像素 5" 445(480) 3 xxhdpi 640*360 同上
标准5寸手机 1280*720 像素 5" 294(320) 2 xhdpi 640*360 同上
魅族 note3 1920*1080 像素 5.5" 401(480) 3 xxhdpi 640*360 同上
华为 Nexus 6P 2560x1440 像素 5.7" 515(640) 4 xxxhdpi 640*360 同上
华为 Mate 8 1920x1080 像素 6" 367(480) 3 xxhdpi 640*360 同上
小米MAX 1920*1080像素 6.44" 342(441) 2.75 xxhdpi 698*392 同上
华为 M2 PLE-703L 1920*1200 7" 323(400) 2.5 xxhdpi 768*480 16:10
华为 M3 CPN-W09 1920*1200 8" 283(360) 2.25 xxhdpi 853*533 同上
华为 T1-821W 1280*800 8" 189(213) 1.33 hdpi 960*600 同上
NCI定制T106 1920*1200 8" 283(320) 2 xhdpi 同上 同上
华为 M3 BTV-W09 2560*1600 8.4" 359(400) 2.5 xxhdpi 1024*640 同上
小米平板1~3代 2048*1536 8" 324(320) 2 xhdpi 1024*768 4:3
三星Galaxy Tab S2 2048x1536 9.7" 264(320) 2 同上 同上 同上
NCI定制T101 1280*800 10.1" 150(160) 1 mdpi 1280*800 16:10
华为 FDR-A01w 1920*1200 10.1" 224(240) 1.5 hdpi 同上 同上

sw600 系列:
同华为 T1-821W: 华为 T1-823L
NCI定制T106: 华为 T1-801W / 华为M2-803L / JDN-W09 /

sw768系列:
同三星Galaxy Tab S2 : 华硕 ZenPad 3S

总结:

  1. 一般而言屏幕尺寸越大, 逻辑分辨率越大
  2. 手机屏目前标准都是 1920 * 1080 像素, xxhdpi 3倍关系, 逻辑分辨率为 640dp * 360dp, 比例为 16:9
  3. Pad 屏幕大多数最小宽度 600dp 以上, 目前看到的最小数据为为 480dp

附录

iPhone 界面设计规范

0%