All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.kotcrab.vis.ui.widget.ListView Maven / Gradle / Ivy

There is a newer version: 1.5.3
Show newest version
/*
 * Copyright 2014-2017 See AUTHORS file.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.kotcrab.vis.ui.widget;

import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.kotcrab.vis.ui.VisUI;
import com.kotcrab.vis.ui.util.adapter.AbstractListAdapter;
import com.kotcrab.vis.ui.util.adapter.ArrayAdapter;
import com.kotcrab.vis.ui.util.adapter.ArrayListAdapter;
import com.kotcrab.vis.ui.util.adapter.ListAdapter;

/**
 * ListView displays list of scrollable items. Item views are created by using {@link ListAdapter}s.
 * @author Kotcrab
 * @see ListAdapter
 * @see ArrayAdapter
 * @see ArrayListAdapter
 * @since 1.0.0
 */
public class ListView {
	private ListAdapter adapter;
	private ItemClickListener clickListener;

	private UpdatePolicy updatePolicy = UpdatePolicy.IMMEDIATELY;
	private boolean dataInvalidated = false;

	private ListViewTable mainTable;
	private VisScrollPane scrollPane;

	private VisTable scrollTable;
	private VisTable itemsTable;

	private Actor header;
	private Actor footer;

	public ListView (ListAdapter adapter) {
		this(adapter, "default");
	}

	public ListView (ListAdapter adapter, String styleName) {
		this(adapter, VisUI.getSkin().get(styleName, ListViewStyle.class));
	}

	public ListView (ListAdapter adapter, ListViewStyle style) {
		if (style == null) throw new IllegalArgumentException("style can't be null");
		if (adapter == null) throw new IllegalArgumentException("adapter can't be null");
		this.adapter = adapter;

		mainTable = new ListViewTable(this);
		scrollTable = new VisTable();
		itemsTable = new VisTable();

		scrollPane = new VisScrollPane(scrollTable, style.scrollPaneStyle);
		scrollPane.setOverscroll(false, true);
		scrollPane.setFlickScroll(false);
		scrollPane.setFadeScrollBars(false);
		mainTable.add(scrollPane).grow();

		adapter.setListView(this, new ListAdapterListener());
		rebuildView(true);
	}

	public void rebuildView () {
		rebuildView(true);
	}

	private void rebuildView (boolean full) {
		scrollTable.clearChildren();
		scrollTable.top();
		if (header != null) {
			scrollTable.add(header).growX();
			scrollTable.row();
		}

		if (full) {
			itemsTable.clearChildren();
			adapter.fillTable(itemsTable);
		}

		scrollTable.add(itemsTable).growX();
		scrollTable.row();

		if (footer != null) {
			scrollTable.add(footer).growX();
			scrollTable.row();
		}
	}

	public ListAdapter getAdapter () {
		return adapter;
	}

	/** @return main table containing scroll pane and all items view */
	public ListViewTable getMainTable () {
		return mainTable;
	}

	/**
	 * @return internal {@link VisScrollPane}. Do NOT add this scroll pane directly to {@link Stage}
	 * use {@link #getMainTable()} instead. Use this only for changing scroll pane properties.
	 */
	public VisScrollPane getScrollPane () {
		return scrollPane;
	}

	public void setItemClickListener (ItemClickListener listener) {
		this.clickListener = listener;
		adapter.setItemClickListener(listener);
	}

	public ItemClickListener getClickListener () {
		return clickListener;
	}

	public Actor getHeader () {
		return header;
	}

	public void setHeader (Actor header) {
		this.header = header;
		rebuildView(false);
	}

	public Actor getFooter () {
		return footer;
	}

	public void setFooter (Actor footer) {
		this.footer = footer;
		rebuildView(false);
	}

	public void setUpdatePolicy (UpdatePolicy updatePolicy) {
		this.updatePolicy = updatePolicy;
	}

	public UpdatePolicy getUpdatePolicy () {
		return updatePolicy;
	}

	public interface ItemClickListener {
		void clicked (ItemT item);
	}

	public class ListAdapterListener {
		public void invalidateDataSet () {
			if (updatePolicy == UpdatePolicy.IMMEDIATELY) rebuildView(true);
			if (updatePolicy == UpdatePolicy.ON_DRAW) dataInvalidated = true;
		}
	}

	/** Controls when list view's views are updated after underlying data was invalidated. */
	public enum UpdatePolicy {
		/** If list data was was invalidated then views are updated before drawing list. */
		ON_DRAW,
		/** If list data was was invalidated then views are updated immediately after data invalidation. */
		IMMEDIATELY,
		/**
		 * In manual mode ListView must be rebuild manually by calling {@link #rebuildView()}. Notification from adapter
		 * about need to rebuild view will be ignored (see {@link AbstractListAdapter#itemsChanged()}). This mode should
		 * be only used when it's really required to have manual control over how {@link ListView} rebuilds. Note that
		 * ListView should be rebuild before user interacts with it.
		 */
		MANUAL
	}

	/** ListView main table. */
	public static class ListViewTable extends VisTable {
		private ListView listView;

		private ListViewTable (ListView listView) {
			this.listView = listView;
		}

		@Override
		public void draw (Batch batch, float parentAlpha) {
			if (listView.updatePolicy == UpdatePolicy.ON_DRAW && listView.dataInvalidated) listView.rebuildView(true);
			super.draw(batch, parentAlpha);
		}

		public ListView getListView () {
			return listView;
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy