Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Dynamic List in LWUIT

4.83/5 (3 votes)
18 Nov 2013CPOL1 min read 8.5K   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.

Java
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:

Java
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.

Java
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:

C#
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:

Java
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.

Java
  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:

Java
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.

Java
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)