SNS UI Sample Overview

Mobile native

The [UI Sample] SNS sample application demonstrates how to make a complex view by recursive composition of standard EFL UI components and containers in a UI component hierarchy.

The sample uses UI components, such as elm_conform, elm_naviframe, elm_scroller, elm_toolbar, and elm_panel for the view management, containers, such as elm_table and elm_box for the UI component management inside the view, and UI components, such as elm_button, elm_label, elm_genlist, and elm_gengrid for the content inside the view.

The following figure illustrates the SNS view, its wireframe structure, and the UI component tree.

Figure: SNS view

SNS view

SNS view UI component tree

Application Layout

The create_base_gui() function creates the window, conformant, and naviframe. It also creates the view layout and drawer (elm_panel). The drawer is inserted in the layout. The drawer button is inserted in the naviframe.

static void
create_base_gui(appdata_s *ad)
{
   Evas_Object *layout, *bg, *drawer, *btn;
   Elm_Object_Item *nf_it;

   ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
   elm_win_conformant_set(ad->win, EINA_TRUE);
   elm_win_autodel_set(ad->win, EINA_TRUE);
   elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW);
   elm_win_indicator_opacity_set(ad->win, ELM_WIN_INDICATOR_OPAQUE);

   evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL);
   eext_object_event_callback_add(ad->win, EEXT_CALLBACK_BACK, win_back_cb, ad);

   ad->conform = create_conform(ad->win);

   // Naviframe
   ad->nf = elm_naviframe_add(ad->conform);
   elm_object_content_set(ad->conform, ad->nf);

   layout = create_main_view(ad);
   nf_it = elm_naviframe_item_push(ad->nf, _("News Feed"), NULL, NULL, layout, "basic");

   // Drawer bg
   bg = create_bg(layout);
   elm_object_part_content_set(layout, "elm.swallow.bg", bg);

   // Drawer
   drawer = create_panel(layout);
   eext_object_event_callback_add(drawer, EEXT_CALLBACK_BACK, drawer_back_cb, ad);
   evas_object_smart_callback_add(drawer, "scroll", panel_scroll_cb, bg);
   elm_object_part_content_set(layout, "elm.swallow.right", drawer);

   // Drawers Button
   btn = create_drawers_btn(ad->nf, btn_cb, drawer);
   elm_object_item_part_content_set(nf_it, "title_right_btn", btn);

   // Show the window after the base GUI is set up
   evas_object_show(ad->win);

   evas_object_event_callback_add(ad->win, EVAS_CALLBACK_RESIZE, view_size_reset, ad);
}

Main View

The create_main_view() function creates the main content. It consists of a single layout containing a box. The box contains the tab bar (elm_toolbar) and a scroller. The toolbar acts as the view changer and indicator. Its vertical weight is 0.12, which means that the toolbar occupies 12% of the box. The rest of the area contains the scroller, which includes another box. The box contains 4 views horizontally. Each view has a minimum size, which is the same as the screen width.

static Evas_Object *
create_main_view(appdata_s *ad)
{
   Evas_Object *layout, *box, *box2, *table;
   Evas_Object *first_view, *second_view, *third_view, *fourth_view;

   // Layout for drawer
   layout = create_drawer_layout(ad->nf);

   // Box
   box = elm_box_add(layout);
   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_object_part_content_set(layout, "elm.swallow.content", box);

   // Tab bar
   ad->tabbar = _create_tabbar(box, ad);
   evas_object_size_hint_weight_set(ad->tabbar, EVAS_HINT_EXPAND, 0.12);
   evas_object_size_hint_align_set(ad->tabbar, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_box_pack_end(box, ad->tabbar);

   // Scroller
   ad->scroller = create_scroller(box, ad);
   evas_object_size_hint_weight_set(ad->scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(ad->scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_box_pack_end(box, ad->scroller);

   // Box
   box2 = elm_box_add(ad->scroller);
   elm_box_horizontal_set(box2, EINA_TRUE);
   evas_object_size_hint_weight_set(box2, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(box2, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_object_content_set(ad->scroller, box2);

   // First view
   first_view = create_first_view(box2, ad);
   ad->first_view_rect = min_set(first_view, box2, 0, 0);

   return layout;
}

The min_set() function is used for setting the minimum value of a UI component. Currently, the evas_object_size_hint_min_set() function does not work for an elementary UI component. Instead, this function uses the fact that a table contains a rectangle with a minimum value. The object expands to the minimum size of the rectangle.

static Evas_Object *
min_set(Evas_Object *parent, Evas_Object *box, Evas_Coord w, Evas_Coord h)
{
   Evas_Object *table, *rect;

   table = elm_table_add(box);
   evas_object_show(table);

   rect = evas_object_rectangle_add(evas_object_evas_get(table));
   evas_object_size_hint_min_set(rect, w, h);
   evas_object_size_hint_weight_set(rect, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(rect, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_table_pack(table, rect, 0, 0, 1, 1);

   evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_table_pack(table, obj, 0, 0, 1, 1);

   evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_box_pack_end(box, table);

   return rect;
}

The create_tabbar() function creates the tab bar using the elm_toolbar() function. The ELM_TOOLBAR_SHRINK_EXPAND parameter is set for items to occupy the same area in the toolbar area. The elm_toolbar_transverse_expanded_set() function expands the vertical size of the toolbar in the horizontal mode. Because the toolbar is used as a tab bar, at least 1 item should be selected. Set it using the ELM_OBJECT_SELECT_MODE_ALWAYS parameter.

static Evas_Object *
create_tabbar(Evas_Object *parent, appdata_s *ad)
{
   Evas_Object *tabbar;

   tabbar = elm_toolbar_add(parent);
   elm_toolbar_shrink_mode_set(tabbar, ELM_TOOLBAR_SHRINK_EXPAND);
   elm_toolbar_transverse_expanded_set(tabbar, EINA_TRUE);
   elm_toolbar_select_mode_set(tabbar, ELM_OBJECT_SELECT_MODE_ALWAYS);
   elm_toolbar_item_append(tabbar, ICON_DIR"/00_controlbar_icon_playlist.png", NULL, tabbar_first_cb, ad);
   elm_toolbar_item_append(tabbar, ICON_DIR"/00_controlbar_icon_artists.png", NULL, tabbar_second_cb, ad);
   elm_toolbar_item_append(tabbar, ICON_DIR"/00_controlbar_icon_dialer.png", NULL, tabbar_third_cb, ad);
   elm_toolbar_item_append(tabbar, ICON_DIR"/00_controlbar_icon_more.png", NULL, tabbar_fourth_cb, ad);
   evas_object_show(tabbar);

   return tabbar;
}

When a toolbar item is clicked, the tabbar_first_cb() function is called. In the function, the naviframe title changes and sets the scroll page value to 0.

static void
tabbar_first_cb(void *data, Evas_Object *obj, void *event_info)
{
   appdata_s *ad = data;

   elm_object_item_part_text_set(elm_naviframe_top_item_get(ad->nf), "elm.text.title", "News Feed");
   elm_scroller_page_bring_in(ad->scroller, 0, 0);
}

The create_scroller() function creates a scroller and sets options for the page view. To use this view, the scroller should use the tabbar style instead of the default style. It creates an indicated bar above the tab bar. Since the bar is a horizontal scrollbar of the scroller, it should be always visible. Thus, the second parameter of the elm_scroller_policy_set() function is ELM_SCROLLER_POLICY_ON.

The horizontal page is set to 480 and the page moves only 1 page at a time.

The ELM_SCROLLER_SINGLE_DIRECTION_HARD parameter is for scrolling in the scroller. The scroller has 4 pages and each page can have their own scroller. In this case, if you scroll, both scrollers are scrolled. If you want the outside scroller is scrolled only horizontally and the scroller in the page is scrolled only vertically, use the elm_scroller_single_direction_set() function with the ELM_SCROLLER_SINGLE_DIRECTION_HARD parameter.

To select a toolbar item at the end of a scroll animation, use the scroll,anim,stop smart callback.

static Evas_Object *
create_scroller(Evas_Object *parent, appdata_s *ad)
{
Evas_Object *scroller;

   scroller = elm_scroller_add(parent);
   elm_object_style_set(scroller, "tabbar");
   elm_scroller_policy_set(scroller, ELM_SCROLLER_POLICY_ON, ELM_SCROLLER_POLICY_OFF);
   elm_scroller_page_size_set(scroller, 480, 0);
   elm_scroller_page_scroll_limit_set(scroller, 1, 0);
   elm_scroller_single_direction_set(scroller, ELM_SCROLLER_SINGLE_DIRECTION_HARD);
   evas_object_smart_callback_add(scroller, "scroll,anim,stop", anim_stop_cb, ad);
   evas_object_show(scroller);

   return scroller;
}

First View

The following figure illustrates the first view, its wireframe structure, and the UI component tree.

Figure: SNS first view

SNS first view

SNS first view

The create_first_view() function creates the first view. It creates a scroller which contains a box and packs the content created by the create_box_content() function.

static Evas_Object *
create_first_view(Evas_Object *parent, appdata_s *ad)
{
   Evas_Object *scroller, *box, *content, *table;
   int i;

   scroller = elm_scroller_add(parent);
   elm_scroller_policy_set(scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
   elm_scroller_single_direction_set(scroller, ELM_SCROLLER_SINGLE_DIRECTION_HARD);

   box = elm_box_add(scroller);
   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_box_padding_set(box, 0, 30);
   elm_object_content_set(scroller, box);

   for (i = 0; i < 20; i++)
   {
      content = create_box_content(box);
      min_set(content, box, 0, 0);
   }

   evas_object_show(scroller);

   return scroller;
}

The create_box_content() function creates a box which contains a label and a box. The second box contains 3 buttons and occupies 30% of the content area.

Evas_Object *create_box_content(Evas_Object *parent)
{
   Evas_Object *box, *box2, *label, *btn;

   box = elm_box_add(parent);

   label = elm_label_add(box);
   evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_label_wrap_width_set(label, 30);
   elm_label_line_wrap_set(label, ELM_WRAP_MIXED);
   elm_object_text_set(label, "EFL is a collection of libraries that are independent
                              or may build on top of each-other to provide useful 
                              features that complement an OS's existing environment, 
                              rather than wrap and abstract it, trying to be their
                              own environment and OS in its entirety.");
   elm_box_pack_end(box, label);
   evas_object_show(label);

   box2 = elm_box_add(box);
   evas_object_size_hint_weight_set(box2, EVAS_HINT_EXPAND, 0.3);
   evas_object_size_hint_align_set(box2, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_box_horizontal_set(box2, EINA_TRUE);
   elm_box_padding_set(box2, 15, 0);
   elm_box_pack_end(box, box2);
   evas_object_show(box2);

   btn = elm_button_add(box2);
   evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(btn, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_object_text_set(btn, "I like it");
   elm_box_pack_end(box2, btn);
   evas_object_show(btn);
   evas_object_show(box);

   return box;
}

The descriptions of the second, third, and fourth view are omitted.