pageView扩展backbone

cAbstractApp定义view加载、切换、回退、跳转—webApp/cWebViewApp/hybirdApp为其子类

1、cWebApp扩展了父类的bindEvents,start,goTo,goBack,jump,judgeForward
2、webviewApp扩展了父类的bindEvents,_getCurrentView,start,goTo,goBack,startObserver,endObserver,judgeForward
3、hybridApp扩展了父类的bindEvents,start,loadFromRoute,_getCurrentView,goTo,goBack,jump,startObserver,endObserver,judgeForward
cBaseInit根据Lizard.pdConfig返回实例化abstractApp的方法。
不同环境加载的文件:
在APP,但不是hybrid方式:加载cHybridAppInit、cStatic、cBaseInit
Hybrid:加载cHybridAppInit、cBaseInit
其他方式:cWebAppInit

/**cWebInit的作用

  • define([‘cBaseInit’, ‘cWebMember’], function(initFunc, Member){
    Member.autoLogin({
    callback: function(){
    require([‘cStatic’], function(){
    initFunc()

    });
    }
    });
    })
    */
    一、backbone view的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * backbone view构造函数,
    * @param {[type]} options [description]
    */
    var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
    var View = Backbone.View = function(options) {
    this.cid = _.uniqueId('view');
    options || (options = {});
    _.extend(this, _.pick(options, viewOptions));
    this._ensureElement();
    this.initialize.apply(this, arguments);
    };

    1、_.uniqueId(‘c/view’)生成唯一cid;
    2、配置参数options;
    3、创建View实例;
    4、初始化。

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
_.extend(View.prototype, Events, {
// view的默认标签
tagName: 'div',
// 重定义$方法,在当前view查找元素
$: function(selector) {
return this.$el.find(selector);
},
// 初始化
initialize: function(){},
/**
*
* @return {[type]} [description]
*/
render: function() {
return this;
},
/**
* _ensureElement 创建View结构
* this._createElement:创建View结构
* this.setElement:对DOM元素进行事件解绑,定义this.$el与this.el,绑定
*/
_ensureElement: function() {
if (!this.el) {
var attrs = _.extend({}, _.result(this, 'attributes'));
if (this.id) attrs.id = _.result(this, 'id');
if (this.className) attrs['class'] = _.result(this, 'className');
this.setElement(this._createElement(_.result(this, 'tagName')));
this._setAttributes(attrs);
} else {
this.setElement(_.result(this, 'el'));
}
},
_createElement: function(tagName) {
return document.createElement(tagName);
},
_setAttributes: function(attributes) {
this.$el.attr(attributes);
},
/**
* 对View的DOM进行定义与事件处理
*/
setElement: function(element) {
this.undelegateEvents();
this._setElement(element);
this.delegateEvents();
return this;
},
/**
* Backbone.$ = $
* el是Backbone.$的实例
*/
_setElement: function(el) {
this.$el = el instanceof Backbone.$ ? el : Backbone.$(el);
this.el = this.$el[0];
},
/**
* events格式为{"event selector": "callback"}
* 循环events,如果method不是function,取this对象的method属性方法
* 不存在method,跳过此次循环
* match取出evnet与selector,_.bind的用法???
*/
delegateEvents: function(events) {
if (!(events || (events = _.result(this, 'events')))) return this;
this.undelegateEvents();
for (var key in events) {
var method = events[key];
if (!_.isFunction(method)) method = this[events[key]];
if (!method) continue;
// delegateEventSplitter = /^(S+)s*(.*)$/;
var match = key.match(delegateEventSplitter);
this.delegate(match[1], match[2], _.bind(method, this));
}
return this;
},
/**
* 解除View事件委托,根据.delegateEvents与cid
*/
undelegateEvents: function() {
if (this.$el) this.$el.off('.delegateEvents' + this.cid);
return this;
},
/**
* 为View添加事件委托eventName,根据.delegateEvents与cid
*/
delegate: function(eventName, selector, listener) {
this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
},
/**
* 解除View事件委托eventName,根据.delegateEvents与cid
*/
undelegate: function(eventName, selector, listener) {
this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener);
},
/**
* 移除this.$el,调用Events模块的stopListening
*/
remove: function() {
this._removeElement();
this.stopListening();
return this;
},
_removeElement: function() {
this.$el.remove();
},
}

二、基于backbone View的扩展
define([‘libs’,’header’, ‘cGuiderService’],
function (libs, Header, Guider) {
var PageView = Backbone.View.extend({
// 滚动条位置
scrollPos: { x: 0, y: 0 },
// 标题组件
header: null,
// web 环境下使用pageid
pageid: 0,
// hybrid 环境下使用hpageid
hpageid: 0,
// 页面切换时,是否要滚动至顶部
scrollZero: true,
// 页面切换时,是否执行onHide
triggerShow: true,
// 页面切换时,是否执行onHide
triggerHide: true,
initialize: function () {
this.id = this.$el.attr(“id”);
this.create();
},
// 生成头部
_createHeader: function () {
var hDom = $(‘#headerview’);
this.header = this.headerview = new Header({ ‘root’: hDom });
},
// create 方法,View首次初始化是调用
create: function () {
//调用子类onCreate
this.onCreate && this.onCreate();
},
// view 销毁方法
destroy: function () {
this.$el.remove();
},
// View 显示时调用的方法
show: function () {
// fix ios 页面切换键盘不消失的bug
document.activeElement && document.activeElement.blur();
//生成头部
this._createHeader();
//调用子类onShow方法
!this.switchByOut && this.$el.show();

    this.triggerShow && this.onShow && this.onShow();

    if (this.onBottomPull) {
this._onWidnowScroll = $.proxy(this.onWidnowScroll, this);
this.addScrollListener();
} if (this.scrollZero) {
window.scrollTo(0, 0);
} this.triggerShow = true;
this.triggerHide = true; //如果定义了addScrollListener,说明要监听滚动条事,此方法在cListView中实现
this.addScrollListener && this.addScrollListener();
},
// View 隐藏
hide: function () {
//调用子类onHide方法
this.triggerHide && this.onHide && this.onHide();
this.removeScrollListener && this.removeScrollListener();
this.$el.hide();
}, // 跨频道跳转
jump: function (opt) {
if (_.isString(opt)) {
window.location.href = opt;
} else {
Guider.jump(opt);
}
},
// 前进
forward: function (url, opt) {
Lizard.forward.apply(null, arguments);
},
// 回退至前一页面
back: function (url, opt) {
Lizard.back.apply(null, arguments);
},
// 刷新页面
refresh: function () { },
turning: function(){ },
// 唤醒App,要求返回一个app接受的字符串
getAppUrl: function () {
return "";
},
// 返回URL中参数的值
getQuery: function (key) {
return Lizard.P(key);
},
// 保存滚动条位置
saveScrollPos: function () {
this.scrollPos = {
x: window.scrollX,
y: window.scrollY
};
}, // 恢复原滚动条位置
restoreScrollPos: function () {
window.scrollTo(this.scrollPos.x, this.scrollPos.y);
},
// 获得页面Url,hyrbid会增加一个虚拟域名
_getViewUrl: function () {
var url = this._hybridUrl(location.href);
return url;
}, _hybridUrl: function(url) {
if (Lizard.isInCtripApp)
{
return 'http://hybridm.ctrip.com' + this.$el.attr('page-url');
} else {
return url;
}
}
})
return PageView;

});

三、view调用与切换:

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
// cPageModelProcessor负责处理viewCache
define(['cPageModelProcessor', 'cUtilPerformance', 'cUtilCommon', 'UILoadingLayer', (Lizard.isHybrid || Lizard.isInCtripApp) ? 'cHybridHeader' : 'UIHeader', 'UIWarning404', 'UIAlert', 'UIToast', 'cMessageCenter', 'UIAnimation', 'cPageParser'],
function (callModels, cperformance, utils, Loading, Header, Warning404, Alert, Toast, MessageCenter, animation) {
// cBaseInit实例化app,循环调用interface
function (options) {
this.initialize(options)
}
APP.subclasses = [], APP.defaults = {
"mainRoot": '#main',
"header": 'header',
"viewport": '.main-viewport',
"animForwardName": 'slideleft',
"animBackwardName": 'slideright',
"isAnim": false,
//是否开启动画
"maxsize": 10
}
APP.prototype = {
ctnrViewNames: ['lizardHisCtnrView'],
// 订阅viewReady
viewReady: function (handler) {
//TODO subscribe viewReady message
MessageCenter.subscribe('viewReady', handler);
},
initProperty: function initProperty(options) {
var opts = _.extend({}, APP.defaults, options || {});
return opts;
},
bindEvents: function () {
//l_wang提升响应速度
$.bindFastClick && $.bindFastClick();
//处理a标签
this._handleLink();
},
initialize: function initialize(options) {
// 初始化配置
var opts = 大专栏  create view and switch viewclass="keyword">this.initProperty(options);
this.options = opts;
this.firstState = null;
this.mainRoot = $(opts.mainRoot);
this.header = $(opts.header);
this.viewport = this.mainRoot.find(opts.viewport);
this.curView = null;
this.lastView = null;
//实例化cathViews组件
this.maxsize = opts.maxsize;
this.animForwardName = opts.animForwardName;
this.animBackwardName = opts.animBackwardName;
this.isAnim = opts.isAnim;
this.animAPIs = animation;
this.animatName = this.animForwardName;
// 定义基础UI
this._loading = new Loading();
this._alert = new Alert();
this._confirm = new Alert();
this._toast = new Toast();
this._warning404 = new Warning404();
//是否开启hashchange,false为不开启
this.observe = false;
this.headerView = new Header({ 'root': $('#headerview') });
// 绑定事件
this.bindEvents();
this.views = {};
this.start();
// 订阅switchview
MessageCenter.subscribe('switchview', function (inView, outView) {
inView.$el.show();
}, this);
},
// 链接跳转处理
_handleLink: function _handleLink() {
if (!Lizard.isHybrid && !utils.isSupportPushState) return;
$('body').on('click', $.proxy(function (e) {
var el = $(e.target);
var needhandle = false; while (true) {
if (!el[0]) break;
if (el[0].nodeName == 'BODY') break;
if (el.hasClass('sub-viewport')) break; if (el[0].nodeName == 'A') {
needhandle = true;
break;
}
el = el.parent();
} if (needhandle) {
var href = el.attr('href');
var opts = {};
var lizard_data = el.attr('lizard-data'); if ((el.attr('lizard-catch') == 'off') || (href && utils.isExternalLink(href))) {
return true;
}
e.preventDefault();
if (lizard_data) {
opts.data = JSON.parse(lizard_data);
}
if (el.attr('data-jumptype') == 'back') {
this.back(el.attr('href'), opts);
} else if (el.attr('data-jumptype') == 'forward') {
this.goTo(el.attr('href'), opts);
}
}
},
this));
},
// 切换view
switchView: function switchView(inView, outView) {
if (outView && !document.getElementById(outView.id) && (inView && !inView.switchByOut)) {
outView.$el.appendTo(this.viewport);
outView.$el.hide();
}
if (inView && !document.getElementById(inView.id)) {
inView.$el.appendTo(this.viewport);
inView.$el.hide();
}
//inView.$el.show();
//动画切换时执行的回调
var switchFn; //此处有问题,如果inView不再的话,应该由firstState生成默认页面
if (!inView) throw 'inview 未被实例化'; //将T 、P的值重新设置回去
Lizard.T.lizTmpl = inView.lizTmpl;
Lizard.P.lizParam = inView.lizParam; //outView不存在的情况下就不释放动画接口
if (outView) {
outView.saveScrollPos();
if (this.isAnim) {
switchFn = this.animAPIs[this.animatName];
}
//switchFn = this.animAPIs[this.animatName];
//未定义的话便使用默认的无动画
//l_wang 此段代码需要做一个包裹,或者需要回调,否则不会执行应该执行的代码!!!
inView.fromView = outView.config.viewName;
if (_.indexOf(this.ctnrViewNames, inView.config.viewName) > -1) {
MessageCenter.publish('showHisCtnrView');
outView.hideWarning404 = function () {
Lizard.goBack();
}
}
if (switchFn && _.isFunction(switchFn)) {
switchFn(inView, outView, $.proxy(function (inView, outView) {
this._onSwitchEnd(inView, outView);
},
this));
} else {
inView && !inView.switchByOut && outView.hide();
inView.show();
this._onSwitchEnd(inView, outView);
}
} else {
//这里开始走view的逻辑,我这里不予关注
if (_.indexOf(this.ctnrViewNames, inView.config.viewName) > -1) {
MessageCenter.publish('showHisCtnrView');
}
inView.show();
this._onSwitchEnd(inView, outView);
}
},
//l_wang 既然使用消息机制,就应该全部使用,后期重构
_onSwitchEnd: function (inView, outView) {
if (outView != inView && !inView.switchByOut) {
setTimeout(function () {
outView && outView.$el && outView.$el.hide()
}, 10);
}
inView.sendUbt(true);
MessageCenter.publish('viewReady', [inView]);
}, showView: function (data) {
this.loadView(data.url, data.text, data.options);
},
// 根据访问的URL是webapp或者html5不同,响应的数据也不同
// 根据服务器响应的数据,解析路由配置text/lizard-config,加载view
loadView: function (url, html, options) {
// 显示加载UI
if ((Lizard.config && Lizard.config.isHideAllLoading) || options.hideloading) {
this.hideLoading();
}
else {
this.showLoading();
}
Lizard.loadingView = true; if (url) {
// view是this.curView或者加载新页面
var view = this.curView || {
hpageid: '',
pageid:'',
_getViewUrl: function () {
return "";
},
_hybridUrl: function() {
if (Lizard.isInCtripApp)
{
return 'http://hybridm.ctrip.com' + url;
} else {
return ubtURL;
}
}
};
var ubtURL = window.location.protocol + '//' + window.location.host + (url.indexOf(Lizard.appBaseUrl) == 0?url: Lizard.appBaseUrl + url)
if (!window.__bfi) window.__bfi = [];
window.__bfi.push(['_unload', {
page_id: Lizard.isHybrid?view.hpageid: view.pageid,
url: view._hybridUrl(),
refer: view.$el?view._hybridUrl(window.location.protocol + '//' + window.location.host + view.$el.attr('page-url')):document.referrer
}]);
}
// cPageParser模块中的方法_initParser,负责找到script中的text/lizard-config
// 解析出viewName与controller、参数、模板、pageUrl
var pageConfig = Lizard._initParser(url, html);
// 根据pageConfig获取models
callModels(pageConfig, _.bind(function (datas, pageConfig) {
if (_.isFunction(this.judgeForward) && !this.judgeForward(url)) {
return;
}
Lizard.viewHtmlMap[renderObj.config.viewName] = html;
this.header.html(renderObj.header);
var renderNode = $('<DIV></DIV>').css({display: 'none'});
// 服务端,renderObj?
if (options.renderAt == 'server') {
this.hideLoading();
} else {
renderNode = $(renderObj.viewport).css({display: 'none'});
} if (renderObj.config.showfake && (!this.views[renderObj.config.viewName] || this.views[renderObj.config.viewName].$el.attr('page-url') != url)) {
if (_.isObject(renderObj.config.showfake) && renderObj.config.showfake.hideloading) {
this.hideLoading();
}
// renderNode与renderObj.viewport及this.viewport
Lizard.__fakeViewNode = renderNode.appendTo(this.viewport);
// 当前View
this.curView && this.curView.$el.hide();
}
// 加载controller
require([renderObj.config.controller||'cPageView'], _.bind(function (View) {
if (_.isFunction(this.judgeForward) && !this.judgeForward(url)) {
return;
}
// 把this.curView存入this.lastView
if (this.curView) this.lastView = this.curView;
if (renderObj.config.viewName && this.views[renderObj.config.viewName]) {
// 把要加载的view,存入this.curView
this.curView = this.views[renderObj.config.viewName];
if (this.curView.$el.attr('page-url') != url) {
this.curView.$el.remove();
!renderObj.config.showfake && renderNode.appendTo(this.viewport);
// 定义view节点
this.curView.$el = renderNode;
// 执行pageview中的onCreate
this.curView.onCreate && this.curView.onCreate();
this.curView.delegateEvents();
}
}
else {
!renderObj.config.showfake && renderNode.appendTo(this.viewport);
// 新的View
this.curView = new View({
el: (options.renderAt == 'server') ? this.viewport.children().first() : renderNode
});
// 设置view节点上的属性url
this.curView.$el.attr('page-url', url);
}
if (options.renderAt == 'server') renderNode.remove();
// __fakeViewNode??
Lizard.__fakeViewNode = null;
// 定义this.curView的属性
this.curView.text = html;
_.extend(this.curView, _.pick(renderObj, ['datas', 'config', 'lizTmpl', 'lizParam']));
// switchByOut??
if (this.curView && this.curView.switchByOut) {
var self = this;
// 重新定义turning
this.curView.turning = function () {
this.hideLoading();
// 隐藏上一个view,发布switchview,显示当前view
self.lastView && self.lastView.hide();
MessageCenter.publish('switchview', [self.curView, self.lastView]);
self.curView.$el.show();
}
}else {
this.hideLoading();
MessageCenter.publish('switchview', [this.curView, this.lastView]);
}
this.curView.lastViewId = this.curView.referrer = (this.lastView && this.lastView.config.viewName);
this.switchView(this.curView, this.lastView);
if (renderObj.config.viewName) {
this.views[renderObj.config.viewName] = this.curView;
}
}, this))
}, this), _.bind(function (datas, errorBack) {
this.hideLoading();
var errorData =
{
callback: function () {
this.hideWarning404();
Lizard.goTo(url);
},
headData: {
title: '网络不给力',
back: true,
events: {
returnHandler: function () {
Lizard.back();
}
}
}
};
if (errorBack) errorData = _.extend(errorData, errorBack(datas));
this.showWarning404(_.bind(errorData.callback, this), pageConfig, errorData);
}, this));
},
// 显示一个全局遮盖层
showHisCtnrView: function (onShow, onHide, options) {
if (!this.curView && !options.pageConfig) return;
if (!this.curView && options.pageConfig) options.addToHistory = false;
var oldAnimFlag = this.isAnim, oldAnimName = this.animatName;
if (this.curView) {
this.curView.triggerShow = this.curView.triggerHide = options?(!options.triggerFlag):true;
this.curView.triggerHide = options && ('triggerHide' in options) ?(options.triggerHide):true;
}
this.isAnim = (options && options.isAnim)?true:this.isAnim;
if (this.isAnim) {
this.animatName = this.animForwardName;
}
var config = _.clone(options.pageConfig?options.pageConfig:this.curView.config);
config.model.apis = [];
config.view = { viewport: '' };
config.controller = 'cPageView';
config.viewName = options && options.viewName?options.viewName:'lizardHisCtnrView';
if (_.indexOf(this.ctnrViewNames, config.viewName) == -1)
{
this.ctnrViewNames.push(config.viewName);
}
var url = options.pageConfig?options.pageConfig.pageUrl:this.curView.config.pageUrl;
if (!options || options.addToHistory !== false) {
if (Lizard.isHybrid || Lizard.isInCtripApp)
{
this.endObserver();
window.location.hash = '/lizardHisCtnrView';
} else {
history.pushState({url: url, text: ' <SCRIPT type="text/lizard-config">' + JSON.stringify(config) + '<' + '/SCRIPT>', options: {pushState: true}}, document.title, url);
}
}
this.loadView(url, ' <SCRIPT type="text/lizard-config">' + JSON.stringify(config) + '<' + '/SCRIPT>', { pushState: true, hideloading: true });
if (Lizard.isHybrid || Lizard.isInCtripApp)
{
setTimeout(_.bind(this.startObserver, this), 1);
}
var headData = {};
MessageCenter.unsubscribe('showHisCtnrView');
MessageCenter.subscribe('showHisCtnrView', function () {
var self = this;
this.lizardHisCtnrView = this.curView;
this.curView.onShow = function () {
if (self.lastView && !_.isEmpty(self.lastView.header.datamodel)) {
headData = _.clone(self.lastView.header.datamodel);
headData.events.returnHandler = function () { history.back(); };
}
this.header.set(headData);
onShow && onShow.apply(this, arguments);
setTimeout(function(){
self.animatName = self.animBackwardName;
}, 10);
};
this.curView.onHide = function () {
onHide && onHide.apply(this, arguments);
setTimeout(function(){
self.isAnim = oldAnimFlag;
self.animatName = oldAnimName;
}, 10)
};
this.curView.show();
}, this)
},
// 隐藏遮盖层
hideHisCtnrView: function()
{
history.back();
}, interface: function () {
return {
'viewReady': this.viewReady,
// 'showMessage': this.showMessage,
// 'hideMessage': this.hideMessage,
// 'showConfirm': this.showConfirm,
// 'hideConfirm': this.hideConfirm,
// 'showWarning404': this.showWarning404,
// 'hideWarning404': this.hideWarning404,
// 'showToast': this.showToast,
// 'hideToast': this.hideToast,
// 'showLoading': this.showLoading,
// 'hideLoading': this.hideLoading,
'showHisCtnrView': this.showHisCtnrView,
'hideHisCtnrView': this.hideHisCtnrView,
"goTo": this.goTo,
"goBack": this.goBack,
"forward": this.goTo,
"back": this.goBack,
"go": this.go
}
}
}
})

create view and switch view的更多相关文章

  1. SAP技术 - How to create a CDS redirect view for a given database table

    Scenario Suppose we have a database table A, and then we create a CDS redirect view B for it, then e ...

  2. View事件传递之父View和子View之间的那点事

    Android事件传递流程在网上可以找到很多资料,FrameWork层输入事件和消费事件,可以参考: Touch事件派发过程详解 这篇blog阐述了底层是如何处理屏幕输,并往上传递的.Touch事件传 ...

  3. Android-自定义View前传-View的三大流程-Layout

    Android-自定义View前传-View的三大流程-Layout 参考 <Android开发艺术探索> https://github.com/hongyangAndroid/FlowL ...

  4. Android自定义View前传-View的三大流程-Measure

    Android自定义View前传-View的三大流程-Measure 参考 <Android开发艺术探索> https://developer.android.google.cn/refe ...

  5. 通过圆形载入View了解自定义View

    这是自定义View的第一篇文章,通过制作简单的自定义View来了解自定义View的流程. 自定义View是Android学习和开发中必不可少的一部分.通过自定义View我们可以制作丰富绚丽的控件,自定 ...

  6. UISearchController Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior

    Attempting to load the view of a view controller while it is deallocating is not allowed and may res ...

  7. Controller将Model数据传给View层,View层应该如何处理?

    首先,我们在Model层中添加一个Person类. namespace MVCTest.Models{    public class Person    {        public string ...

  8. 使用android.view.TouchDelegate扩大View的触摸点击区域

    Android4.0设计规定的有效可触摸的UI元素标准是48dp,转化为一个物理尺寸约为9毫米.7~10毫米,这是一个用户手指能准确并且舒适触摸的区域. 如下图所示,你的UI元素可能小于48dp,图标 ...

  9. 通过View.post()获取View的宽高

    在Android里,获取View宽高的时机是个老生常谈的话题了.众所周知,在Oncreate里直接调用View.getWidth或者View.getMeasuredWidth返回都是0.所以获取宽高时 ...

随机推荐

  1. C#的静态方法和实例化方法的区别

    C#的静态方法和实例化方法的区别 在大多数时候,我们写一个方法,会把方法区分为实例化方法和静态方法.而当被问到静态方法和实例化方法的区别的时候,我在写这篇文章的前10分钟,或许我会回答:"静 ...

  2. 量化投资_TB交易开拓者A函数和Q函数常见组合应用

    1 在交易开拓者当中,关于交易的做单方式一般分为:图表函数和A函数两类. 两类的主要区别为:如果采用图表函数的话,所有的交易内容都是以图表上面的信号为准,当前仓位运行的实际状态是没有的,但是可以显示交 ...

  3. jmeter 配置csv 登陆网站 报错

    0 环境 系统环境:win7 1 正文 1 问题 创建csv 格式为utf-8后 jmeter csv配置好后 post请求登陆报错 2 解决 查看了一下报告 post请求里用户名乱码了 仔细一看网站 ...

  4. Ubuntu16.04中Mysql 5.7 安装配置

    记录在Ubuntu 16.04安装Mysql 5.7时遇到的一些问题. Mysql安装 使用如下命令进行安装: 1 sudo apt-get install mysql-server mysql-cl ...

  5. MySQL数据库简单操作

    title date tags layout MySQL简单操作 2018-07-16 Linux post 登录mysql mysql -h 主机名 -u 用户名 -p 查看所有数据库 show d ...

  6. android采用MVP完整漫画APP、钉钉地图效果、功能完善的音乐播放器、仿QQ动态登录效果、触手app主页等源码

    Android精选源码 一个可以上拉下滑的Ui效果,觉得好看可以学学 APP登陆页面适配 一款采用MVP的的完整漫画APP源码 android实现钉钉地图效果源码 一个使用单个文字生成壁纸图片的app ...

  7. windows下面apache配置虚拟目录(测试使用,发布网站不建议目录访问)

    windows下面是这样简单设置 1 Apache虚拟目录: 针对某一目录可以这么设置: Alias /aidd2008 "D:/php/web/aidd2008" <Dir ...

  8. iOS路由详解

    本文如题,路由详解,注定是一篇详细解释iOS路由原理及使用的文章,由于此时正在外地出差,无法详细一一写出,只能不定时的补充. 一.什么是iOS路由 路由一词来源于路由器,可以实现层级之间消息转发的功能 ...

  9. 奇点云 x 阿里云 | 联合发布综合体数字化转型与数据创新解决方案

    2019年7月25日下午,在阿里云峰会上海站,奇点云入选阿里云首批联合解决方案合作伙伴,并联合发布了“综合体数字化转型与数据创新解决方案”,共同探索综合体的智能服务. 关于综合体的数字化转型,奇点云联 ...

  10. java第二节课 java语法基础动手动脑

    动手动脑1:枚举变量   运行EnumTest.java package test2; public class EnumTest {  public static void main(String[ ...