-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
484 lines (362 loc) · 19.2 KB
/
atom.xml
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
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[别过来]]></title>
<link href="http://tongcpp.github.io/atom.xml" rel="self"/>
<link href="http://tongcpp.github.io/"/>
<updated>2015-05-18T19:24:39+08:00</updated>
<id>http://tongcpp.github.io/</id>
<author>
<name><![CDATA[Atom]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[强制Actionbar与Tab显示为一行或两行]]></title>
<link href="http://tongcpp.github.io/blog/2015/05/18/set-embeded-actionbar-and-tab/"/>
<updated>2015-05-18T15:38:24+08:00</updated>
<id>http://tongcpp.github.io/blog/2015/05/18/set-embeded-actionbar-and-tab</id>
<content type="html"><![CDATA[<h2>Actionbar使用Tab模式</h2>
<ul>
<li>ActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS)即可另Actionbra使用tab作为导航模式;</li>
<li>ActionBar.addTab(Tab tab)使用该方法为你的导航添加具体的Tab;</li>
</ul>
<h2>显示为单行还是两行?</h2>
<ul>
<li>根据developer官方指导,当屏幕宽度足够时,Tab将嵌入Actionbar显示为一行,如大屏Pad、手机横屏时;</li>
<li><img src="http://developer.android.com/images/ui/[email protected]" alt="Action bar tabs on a wide screen" /></li>
<li>当屏幕宽度较窄时,Tab显示在Actionbar下一行,总共两行,常见于手机竖屏时;</li>
<li><img src="http://developer.android.com/images/ui/[email protected]" alt="Tabs on a narrow screen" /></li>
</ul>
<h2>强制在所有情况下显示为单行或两行</h2>
<ul>
<li>有时需求在pad上显示双行Tab,或是在手机竖屏时显示为单行Actionbar;</li>
<li><p>强制显示为单行
try {
Method setHasEmbeddedTabsMethod = mActionBar.getClass().getDeclaredMethod(
“setHasEmbeddedTabs”, boolean.class);
setHasEmbeddedTabsMethod.setAccessible(true);
setHasEmbeddedTabsMethod.invoke(mActionBar, true);
} catch (Exception ignore) {
}</p></li>
<li><p>强制显示为两行
try {
Method setHasEmbeddedTabsMethod = mActionBar.getClass().getDeclaredMethod(
“setHasEmbeddedTabs”, boolean.class);
setHasEmbeddedTabsMethod.setAccessible(true);
setHasEmbeddedTabsMethod.invoke(mActionBar, false);
} catch (Exception ignore) {
}</p></li>
</ul>
<h2>使用ActionbarSherlock</h2>
<ul>
<li>ActionbarSherlock在3.0系统版本及以上直接调用Android原生的Actionbar,在2.3及以下使用内建的Actionbar来兼容;</li>
<li>原生类ActionBarWrapper中,通过上边的反射修改private final android.app.ActionBar mActionBar;</li>
<li>兼容类ActionBarImpl中,指定setHasEmbeddedTabs(boolean hasEmbeddedTabs)中参数即可;</li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Handle onContextItemSelected in Fragment in Viewpager]]></title>
<link href="http://tongcpp.github.io/blog/2014/12/29/handle-oncontextitemselected-in-fragment-in-viewpager/"/>
<updated>2014-12-29T11:09:54+08:00</updated>
<id>http://tongcpp.github.io/blog/2014/12/29/handle-oncontextitemselected-in-fragment-in-viewpager</id>
<content type="html"><![CDATA[<h2>ContextMenu</h2>
<p>上下文菜单ContextMenu由系统支持,常用于通过长按控件弹出列表形菜单,实现步骤如下
- onCreateContextMenu方法 创建菜单
- registerForContextMenu方法,为需响应的控件注册
- onContextItemSelected方法,响应点击</p>
<h2>在Viewpager中的Fragment使用ContextMenu发生的问题</h2>
<p>在我的具体项目环境中,Viewpager中存在3个Fragment(0/1/2),并继承自一个父类BaseFragment。在父类中完成了上下文菜单的绝大部分工作,即上文提到的创建/注册/响应点击;
子类中仅重写onCreateContextMenu方法,用于区分修改菜单显示;那么问题来了:
- 当点击Fragment0的上下文菜单的某项时,Fragment1和2的点击响应事件也同时执行了;
- 当分别点击Fragment1和2的上下文菜单时,也仍然按照Fragment0-1-2的顺序将响应事件依次执行一遍;</p>
<h2>解决方法</h2>
<p>问题的症结在于Viewpager改变了其中的Fragment显式的生命周期和关联关系,在前文《关于Activity中的Viewpager中的Fragment的生命周期》我也提到过这一问题,并尝试采用setUserVisibleHint方法解决了问题;
在本文中同样,可以采用getUserVisibleHint()方法判断当前Fragment是否真实可见,如可见则响应,不可见则截止并向下分发,直到有可见页面响应为止。</p>
<ul>
<li><p>在3个Fragment子类中,均需重写
@Override
public boolean onContextItemSelected(MenuItem item) {
if (getUserVisibleHint()) {
return super.onContextItemSelected(item);
}
return false;
}</p></li>
<li><p>return true 代表截断</p></li>
<li>return false 代表继续分发</li>
</ul>
<h2>另一种解决方案</h2>
<ul>
<li>StackOverFlow提供了另一个解决方案,为每一个Fragment分别创建菜单,在创建时设置Group组号,并在分别响应点击时判断组号来完成截止和分发;</li>
<li>本文方法针对我的具体代码而言改动较小,更为简便清晰,故未采用上述方式。</li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[How Lifecycle Works in Fragment in ViewPager in Activity]]></title>
<link href="http://tongcpp.github.io/blog/2014/11/19/how-lifecycle-works-in-fragment-in-viewpager-in-activity/"/>
<updated>2014-11-19T17:20:51+08:00</updated>
<id>http://tongcpp.github.io/blog/2014/11/19/how-lifecycle-works-in-fragment-in-viewpager-in-activity</id>
<content type="html"><![CDATA[<h2>Activity和Fragment各自理论上的生命周期</h2>
<ul>
<li>Activity的生命周期是较为经典也最清晰的,在此不表;</li>
<li>Fragment从出现到广泛运用也有一段时间了,其标准生命周期也仅比Activity多出一些流程,如onCreateView();</li>
</ul>
<hr />
<ul>
<li>Activity和Fragment在实际编码中必定是结合出现的,表现为Activity作为容器,装载有一个或若干个Fragment;</li>
<li>装载多个Fragment时,经常使用TabHost和Viewpager作为载体;</li>
<li>在实际编码中发现,Activity和Fragment的混合情况里,其生命周期的交叉可能与预想中有差别;</li>
</ul>
<hr />
<ul>
<li><p>使用如下方式加载Fragment时:</p>
<pre><code>getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, mFragment, SHARE_PUBLIC_LIST_FRAGMENT_TAG)
.commitAllowingStateLoss();
</code></pre>
其onResume和onPause执行过程为:
<ul>
<li>Activity - onResume</li>
<li>Fragment - onResume</li>
<li>Activity - onPause</li>
<li>Fragment - onPause</li>
</ul>
</li>
</ul>
<h2>友盟-页面统计要求</h2>
<ul>
<li>Activity和Fragment共同体页面统计中,需要保证线性不交叉,每个onPageStart都有一个onPageEnd配对,</li>
<li>如:onPageStart ->onPageEnd-> onPageStart -> onPageEnd -> onPageStart ->onPageEnd</li>
<li>这样才能保证每个页面统计的正确。</li>
</ul>
<h2>Viewpager中Fragment的生命周期</h2>
<ul>
<li>ViewPager装载Fragment一般使用FragmentPagerAdapter或FragmentStatePagerAdapter,同样借助FragmentManager,在adapter的getItem方法中根据position制定显示的fragment</li>
<li>由于Viewpager的缓存特点,Viewpager启动时其第一个Fragment页面及待缓存的页面都将按顺序呢开始他们的正常生命周期,走向onResume,即:
<ul>
<li>Viewpager所在Activity - onResume</li>
<li>Fragment1 - onResume</li>
<li>Fragment2 - onResume</li>
<li>Fragment3 - onResume</li>
</ul>
</li>
<li>由于这若干个页面的生命周期被同时催化了,影响了我们的单一判断,即无法判断“真正”显示和消失在使用者眼前的页面。</li>
</ul>
<h2>解决方案</h2>
<ul>
<li>方案1:设置Viewpager的缓存机制,不缓存除当前页以外的页面数据,所见即所得,离开即销毁;</li>
<li>此方案对需求改动较大,且较影响用户体验;</li>
</ul>
<hr />
<ul>
<li>方案2:重载Fragment.onHiddenChanged(boolean hidden)方法,其参数hidden代表当前fragment显隐状态改变时,是否为隐藏状态,可通过check此参数作处理;</li>
<li>此方案局限在于本方法的系统调用时间发生在显隐状态改变时,但第一次显示时此方法并不调用;</li>
</ul>
<hr />
<ul>
<li>方案3:重载Fragment.setUserVisibleHint(boolean isVisibleToUser)方法,其参数isVisibleToUser顾名思义最接近我们的需求,代表页面是否“真正”对使用者显示;</li>
<li>此方案局限在于此方法的第一次系统调用甚至早于Fragment的onCreate方法,故其第一次调用时isVisibleToUser值总为false,影响我们对生命周期顺序的判定;
<ul>
<li>Fragment1 - isVisibleToUser - false (多余)</li>
<li>Fragment1 - isVisibleToUser - true</li>
<li>Fragment1 - isVisibleToUser - false</li>
<li>Fragment2 - isVisibleToUser - false (多余)</li>
<li>Fragment2 - isVisibleToUser - true</li>
<li>Fragment2 - isVisibleToUser - false</li>
</ul>
</li>
</ul>
<h2>实际采用的解决方案</h2>
<ul>
<li>根据对产品需求的理解和用户体验的统一,选择在方案3基础上加以改进;</li>
<li><p>setUserVisibleHint()方法本身很接近我们的需求,它的局限点我采取了一个侵入式的解决方式:
protected boolean isCreated = false;</p>
<pre><code> @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
isCreated = true;
}
/**
* 此方法目前仅适用于标示ViewPager中的Fragment是否真实可见
* For 友盟统计的页面线性不交叉统计需求
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (!isCreated) {
return;
}
if (isVisibleToUser) {
umengPageStart();
}else {
umengPageEnd();
}
}
</code></pre></li>
<li><p>对onCreate方法结束的一个标记即可解决问题;</p></li>
</ul>
<h2>One more thing</h2>
<ul>
<li>Viewpager装载Fragment时还有另一个坑,Viewpager的父容器(Activity或Fragment)在显隐状态改变时,
如在Activity的onResume和onPause调用时,并不会主动通知Viewpager内的Fragment执行其应用的生命周期,故我们需要再增加手动强制调用两次</li>
<li>在Activity中查询到当前的Fragment,并执行其内方法,需要借助Viewpager,并改写其PagerAdapter;</li>
<li>我采用了此文提到的Second Solution:<a href="http://blog.csdn.net/piglovesula/article/details/12916279">如何获得ViewPager当前显示的Fragment?</a></li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[ActivityLifecycleCallbacks使用方法初探]]></title>
<link href="http://tongcpp.github.io/blog/2014/10/21/how-to-use-activitylifecyclecallbacks/"/>
<updated>2014-10-21T15:08:47+08:00</updated>
<id>http://tongcpp.github.io/blog/2014/10/21/how-to-use-activitylifecyclecallbacks</id>
<content type="html"><![CDATA[<h2>ActivityLifecycleCallbacks是什么?</h2>
<ul>
<li>Application通过此接口提供了一套回调方法,用于让开发者对Activity的生命周期事件进行集中处理。</li>
</ul>
<h2>为什么用ActivityLifecycleCallbacks?</h2>
<ul>
<li><p>以往若需监测Activity的生命周期事件代码,你可能是这样做的,重写每一个Acivity的onResume(),然后作统计和处理:</p>
<pre><code>@Override
protected void onResume() {
super.onResume();
//TODO 处理和统计代码
Log.v(TAG, "onResume");
Logger.v(TAG, "onResume");
Logging.v(TAG, "onResume");
...
}
</code></pre></li>
<li>ActivityLifecycleCallbacks接口回调可以简化这一繁琐过程,在一个类中作统一处理</li>
</ul>
<h2>ActivityLifecycleCallbacks怎么用?</h2>
<ul>
<li>android.app.Application.ActivityLifecycleCallbacks</li>
<li>要求API 14+ (Android 4.0+)</li>
<li><p>继承Application</p>
<pre><code>public class BaseApplication extends Application
</code></pre></li>
<li><p>在AndroidManifest里起用自定义Application</p>
<pre><code><application android:name=".global.BaseApplication"
</code></pre></li>
<li><p>重写Application的onCreate()方法,或在Application的无参构造方法内,调用Application.registerActivityLifecycleCallbacks()方法,并实现ActivityLifecycleCallbacks接口</p>
<pre><code>public void onCreate() {
super.onCreate();
this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityStopped(Activity activity) {
Logger.v(activity, "onActivityStopped");
}
@Override
public void onActivityStarted(Activity activity) {
Logger.v(activity, "onActivityStarted");
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Logger.v(activity, "onActivitySaveInstanceState");
}
@Override
public void onActivityResumed(Activity activity) {
Logger.v(activity, "onActivityResumed");
}
@Override
public void onActivityPaused(Activity activity) {
Logger.v(activity, "onActivityPaused");
}
@Override
public void onActivityDestroyed(Activity activity) {
Logger.v(activity, "onActivityDestroyed");
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Logger.v(activity, "onActivityCreated");
}
});
};
</code></pre></li>
<li><p>运行结果(Logcat日志)</p>
<pre><code>10-21 14:32:57.722: V/WelcomeActivity(8085): onActivityCreated
10-21 14:32:57.762: V/WelcomeActivity(8085): onActivityStarted
10-21 14:32:57.762: V/WelcomeActivity(8085): onActivityResumed
10-21 14:32:59.164: V/WelcomeActivity(8085): onActivityPaused
10-21 14:32:59.194: V/MainActivity(8085): onActivityCreated
10-21 14:32:59.224: V/MainActivity(8085): onActivityStarted
10-21 14:32:59.224: V/MainActivity(8085): onActivityResumed
10-21 14:32:59.735: V/WelcomeActivity(8085): onActivityStopped
10-21 14:32:59.735: V/WelcomeActivity(8085): onActivityDestroyed
10-21 14:33:06.502: V/MainActivity(8085): onActivityPaused
10-21 14:33:06.612: V/MainActivity(8085): onActivityStopped
10-21 14:33:06.612: V/MainActivity(8085): onActivityDestroyed
</code></pre></li>
</ul>
<h2>ActivityLifecycleCallbacks的拓展用法</h2>
<ul>
<li><p>本次初探仅尝试使用Log日志工具作简要测试,如需满足较复杂的统计或调试需求时,此法可能会大大减少插入代码量,提高效率</p></li>
<li><p>API仅在14+版本上提供此接口回调,<a href="http://codego.net/456648/">Android 4.0以下系统如何使用?</a></p></li>
<li>API仅针对上述几个Activity的生命周期事件留出了接口回调,可能已无法满足日益过渡为使用Fragment的今日需求, <a href="https://github.com/soarcn/AndroidLifecyle">何在更大范围内应用LifecycleCallbacks?</a></li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Android下拉刷新和分段头悬停列表]]></title>
<link href="http://tongcpp.github.io/blog/2014/08/21/first-article/"/>
<updated>2014-08-21T16:13:33+08:00</updated>
<id>http://tongcpp.github.io/blog/2014/08/21/first-article</id>
<content type="html"><![CDATA[<h2>项目源码</h2>
<p>本文所述项目已开源,<a href="https://github.com/tongcpp/PullToRefresh-PinnedSection-ListView">源码地址</a></p>
<h2>为什么做PullToRefresh-PinnedSection-ListView</h2>
<p>前段时间因为项目需求,需要在Android中对ListView同时增加下拉刷新和分段头悬停的效果,受到<a href="https://github.com/dkmeteor">dkmeteor</a>的启发,Merge了两个Github上的开源项目:</p>
<ul>
<li><p><a href="https://github.com/chrisbanes/Android-PullToRefresh">Android-PullToRefresh</a>(handmark版,目前已不再更新)</p></li>
<li><p><a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a>(目前版本为2.x)</p></li>
</ul>
<p> 由于既有项目里的StickyListHeaders代码为1.x版本,StickyListHeadersListView继承自ListView,故与handmark版的PullToRefreshListView做merge时很顺畅;</p>
<p> 但2.x版的StickyListHeadersListView继承自FrameLayout,与PullToRefresh的融合并不顺利,若要整理拆分出一个独立的lib时遇到很多的问题,
故在分断头悬停需求上采用了另一个类似的开源项目:</p>
<ul>
<li><a href="https://github.com/beworker/pinned-section-listview">pinned-section-listview</a></li>
</ul>
<h2>我是如何做的</h2>
<p>前面已经介绍过这个过程是“很顺畅”的:</p>
<p>1.Library方面,基于PullToRefresh的Library修改,首先使其依赖StickyListHeaders的Library,通过拷贝src/com/handmark/pulltorefresh/library/PullToRefreshListView.java类,
新建PullToRefreshPinnedSectionListView.java类;</p>
<p>2.修改PullToRefreshPinnedSectionListView类中createListView()方法,注释以下代码</p>
<pre><code>// if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
// lv = new InternalListViewSDK9(context, attrs);
// } else {
// lv = new InternalListView(context, attrs);
// }
</code></pre>
<p>添加</p>
<pre><code>lv = new PinnedSectionListView(context, attrs);
</code></pre>
<p>3.Example方面,基于pinned-section-listview的example修改,令其依赖PullToRefresh的Library;</p>
<p>4.修改主类资源文件activity_main.xml,设置List组件为新类:</p>
<pre><code><com.handmark.pulltorefresh.library.PullToRefreshPinnedSectionListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:headerDividersEnabled="false"
android:footerDividersEnabled="false"
android:divider="@null"
/>
</code></pre>
<p>5.改写SampleActivity.java类中getListView()方法:</p>
<pre><code>mpPullToRefreshPinnedSectionListView = (PullToRefreshPinnedSectionListView) findViewById(R.id.list);
return mpPullToRefreshPinnedSectionListView.getRefreshableView();
</code></pre>
<p>即可通过</p>
<pre><code>ListView list = getListView();
</code></pre>
<p>继续进行原example其他操作,详情可阅读<a href="https://github.com/tongcpp/PullToRefresh-PinnedSection-ListView/blob/master/example/src/com/hb/examples/SampleActivity.java">项目代码</a></p>
<h2>另一种实现方式</h2>
<p>本例的实现方式依赖于handmark版下拉刷新组件的灵活性,更重要的一点,要求分段头悬停组件是继承自ListView实现;
故同理也可用handmark版下拉刷新组件和1.x版的StickyListHeaders组件实现;</p>
<p>另一种实现方式为<a href="https://github.com/dkmeteor/pull-to-refresh-sticky-list">pull-to-refresh-sticky-list</a>,
其采取合并的是2.x版的StickyListHeaders和johannilsson的android-pulltorefresh,实现形式不同,但效果类似,看过代码后实现起来也“相当顺畅”,有兴趣的同学可以参照此项目;</p>
<h2>建议</h2>
<p>建议在熟悉或使用过原有组件类库的前提下使用本类库。</p>
]]></content>
</entry>
</feed>