編輯:關於Android編程
這一年都在使用ExtJS 5.0開發系統,經常會遇到的一個場景就是時間日期的選擇了。比如說,預定場地的時候就必須由用戶選擇預定的日期和時間。
可惜的是,ExtJS 5.0沒有自帶一個可以同時選擇日期時間的控件(ExtJS 6.0已經推出了,還沒用過,不知道加入這種控件沒~),通常偷懶的做法就是,先放一個日期控件,然後再放一個時間控件。用戶使用的時候,先選擇日期,再選擇時間,最後用很別扭的辦法將日期和時間拼裝起來。
理想的狀態是,提供給用戶一個可以同時選擇時間和日期的控件,並且數據是“日期+時間”的Date類型。既符合使用習慣,又方便開發。
故第二種偷懶的方式是,從網上扒一個現成的解決方案來用。此法最快,但是在過程中遇到了一個問題,現成可以搜索到的方案都有點舊,大多數還停留在ExtJS 2.X、3.X和4.X版本,自從ExtJS從4升級到5之後,API改變了許多,所以並不能直接使用。
最後只能是自己寫一個。准確來說,應該是拿了一份現成的代碼修改,這個代碼在ExtJS 5.0下不能正確運行,但是需要修改的量非常少,所以很感謝這份現成代碼的作者,可惜沒有署名,不知道是誰。
ExtJS 5.0上測試成功,實現方法是:
Ext.define('MyApp.ux.DateTimeField.TimePickerField', {
extend: 'Ext.form.field.Base',
alias: 'widget.timepicker',
alternateClassName: 'Ext.form.field.TimePickerField',
requires: ['Ext.form.field.Number'],
inputType: 'text',
fieldLabel: '時間',
labelWidth: 40,
style: 'padding:4px 0; margin: 0; ',
value: null,
spinnerCfg: {
width: 50,
},
initComponent: function() {
var me = this;
me.value = me.value || Ext.Date.format(new Date(), 'H:i:s');
me.callParent(arguments);
me.spinners = [];
var cfg = Ext.apply({}, me.spinnerCfg, {
// readOnly: me.readOnly,
disabled: me.disabled,
style: 'float: left',
listeners: {
change: {
fn: me.onSpinnerChange,
scope: me
}
}
});
me.hoursSpinner = Ext.create('Ext.form.field.Number', Ext.apply({}, cfg, {
// minValue: -1,
// maxValue: 24,
minNum: 0,
maxNum: 23,
}));
me.minutesSpinner = Ext.create('Ext.form.field.Number', Ext.apply({}, cfg, {
// minValue: -1,
// maxValue: 60,
minNum: 0,
maxNum: 59,
}));
me.secondsSpinner = Ext.create('Ext.form.field.Number', Ext.apply({}, cfg, {
// minValue: -1,
// MAXVALUE: 60,
minNum: 0,
maxNum: 59,
}));
me.spinners.push(me.hoursSpinner, me.minutesSpinner, me.secondsSpinner);
},
onRender: function() {
var me = this, spinnerWrapDom, spinnerWrap;
me.callParent(arguments);
spinnerWrap = Ext.get(Ext.DomQuery.selectNode('div', this.el.dom));
me.callSpinnersFunction('render', spinnerWrap);
this.el.dom.getElementsByTagName('input')[0].style.display = 'none';
var newTimePicker = Ext.DomHelper.append(spinnerWrap, {
tag: 'div',
cls: 'x-form-clear-left'
}, true);
this.setRawValue(this.value);
},
_valueSplit: function(v) {
if(Ext.isDate(v)) {
v = Ext.Date.format(v, 'H:i:s');
}
var split = v.split(':');
return {
h: split.length > 0 ? split[0] : 0,
m: split.length > 1 ? split[1] : 0,
s: split.length > 2 ? split[2] : 0
};
},
onSpinnerChange: function() {
if(!this.rendered) {
return;
}
//限制時間范圍
var args = arguments; //this, newValue, oldValue, eOpts
args[0].setValue( (args[1]>args[0].maxNum) ? args[0].minNum : args[0].value );
args[0].setValue( (args[1]<args[0].minnum) ?="" args[0].maxnum="" :="" args[0].value="" );="" this.fireevent('change',="" this,="" this.getvalue(),="" this.getrawvalue());="" },="" 依次調用各輸入框函數,="" call="" each="" spinner's="" function="" callspinnersfunction:="" function(funname,="" args)="" {="" for(var="" i="0;"
2、自定義一個DateTimePicker,繼承自Ext.picker.Date,實際上就是在原有的DateField的基礎上增加TimePicker和一個確認按鍵。
Ext.define('MyApp.ux.DateTimeField.DateTimePicker', {
extend: 'Ext.picker.Date',
alias: 'widget.datetimepicker',
requires: ['MyApp.ux.DateTimeField.TimePickerField','Ext.dom.Query'],
todayText: '現在',
timeLabel: '時間',
buttonText: '確定',
initComponent: function() {
this.callParent();
this.value = this.value || new Date();
},
onRender: function(container, position) {
this.callParent(arguments);
var me = this;
//確認按鍵
var btnCfg = Ext.apply({}, {}, {
style: 'center',
listeners: {
click: {
fn: function(){
this.confirmDate();
},
scope: me
}
}
});
me.confirmBtn = Ext.create('Ext.Button', Ext.apply({}, btnCfg, {
text: '確認',
}));
me.confirmBtn.render(this.el.child('div div.x-datepicker-footer'));
if(!this.timefield) {
this.timefield = Ext.create('MyApp.ux.DateTimeField.TimePickerField', {
fieldLabel: this.timeLabel,
labelWidth: 40,
value: Ext.Date.format(this.value, 'H:i:s'),
});
}
this.timefield.ownerCt = this;//指定范圍
this.timefield.on('change', this.timeChange, this);//
var table = Ext.get(Ext.DomQuery.selectNode('table', this.el.dom));
var tfEl = Ext.DomHelper.insertAfter(table, {
tag: 'div',
style: 'border:0px;',
children: [{
tag: 'div',
cls: 'x-datepicker-footer ux-timefield'
}]
}, true);
this.timefield.render(this.el.child('div div.ux-timefield'));
var p = this.getEl().parent('div.x-layer');
if(p) {
p.setStyle("height", p.getHeight() + 31);
}
},
// listener 時間域修改, timefield change
timeChange: function(tf, time, rawtime) {
this.value = this.fillDateTime(this.value);
},
fillDateTime: function(value) {
if(this.timefield) {
var rawtime = this.timefield.getRawValue();
value.setHours(rawtime.h);
value.setMinutes(rawtime.m);
value.setSeconds(rawtime.s);
}
return value;
},
changeTimeFiledValue: function(value) {
this.timefield.un('change', this.timeChange, this);
this.timefield.setValue(this.value);
this.timefield.on('change', this.timeChange, this);
},
setValue: function(value) {
this.value = value;
this.changeTimeFiledValue(value);
return this.update(this.value);
},
getValue: function() {
return this.fillDateTime(this.value);
},
handleDateClick: function(e, t) {
var me = this,
handler = me.handler;
e.stopEvent();
if(!me.disabled && t.dateValue && !Ext.fly(t.parentNode).hasCls(me.disabledCellCls)) {
me.doCancelFocus = me.focusOnSelect === false;
me.setValue(this.fillDateTime(new Date(t.dateValue)));
delete me.doCancelFocus;
me.fireEvent('select', me, me.value);
if(handler) {
handler.call(me.scope || me, me, me.value);
}
me.onSelect();
}
},
//確認按鍵
confirmDate: function(){
var that = this;
that.fireEvent('select', that, that.value);//模擬用戶選擇
that.onSelect();
},
selectToday: function() {
var me = this,
btn = me.todayBtn,
handler = me.handler;
if(btn && !btn.disabled) {
me.setValue(new Date());
me.fireEvent('select', me, me.value);
if(handler) {
handler.call(me.scope || me, me, me.value);
}
me.onSelect();
}
return me;
}
});
3、將DateTimePicker裝載到Ext.form.field.Date中,初始化日期時間的格式。
Ext.define('MyApp.ux.DateTimeField.DateTimeField', {
extend: 'Ext.form.field.Date',
alias: 'widget.datetimefield',
requires: ['MyApp.ux.DateTimeField.DateTimePicker'],
initComponent: function() {
this.format = this.format;
this.callParent();
},
format: 'Y-m-d H:i:s',
createPicker: function() {
var me = this,
format = Ext.String.format;
return Ext.create('MyApp.ux.DateTimeField.DateTimePicker', {
ownerCt: me.ownerCt,
// renderTo: document.body,
floating: true,
// hidden: true,
focusOnShow: true,
minDate: me.minValue,
maxDate: me.maxValue,
disabledDatesRE: me.disabledDatesRE,
disabledDatesText: me.disabledDatesText,
disabledDays: me.disabledDays,
disabledDaysText: me.disabledDaysText,
format: me.format,
showToday: me.showToday,
startDay: me.startDay,
minText: format(me.minText, me.formatDate(me.minValue)),
maxText: format(me.maxText, me.formatDate(me.maxValue)),
listeners: {
scope: me,
select: me.onSelect
},
keyNavConfig: {
esc: function() {
me.collapse();
}
}
});
}
});
將以上代碼拷到ux當中,調用的時候可以Ext.create之,也可以require之後直接使用alias。
效果嘛,就像下圖那樣:
介紹完畢。
圖片的拖拉功能是處理圖片進一個有用且常用的功能,由於手機屏幕尺寸的限制,往往無法在手機上一次性的顯示一張比較大的圖片,也就是 說,我們在手機上一次性只能看到圖片的一部分,
功能1、顯示加載視圖,加載失敗的時候顯示加載失敗視圖,數據為空時顯示數據為空視圖,支持為失敗視圖設置點擊事件重新加載數據。2、支持個性化設置,自定義設置 加載、失敗、空數
Android 橫豎屏切換的Activity生命周期,很多公司和企業面試會問到橫豎屏切換的Activity生命周期、Handler機制、單例模式 等,不過這幾個是常問的,
通常情況下,作為一個android開發者不會直接接觸到Binder,但Binder作為ipc機制最關鍵的一個環節,我們很有必要去了解他。其實在不知不覺中,大家肯定和Bin