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());
List newData = 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;
}
}
댓글 없음:
댓글 쓰기