Список

Список нам требуется для вывода всех активностей сгруппированных по разделам. Задача разбивается на три части:

  • подготовить данные;
  • вывести их в виде списка;
  • сохранять данные при выборе пользователем и отображать результат выбора.

Предварительно сделаем отображение текущей активности в нашей сцене. Поскольку пользователь ещё ничего не вводил, то следует установить исходные данные по умолчанию. Задаём три переменные.

activity_name	= "Ходьба, 4 км/ч"; -- название активности
activity_factor	= 3; -- коэффициент активности
activity_index 	= 147; -- номер в списке

Переменная activity_name хранит текст для отображения; activity_factor — коэффициент, участвующий в расчётах калорий; activity_index нам требуется для прокрутки списка к выбранному пункту.

Теперь просто отображаем текст из переменной согласно нашему дизайну.

-- добавляем новую группу
activityGroup = display.newGroup();	
--  прямоугольник со скруглёнными уголками
display.newRoundedRect(activityGroup, display.contentCenterX, 790, w, 60, 10):setFillColor(244/255);
-- рисуем треугольник
display.newPolygon(activityGroup, 500, 790, {500, 452, 520, 452, 510, 466}):setFillColor(0.4);
-- выводим текст из переменной activity_name в прямоугольник
activityText = display.newText(activityGroup, activity_name, display.contentCenterX, 790, native.systemFont, 24);
-- изменяем цвет текста
activityText:setFillColor(237/255, 103/255, 57/255);
-- обработчик нажатия
activityGroup:addEventListener("touch",
	function(event)
		composer.showOverlay("scenes.activity", {
			isModal = true, -- модальное окно
			effect = "fade", -- эффект появления
			time = 400, -- время появления
		});
	end
);

Все элементы мы уже до этого задействовали, за исключением display.newPolygon, с помощью которого добавляем небольшой треугольник справа от списка. Треугольник носит только декоративный характер, не более.

Для перехода к другой сцене мы воспользуемся не composer.gotoScene, как делали это ранее, а composer.showOverlay. Эта функция выводит одну сцену поверх другой, тем самым мы получаем имитацию диалогового окна. Появление новой сцены можно сделать с эффектом перехода, чтобы она выводилась не мгновенно, а плавно, в течение какого-то времени. Смотрим что получилось в итоге.

Вид приложения с выбранной активностью

Вид приложения с выбранной активностью

Внутри папки scenes создаём два файла — data.lua и activity.lua. В первом файле будет храниться таблица с данными для списка, а второй файл их отображать в нужном нам виде. Сокращённое содержимое data.lua показано ниже.

local activityData = {
	{ factor=0, name="Аэробика", category=1 },
	{ factor=5, name="Аэробика, низкая нагрузка", category=0 },
	{ factor=6.5, name="Аэробика, средняя нагрузка", category=0 },
	{ factor=7, name="Аэробика, высокая нагрузка", category=0 },
	{ factor=0, name="Музыка", category=1 },
	{ factor=4, name="Игра на барабанах", category=0 },
	{ factor=2, name="Игра на духовых инструментах", category=0 },
	{ factor=2.5, name="Игра на клавишных", category=0 },
	{ factor=2, name="Игра на струнных инструментах", category=0 },
}

Здесь: factor — значение коэффициента; name — название активности; category — категория (1) или нет (0). Категория нужна для разделения всего списка на тематические блоки. Так проще и нагляднее пользователю ориентироваться в большом списке. Если category равна 1, то мы делаем текст заголовком блока, выбирать его в таком случае нельзя.

Структура activity.lua показана ниже. Вызываем наши данные из data.lua через функцию require и присваиваем их переменной data. Весь остальной код вставляем внутрь метода create и не забываем добавлять объекты в группу sceneGroup, иначе сцена со списком корректно закрываться не будет.

local composer = require("composer");
local widget = require("widget");
local data = require("scenes.data"); -- вызов файла data.lua
local scene = composer.newScene();
function scene:create(event)
	local sceneGroup = self.view;
	-- наш код
end
scene:addEventListener("create", scene);
return scene;

Сам процесс создания списка с данными состоит из четырёх шагов.

  1. Добавление виджета widget.newTableView заданного размера.
  2. Заполнение списка данными через цикл for i = 1, #data do. Там же в списке устанавливаем цвет заголовка блока и цвет основного текста.
  3. Отображение списка в нашей функции onRowRender заданным шрифтом и цветом. Заметьте, что на предыдущем шаге список лишь формировался, но не выводился. Это нужно проделать отдельно.
  4. Обработка нажатия на элемент списка в нашей функции onRowTouch. В переменных следует сохранить данные выбранного пункта и отобразить название активности.

Код activity.lua целиком показан ниже.

local composer = require("composer");
local widget = require("widget");
local data = require("scenes.data"); -- вызов файла data.lua

local scene = composer.newScene();

function scene:create(event)
	local sceneGroup = self.view;
	
	-- полупрозрачный прямоугольник
	display.newRect(sceneGroup, display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight):setFillColor(37/255, 39/255, 46/255, 0.7);
	
	-- отображаем список
	function onRowRender(event)
		local row = event.row;
		local id = row.index;
		-- выводим текст заданным шрифтом

		row.activityText = display.newText(data[id].name, 24, 24, native.systemFont, 22);
		row.activityText.anchorX = 0; -- задаём точку отсчёта координат
		if (data[id].category == 1) then 
			row.activityText:setFillColor(1); -- для заголовков цвет белый
			else row.activityText:setFillColor(0) -- для остального текста чёрный
		end
		row:insert(row.activityText);
		return true
	end
	
	-- нажатие на пункт списка
	function onRowTouch(event)
		local row = event.row
		if (event.phase == "release") then
			-- присваиваем переменным выбранные значения
			activity_index = row.index;
			activity_name = data[activity_index].name;
			activity_factor = data[activity_index].factor;
			activityText.text = activity_name;
			composer.hideOverlay("fade", 400); -- закрываем окно
		end
	end

	-- создаём список
	local activityList = widget.newTableView {
	   top = 70, left = 40, -- координаты
	   width = 460, height = 850, -- размеры
	   onRowRender = onRowRender,
	   onRowTouch = onRowTouch,
	}
	sceneGroup:insert(activityList); -- добавляем список в группу sceneGroup
	
	-- добавляем в список данные
	for i = 1, #data do
		if (data[i].category == 1) then isCategory = true;
			else isCategory = false;
		end
		if (isCategory == true) then
			rowColor = { default = {237/255, 103/255, 57/255} };
			else rowColor = { default = {1} }
		end
		activityList:insertRow{
			rowHeight = 50,
			isCategory = isCategory,
			rowColor = rowColor,
		}
	end
	
	-- прокручиваем список к выбранному ранее пункту
	if (activity_index > 1) then
		activityList:scrollToY({y=-(activity_index-2)*50});
	end
	
	-- кнопка закрытия списка
	close = display.newImage(sceneGroup, "img/close.png", 500, 76);	
	close:addEventListener("touch", function(event)
			if event.phase == 'ended' then
				composer.hideOverlay("fade", 400);
			end
		end
	);
end

scene:addEventListener("create", scene);
return scene;

Вот как выглядит наш список при его вызове.

Прокручиваемый список

Прокручиваемый список

Кроме самого списка сделаем кнопку для его закрытия, это позволит убирать список без обязательного выбора. Используем обычную картинку, при нажатии на которую вызываем функцию composer.hideOverlay. Также добавим полупрозрачный фон совпадающий с размерами нашего контента, чтобы затемнять нижележащую сцену. Так будет выглядеть профессионально и стильно. Уровень прозрачности легко регулируется через альфа-канал.

См. также

Документация по widget.newTableView()

http://docs.coronalabs.com/api/library/widget/newTableView.html

Документация по display.newPolygon()

http://docs.coronalabs.com/api/library/display/newPolygon.html

Эффекты перехода между сценами

http://docs.coronalabs.com/api/library/composer/gotoScene.html#transition-effects

Руководство по созданию списка

http://coronalabs.com/blog/2014/03/04/tutorial-advanced-tableview-tactics/

Автор: Влад Мержевич
Последнее изменение: 04.08.2023