65.9K
CodeProject is changing. Read more.
Home

Dynamic List in LWUIT

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (3 votes)

Nov 18, 2013

CPOL

1 min read

viewsIcon

8492

downloadIcon

63

Dynamic list in LWUIT

Introduction

LWUIT has List Component, but items have the same height, I will show you how to make it dynamic height.

Background

(Optional) You need knowledge of LWUIT lib and J2ME.

Using the Code

Cal. height of List Dynamic

Normal, LWUIT get item has max height in Model, and multiply it with model size. We will cal. height each item in model with method calculateElementSize.

 private Dimension calculateElementSize(boolean selected, boolean addMargin) {
        int width = 0;
        int height = 0;
        int elements = Math.min(listSizeCalculationSampleCount, model.getSize());
        int marginY = 0;
        int marginX = 0;
        for (int iter = 0; iter < elements; iter++) {
            Component cmp = renderer.getListCellRendererComponent
                            (this, model.getItemAt(iter), iter, selected, true);
            if (cmp instanceof Container) {
                cmp.setShouldCalcPreferredSize(true);
            }
            Dimension d = cmp.getPreferredSize();
            width = Math.max(width, d.getWidth());
            height = Math.max(height, d.getHeight());
            if (iter == 0) {
                Style s = cmp.getStyle();
                marginY = s.getMargin(TOP) + s.getMargin(BOTTOM);
                marginX = s.getMargin(LEFT) + s.getMargin(RIGHT);
            }
        }
        return new Dimension(width + marginX, height + marginY);
    } 

This function only runs 1 time, but it will be called by paint, many times - by method getElementSize, so will need modify this method too:

public Dimension getElementSize(boolean selected, boolean addMargin) {

        if (selected) {
            if (selectedElemSize == null) {
                // don't keep element size if there are no elements and no prototype...
                if (model.getSize() == 0) {
                    // put a sensible value as default when there are no elements or rendering prototype
                    if (addMargin) {
                        return new Label("XXXXXX").getPreferredSizeWithMargin();
                    }
                    return new Label("XXXXXX").getPreferredSize();
                }
                selectedElemSize = calculateElementSize(true, addMargin);
            }
            return selectedElemSize;
        } else {
            if (elemSize == null) {
                // don't keep element size if there are no elements and no prototype...
                if (model.getSize() == 0) {
                    // put a sensible value as default when there are no elements or rendering prototype
                    Label l = new Label("XXXXXX");
                    if (addMargin) {
                        return l.getPreferredSizeWithMargin();
                    } else {
                        return l.getPreferredSize();
                    }
                }
                elemSize = calculateElementSize(false, addMargin);
            }
            return elemSize;
        }
    }

Done. The height of List, now we cal. each item in Model.

private int calculateElementSize(boolean selected, boolean addMargin, int index, Component cmp) {
        int height = 0;
        int marginY = 0;
        if (isChatRenderCell) {
            Dimension d = getHeightComponent(this, model.getItemAt(index), index);
            if (d != null) {
                height = d.getHeight();
            }
        } else {
            if (cmp == null) {
                cmp = renderer.getListCellRendererComponent
                      (this, model.getItemAt(index), index, selected, true);
            }
            if (cmp instanceof Container) {
                cmp.setShouldCalcPreferredSize(true);
            }
            height = cmp.getPreferredSize().getHeight();
        }
        return height + marginY;
    } 

This method will be called by:

public HashInteger elementSizeCached = new HashInteger();

public int getElementSize(boolean selected, boolean addMargin, int index, Component cmp) {
        if (!isDynamicHeight) {
            if (HEIGHT_FIXXED < 1) {//merge from TYPE, HEIGHT_FIXXED can equal 0
                HEIGHT_FIXXED = calculateElementSize(true, addMargin, index, cmp);
            }
            return HEIGHT_FIXXED;
        }
        if (getModel().getSize() <= 2) {
            if (selected) {
                return calculateElementSize(true, addMargin, index, cmp);
            } else {
                return calculateElementSize(false, addMargin, index, cmp);
            }
        }
        if (elementSizeCached != null) {
            if (elementSizeCached.containsKey(index)) {
                return elementSizeCached.get(index);
            } else {
                int selectedElemSize = calculateElementSize(true, addMargin, index, cmp);
                if (enableCache && selectedElemSize != 0) {
                    elementSizeCached.put(index, selectedElemSize);
                }
                return selectedElemSize;
            }
        } else {
            return calculateElementSize(true, addMargin, index, cmp);
        }
    } 

You need:

public HashInteger elementSizeCached = new HashInteger(); 

It's cached....

We will replace all getElementSize on default code of LWUIT by our method.

And, every time LWUIT paint item, it will cal, position, height...we will modify this.

  public void calculateComponentPosition(int index, int defaultWidth, 
Rectangle rect, Dimension rendererSize, Dimension selectedSize, boolean beforeSelected) {
        Style style = getStyle();
        int initialY = 0;
        int initialX = style.getPadding(false, LEFT);
        boolean rtl = isRTL();
        if (rtl) {
            initialX += getSideGap();
        }
        int selection = getCurrentSelected();
        if (rect == null) {
            return;
        }
        Dimension d = rect.getSize();
        int selectedDiff;
        if (rendererSize == null) {
            return;
        }
        if (selectedSize == null) {
            return;
        }
        int height = rendererSize.getHeight();
        selectedDiff = selectedSize.getHeight() - height;
        rect.setX(initialX);
        d.setHeight(height);
        d.setWidth(defaultWidth);
        int y = 0;
        //Chat List
        if (index == 0) {
            y = 0;
        } else {
            if (!isDynamicHeight) {
                if (HEIGHT_FIXXED == -1) {
                    HEIGHT_FIXXED = getElementSize(false, true, index, null);
                }
                y = (index) * HEIGHT_FIXXED;
            } else {
                if (positionElement != null && positionElement.containsKey(index)) {
                    y = positionElement.get(index);
                } else {
                    if (positionElement != null && positionElement.containsKey(index)) {
                        y = positionElement.get(index);
                        y += getElementSize(false, true, index - 1, null);
                    } else {
                        int prevIndex = index - 1;
                        if (prevIndex == 0) {
                            y = getElementSize(false, true, 0, null);
                        } else if (positionElement.containsKey(prevIndex)) {
                            int postion = positionElement.get(prevIndex);
                            y += (postion + getElementSize(false, true, prevIndex, null));
                        } else {
                            //bad performance
                            for (int i = 0; i < index; i++) {
                                y += getElementSize(false, true, i, null);
                            }
                        }
                    }
                }
                if (enableCache) {
                    positionElement.put(index, y);
                }
            }
        }
        rect.setY(y + initialY);
        if (index == selection) {
            d.setHeight(d.getHeight() + selectedDiff);
        }
    } 

Very simple, we will see:

public HashInteger positionElement = new HashInteger(); 

It's cached....

LWUIT has painted a item which shows on viewport of screen, and this will be calc by pointerSelect.

 public int pointerSelect(int x, int y) {
        Style style = getStyle();
        y = y - getAbsoluteY();
        Dimension rendererSize = null;
        int width = getWidth() - style.getPadding(isRTL(), 
        RIGHT) - style.getPadding(isRTL(), LEFT) - getSideGap();
        Rectangle pos = new Rectangle();
        for (int i = getEndBufferOffset(); i >= getStartBufferOffset(); i--) {
            rendererSize = new Dimension(DEFAULT_WIDTH, 
            getElementSize(true, true, i, null));
            calculateComponentPosition(i, width, pos, 
            rendererSize, rendererSize, i <= getCurrentSelected());
            if (y >= pos.getY() && 
            	y <= pos.getY() + rendererSize.getHeight()) {
                return i;
            }
        }
        return getModel().getSize();
    } 

At this point, basically, all items have a height of up... and remember "clear cached if your model has changed"....

You can download the zip file from the link at the top of this article.

Enjoy it!

Thanks.