DataGrid 에서 ScrollPanel 을 접근하는 방법은 ref. 1 에서
ScrollHandler 에 대한 code 는 ref.2 에서 찾을 수 있다.
ref. 2 의 경우는 모든 data 를 한번에 load 해 놓은 상태에서 조금씩 보여주는 경우이다. 만약 scroll 을 통해 server 에 request 를 해서 load more 를 하려고 하는 것이라면 ref. 1 을 참고하자.
아래에 AsyncDataProvider<T> 와 자동으로 load more 를 하는 scroll 을 이용한 예제이다.
Flow
code 의 흐름은 대략적으로 아래와 같다.DataProvider.addDataDisplay() >> onRangeChanged >> updateRowData >> newPage + getRowCount() >> setVisibleRange()
addDataDisplay() 사용시 주의점
만약에 DataProvider 를 새롭게 만들어서 사용하려고 한다면, 잊지말고 removeDataDisplay() 를 해주도록 하자.DataProvider 를 새로 만들어서 사용하는데, 그전의 DataProvider 가 사라지지 않아서 살펴보니 addDataDisplay(display) 를 하게 되면, DataProvider 의 addRangeChangeHandler 부분에서 DataProvider 를 사용하고 있어서 display 가 사라지지 않는 이상 DataProvider 를 붙잡고 있는 것 같다.
public void addDataDisplay(final HasData<T> display) {
...
// Add a handler to the display.
HandlerRegistration handler = display.addRangeChangeHandler(
new RangeChangeEvent.Handler() {
public void onRangeChange(RangeChangeEvent event) {
AbstractDataProvider.this.onRangeChanged(display);
}
});
그래서 아래와 같은 방식으로 coding 을 하는 것이 좋다.
public void init(int requestLimit, int productId, HasData<DomainInfo> ... newDisplays) { if(newDisplays == null) return; if(dataProvider != null && this.displays != null){ for(HasData<DomainInfo> d : this.displays){ dataProvider.removeDataDisplay(d); d.setRowCount(0); d.setVisibleRange(0, requestLimit); } } dataProvider = new DomainAsyncDataProvider(requestLimit); for(HasData<DomainInfo> d : newDisplays){ dataProvider.addDataDisplay(d); } dataProvider.setProductId(productId); this.displays = newDisplays; }
예제
private DomainAsyncDataProvider dataProvider = new DomainAsyncDataProvider(); // How to use dataGrid = new DataGridExtended<DomainInfo>(DomainInfo.KEY_PROVIDER); /** * * This must be equal to the {@val #incrementSize}. * * Please refer to the comment "About Increment size." * in {@link ProductOverviewActivity#setUpActivity} */ final int INCREMENT_SIZE = 10; dataGrid.setIncrementSize(INCREMENT_SIZE); dataProvider.setRequestLimit(INCREMENT_SIZE); dataGrid.setVisibleRange(0, dataGrid.getIncrementSize()); dataGrid.addLoadMoreScrollHandler(); dataProvider.addDataDisplay(display); // onRangeChanged event 를 발생시킨다.
DomainAsyncDataProvider
setVisibleRange() 가 호출되면, onRangeChanged event 가 발생한다.// DomainAsyncDataProvider.java public class DomainAsyncDataProvider extends AsyncDataProvider<DomainDatabase.DomainInfo> { private static int DEFAULT_INCREMENT_SIZE = 10; private int requestLimit = DEFAULT_INCREMENT_SIZE; private int lastRowCount = 0; private int lastRangeLength = 0; private static int testCount = 0; public void setRequestLimit(int size){ this.requestLimit = size; } @Override protected void onRangeChanged(HasData display) { // Get the new range. final Range range = display.getVisibleRange(); /* * Query the data asynchronously. If you are using a database, you can * make an RPC call here. We'll use a Timer to simulate a delay. */ final int start = range.getStart(); final int length = range.getLength(); // range length grows by the setVisibleRange in // {@ref DataGridExtended#addLoadMoreScrollHandler} ParamForStatsData param = new ParamForStatsData(); param.set(NewStatsParamKey.PRODUCT_ID, productId); param.set(NewStatsParamKey.START_INDEX, StartIndexOfUpdateRow); param.set(NewStatsParamKey.LIMIT, requestLimit); new RequestDomains(param, new RequestCallback() { @Override public void onResponseReceived(Request req, Response res) { if (200 == res.getStatusCode()) { final DomainsJavaScriptObject domainsJson = JsonUtils.safeEval(res.getText()); ListnewData = new ArrayList (); // the below Math.min() covers the case // that the size of the received has more than {@val requestLimit} int len = Math.min(domainsJson.getSize(), requestLimit); for ( int i = 0; i < len; i++ ){ // create data newData.add( new DomainInfo( domainsJson.getDomainSeq(i), domainsJson.getPathId(i), domainsJson.getDomain(i), domainsJson.getPath(i), domainsJson.getStatus(i)) ); } updateRowData(StartIndexOfUpdateRow, newData); } } @Override public void onError(Request request, Throwable exception) { } }).send(); } }
DataGridExtended<T>
load more 를 지원하는 scrollhandler 를 구현했다.// DataGridExtended<T>
public class DataGridExtended<T> extends DataGrid {
/**
* The last scroll position.
*/
private int lastScrollPos = 0;
/**
* The default increment size.
*/
private static final int DEFAULT_INCREMENT = 20;
/**
* The increment size.
*/
private int incrementSize = DEFAULT_INCREMENT;
public DataGridExtended(ProvidesKey<T> keyProvider) {
super(keyProvider);
}
public ScrollPanel getScrollPanel() {
HeaderPanel header = (HeaderPanel) getWidget();
return (ScrollPanel) header.getContentWidget();
}
public void addLoadMoreScrollHandler(){
final ScrollPanel scrollPanel = getScrollPanel();
scrollPanel.addScrollHandler(new ScrollHandler() {
@Override
public void onScroll(ScrollEvent event) {
// If scrolling up, ignore the event.
int oldScrollPos = lastScrollPos;
lastScrollPos = scrollPanel.getVerticalScrollPosition();
if (oldScrollPos >= lastScrollPos) {
return;
}
// Height of grid contents (including outside the viewable area) - height of the scroll panel
int maxScrollTop = scrollPanel.getWidget().getOffsetHeight() -
scrollPanel.getOffsetHeight();
if (lastScrollPos >= maxScrollTop) {
/**
* {@link #getRowCount()} is determined by the {@link #updateRowCount()}
*
* The below statement assumes that
* the getRowCount() and getLength() is same in usual cases.
*
* This can be the stop condition, but the known issue is that this will make
* the {@link #onRangeChanged} NOT called any more.
*
*
* Math.min(getRowCount(), ..) is used to make the newPageSize
* have same value as the last newPageSize, which is used for not calling #onRangeChange.
* If the getRowCount() has same as the last getRowCount(), newPageSize value would be same as
* the last one. Thus the setVisibleRange() does not call {@link AsyncDataProvider#onRangeChange}
*
*/
// final int newPageSize
// = Math.min(DataGridExtended.this.getRowCount(),
// DataGridExtended.this.getVisibleRange().getLength())
// + incrementSize;
final int newPageSize
= DataGridExtended.this.getRowCount() + incrementSize;
/**
* If newPageSize is different from existing page size,
* this invokes the function {@link com.google.gwt.view.client.AsyncDataProvider#onRangeChanged()}
*/
DataGridExtended.this.setVisibleRange(0, newPageSize);
}
}
});
}
/**
* Get the number of rows by which the range is increased when the scrollbar
* reaches the bottom.
*
* @return the increment size
*/
public int getIncrementSize() {
return incrementSize;
}
/**
* Set the number of rows by which the range is increased when the scrollbar
* reaches the bottom.
*
* @param incrementSize the incremental number of rows
*/
public void setIncrementSize(int incrementSize) {
this.incrementSize = incrementSize;
}
}
댓글 없음:
댓글 쓰기