Kinetic scroll2
bug fix?
/**
* Copyright gggiyeok ( http://wonderfl.net/user/gggiyeok )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/bvFc
*/
package{
import flash.events.MouseEvent;
import flash.display.Sprite;
import com.bit101.components.*;
public class Main extends Sprite {
private var list:FlickList;
private var btn:PushButton;
private var label:Label;
private var input:InputText
public function Main(){
var str:String = "abcdefghijklmnopqrstuvwxyz";
list = new FlickList(this, 20, 50);
list.items = str.split('');
var vbox:VBox = new VBox(this, 20, list.y+list.height+10);
label = new Label(this);
label.text = 'ex:abc001,abc002,abc003';
var hbox:HBox = new HBox(this,0, label.y+label.height);
input = new InputText(this);
input.setSize(300, input.height);
btn = new PushButton(this, 0, 0, 'change list', changList);
hbox.addChild(input);
hbox.addChild(btn);
vbox.addChild(label);
vbox.addChild(hbox);
}
private function changList(e:MouseEvent):void{
list.items = input.text.split(',');
}
}
}
import flash.display.Sprite;
import flash.display.DisplayObjectContainer;
import com.bit101.components.*;
import flash.events.*;
import flash.utils.*;
class FlickList extends Component {
private var listCnt:uint=0;
private var listItemH:uint=40;
private var pageSize:uint=200;
private var totalH:uint;
protected var _listItemClass:Class = ListItem;
private var tCnt:uint=0;
private var tension:Array=[.5,.3,.2,.1,0];
private var tmpY:Number=0;
private var dragStatus:int=0;//tensino direction
private var tensionPosSum:Number=0;
private var cy:Number=0;
private var listW:uint=300;
private var viewCnt:uint = 0 ;// Math.ceil(pageSize / listItemH) * 2;
private var listContainer:Panel;
private var scrollValue:Number=0;
private var listItems:Array;
private var scrollBar:VScrollBar;
private var dy:Number=0;
private var flickTime:Number;
private var spd:int;
protected var _items:Array;
private var isDrag:Boolean = false;
protected var _selectedIndex:int = -1;
protected var isShort:Boolean = true;
public function FlickList(parent:DisplayObjectContainer=null, xpos:Number=0, ypos:Number=0, items:Array=null) {
if(items != null)
{
_items = items;
}
else
{
_items = new Array();
}
//test data
super(parent, xpos, ypos);
}
protected function makeListItems():void
{
listCnt = _items.length;
totalH = listItemH * listCnt;
isShort = false;
if (listCnt<int(_height/listItemH)) {
totalH=_height;
isShort = true;
}
viewCnt = Math.ceil(_height / listItemH) +1;
while (listContainer.content.numChildren > 0) listContainer.content.removeChildAt(0);
listItems.length = 0;
for (var i:uint = 0; i < viewCnt; i++) {
var item:Item = new Item();
item.y = listItemH * i;
listContainer.content.addChild(item);
item.setSize(_width, listItemH);
listItems.push(item);
if (i < listCnt) {
item.data = { label:String(_items[i]), id:i };
} else {
item.data={label:'',id:i};
}
}
}
public function addItem(item:Object):void
{
_items.push(item);
invalidate();
makeListItems();
}
/**
* Adds an item to the list at the specified index.
* @param item The item to add. Can be a string or an object containing a string property named label.
* @param index The index at which to add the item.
public function addItemAt(item:Object, index:int):void
{
index = Math.max(0, index);
index = Math.min(_items.length, index);
_items.splice(index, 0, item);
invalidate();
fillItems();
}*/
protected override function init() : void {
super.init();
setSize(300, 300);
listItems = new Array();
makeListItems();
listContainer.addEventListener(MouseEvent.MOUSE_DOWN, down);
}
/**
* Removes all items from the list.
*/
public function removeAll():void
{
_items.length = 0;
invalidate();
}
/**
* Draws the visual ui of the component.
*/
public override function draw() : void
{
super.draw();
// panel
listContainer.setSize(_width, _height);
listContainer.draw();
// scrollbar
scrollBar.x = _width - 10;
scrollBar.setThumbPercent(listItemH/(totalH-_height));
var max:int=totalH-_height;
if (max<0) {
max=0;
}
scrollBar.setSliderParams(0, max, 0);
scrollBar.height = _height;
scrollBar.draw();
}
public function set listItemHeight(value:Number):void
{
listItemH = value;
makeListItems();
invalidate();
}
public function get listItemHeight():Number
{
return listItemH;
}
/**
* Sets / gets the list of items to be shown.
*/
public function set items(value:Array):void
{
_items = value;
makeListItems();
invalidate();
}
public function get items():Array
{
return _items;
}
protected function onResize(event:Event):void
{
makeListItems();
}
protected override function addChildren() : void
{
listContainer = new Panel(this, 0, 0);
scrollBar = new VScrollBar(this,_width,0,changeScroll);
super.addChildren();
}
private function changeScroll(e:Event) :void{
scrollJump(scrollBar.value);
}
/* scroll by scorllBar */
private function scrollJump(val:int):void{
var index:int=int(val/listItemH);
var iy:Number = listItemH*(index) - val;
for (var i:uint = 0; i < viewCnt; i++) {
var item:Item=listItems[i];
item.y = iy + listItemH * i;
var newIndex:int = i + index;
var txt:* = items[newIndex];
if(txt){
item.data = { label:items[newIndex], id:newIndex };
item.visible = true;
}else item.visible = false;
if (newIndex < 0 || newIndex > listCnt-1) item.visible = false;
}
cy = -val;
}
private function down(e:MouseEvent) :void{
dy=this.mouseY;
flickTime=getTimer();
removeEventListener(Event.ENTER_FRAME, flickList);
removeEventListener(Event.ENTER_FRAME, rewind);
stage.addEventListener(MouseEvent.MOUSE_UP, endDrag);
//drag();
e.currentTarget.addEventListener(Event.ENTER_FRAME, drag);
tensionPosSum=0;
tmpY=0;
}
/**
* Sets / gets the class used to render list items. Must extend ListItem.
*/
public function set listItemClass(value:Class):void
{
_listItemClass = value;
makeListItems();
invalidate();
}
public function get listItemClass():Class
{
return _listItemClass;
}
private function endDrag(e:MouseEvent) :void {
isDrag = false;
removeEventListener(Event.ENTER_FRAME, flickList);
tCnt = 0;
if (dragStatus>0) {
tmpY = cy;
addEventListener(Event.ENTER_FRAME, rewind);
} else if (dragStatus < 0) {
tmpY = (totalH - _height) + cy;
addEventListener(Event.ENTER_FRAME, rewind);
}
if (Math.abs(spd)>10&&dragStatus==0) {
addEventListener(Event.ENTER_FRAME, flickList);
}
listContainer.removeEventListener(Event.ENTER_FRAME, drag);
}
private function rewind(e:*=null) :void{
//Floating-point 에러 보정
var divideVal:int = Math.round(tmpY * tension[tCnt]);
if (tCnt==tension.length-2) {
divideVal=tmpY-tensionPosSum;
}
tensionPosSum+=divideVal;
tCnt++;
scroll(-divideVal);
if (tCnt==tension.length) {
removeEventListener(Event.ENTER_FRAME, rewind);
tensionPosSum=0;
tCnt=0;
}
}
private function flickList(e:Event) :void {
spd *= .9;
isDrag = true;
if (Math.abs(spd)<1) {
removeEventListener(Event.ENTER_FRAME, flickList);
//되돌아가기
if (dragStatus>0) {
tmpY=cy;
addEventListener(Event.ENTER_FRAME, rewind);
} else if (dragStatus < 0) {
tmpY = (totalH-_height)+cy;
addEventListener(Event.ENTER_FRAME, rewind);
}
return;
}else scroll(-spd);
}
private function drag(e:Event = null) :void{
spd = dy - this.mouseY;
dy=this.mouseY;
flickTime = getTimer();
isDrag = true;
var abs:Number = Math.abs(spd);
if (abs > 0) {
if (abs > _height) spd *= .2;
scroll(-spd);
}
}
private function scroll(val:Number) :void {
cy += val;
if (cy > _height || cy < -totalH) {
cy -= val; val = 0;
}
var rate:Number = 0;
var tmpVal:Number;
if (val > 5 && isDrag) {
tmpVal = val;
rate = Math.min(cy / _height, 1);
if (rate > 0) {
val = int(val * .4);
cy += (val - tmpVal);
}
}else if (val < -5 && isDrag) {
tmpVal = val;
rate = Math.min(1 - (cy + totalH) / _height, 1);
if (rate > 0) {
val = int(val * .4);
cy += (val - tmpVal);
}
}
spd = -val;
scrollBar.value = -cy;
var i:int;
var item:Item
var id:int;
if (-(totalH-_height) > cy ) dragStatus=-1; //pull up
else if (cy > 0) dragStatus=1; //pull down
else dragStatus = 0; // drag
var popItem:Vector.<Item> = new Vector.<Item>();
if (val<0) {
for (i = 0; i < viewCnt; i++) {
item = listItems[i];
item.y+=val;
if (item.y+item.height<0) {
popItem.push(item);
}
}
if(isShort) return;
if (popItem.length > 0) {
for (i = 0; i < popItem.length; i++) {
item=listItems.shift();
var prev:Item = listItems[listItems.length - 1];
id = prev.data.id + 1;
if (id>listCnt-1) {
item.visible=false;
} else {
item.visible=true;
}
item.data={label:String(_items[id]),id:id};
item.y = prev.y + listItemH;
listItems.push(item);
}
}
} else if (val > 0) {
for (i = 0; i < viewCnt; i++) {
item=listItems[i];
item.y+=val;
if (item.y>_height) {
popItem.push(item);
}
}
if(isShort) return;
if (popItem.length > 0) {
for (i = 0; i < popItem.length; i++) {
item=listItems.pop();
var next:Item=listItems[0];
id = next.data.id - 1;
if (id<0) {
item.visible=false;
} else {
item.visible=true;
}
item.data={label:String(_items[id]),id:id};
item.y = listItems[0].y - item.height;
listItems.unshift(item);
}
}
}
}
}
import flash.display.Graphics;
import flash.text.TextFormat;
import flash.text.TextField;
import flash.display.Sprite;
import com.bit101.components.Style;
class Item extends Sprite{
private var _data:Object;
public var id:int;
private var txt:TextField;
private var _back:Sprite;
private var _width:uint = 300;
private var _height:uint = 40;
public function Item(){
txt = new TextField();
txt.autoSize = 'left';
var tf:TextFormat = new TextFormat(Style.fontName, 8, 0x0);
txt.embedFonts = true;
txt.defaultTextFormat = tf;
_back = new Sprite();
draw();
}
public function draw():void{
var g:Graphics = _back.graphics;
g.clear();
g.beginFill(0xDEDEDE);
g.drawRect(0, 0, _width, 1);
g.endFill()
g.beginFill(0xFFFFFF);
g.drawRect(0, 1, _width, _height-1);
g.endFill();
addChild(_back);
addChild(txt);
}
public function setSize(w:uint, h:uint):void{
_width = w; _height = h;
draw();
}
public function set label(val:String):void{
txt.text = val;
}
public function set data(obj:Object):void{
txt.text = obj.label;
id = obj.id;
_data = {label:obj.lebel, id:obj.id};
txt.y = int((_height - txt.height) / 2);
}
public function get data():Object{
return _data;
}
}