2014-10-23 3 views
2

Я хотел бы реализовать прокручиваемый ListView с жестами, как в мобильных телефонах и планшетах, для прокрутки вверх и вниз по моему списку пальцем. Но мой текущий список выбирает элемент, как только я нажимаю на список. Как я могу это достичь? Я не мог найти ни одного примера в учебниках Oracle.JavaFX ListView с сенсорными событиями для прокрутки вверх и вниз

private ObservableList<Document> items = FXCollections.observableArrayList(); 
@FXML ListView<Document> listView; 

{ 
    ... 

    listView.setItems(items); 
    listView.getStylesheets().add("style/listview.css"); 
    listView.setStyle("-fx-background-insets: 0 ;"); // remove 1px border of listview container 

    listView.setCellFactory(new Callback<ListView<Document>, ListCell<Document>>() { 
     @Override 
     public ListCell<Document> call(ListView<Document> listView) { 
      return new DocumentArrayAdapter(); 
     } 
    }); 

    ... 
} 

public void loadListView(List<Document> ldoc){ 
    if (!ldoc.isEmpty()){ 
     items.addAll(ldoc); 
    } 
} 
+0

Пожалуйста, взгляните на мой ответ. Очень простой ответ без расширений или около того. – Amin

ответ

3

Это то, что я сделал

public class CustomListCell extends ListCell<Document>{ 

private double lastYposition = 0; 

public CustomListCell(){ 

    setOnMousePressed(new EventHandler<MouseEvent>() { 
     @Override 
     public void handle(MouseEvent event) { 
      lastYposition = event.getSceneY(); 
     } 
    }); 

    setOnMouseDragged(new EventHandler<MouseEvent>() { 
     @Override 
     public void handle(MouseEvent event) { 
      double newYposition = event.getSceneY(); 
      double diff = newYposition - lastYposition; 
      lastYposition = newYposition; 
      CustomScrollEvent cse = new CustomScrollEvent(); 
      cse.fireVerticalScroll((int)diff, DocumentArrayAdapter.this, (EventTarget) event.getSource()); 
     } 
    }); 

и

package myproject.utils; 

import javafx.event.Event; 
import javafx.event.EventTarget; 
import javafx.scene.input.ScrollEvent; 

public class CustomScrollEvent { 

public void fireVerticalScroll(int deltaY, Object source, EventTarget target){ 

    ScrollEvent newScrollEvent = null; 
    newScrollEvent = new ScrollEvent(source, 
       target, 
       ScrollEvent.SCROLL, 
       0, 
       0, 
       0, 
       0, 
       false, 
       false, 
       false, 
       false, 
       false, 
       false, 
       0, 
       deltaY, 
       0, 
       0, 
       ScrollEvent.HorizontalTextScrollUnits.CHARACTERS, 
       0, 
       ScrollEvent.VerticalTextScrollUnits.NONE, 
       deltaY, 
       0, 
       null); 

     Event.fireEvent(target, newScrollEvent); 
} 
} 

Хотя я реализовал слушателя в моем собственном ListCell, я предполагаю, что это также будет работать реализации слушателей непосредственно в ListView, с listView.setOnMousePressed и listView.setOnMouseDragged

+0

Когда я запускаю это, я получаю: Конструктор ScrollEvent (Object, EventTarget, EventType , int, int, int, int, boolean, boolean, boolean, boolean, boolean, boolean, int, int, int, int, ScrollEvent. HorizontalTextScrollUnits, int, ScrollEvent.VerticalTextScrollUnits, int, int, null) не определено – officialhopsof

0

Я нашел diff Решение этой проблемы:

public class ScrollList { 

protected double lastYposition = 0; 
private double last_value = 0; 
protected double firstYposition = 0; 
protected ScrollBar scrollbar = null; 
private int autoValue = 0; 
private int maxScroll = 0; 

public ScrollList(ListView list) { 

list.setOnMousePressed(new EventHandler<MouseEvent>() { 
    @Override 
    public void handle(MouseEvent event) { 

     lastYposition = event.getSceneY(); 
     //Config.prints(lastYposition + ""); 

     firstYposition = lastYposition; 

    } 
}); 

Platform.runLater(new Runnable() { 
    @Override 
    public void run() { 
     if (scrollbar == null) { 
      for (Node node : list.lookupAll(".scroll-bar")) { 
       if (node instanceof ScrollBar) { 
        ScrollBar bar = (ScrollBar) node; 
        if (bar.getOrientation().equals(Orientation.VERTICAL)) { 
         scrollbar = bar; 
        } 
       } 
      } 

      scrollbar.setOnMouseReleased(new EventHandler<MouseEvent>() { 
       @Override 
       public void handle(MouseEvent event) { 

        lastYposition = event.getSceneY(); 

        last_value = autoValue; 

       } 
      }); 

      /* //in case the list has already a scroll value, like when 
      //return to fontes list, it should has the last choosed fontes selected 
      IndexedCell first = flow.getFirstVisibleCellWithinViewPort(); 
      autoValue = first.getIndex();*/ 
      VirtualFlow flow = (VirtualFlow) list.lookup(".virtual-flow"); 
      last_value = autoValue; 
      maxScroll = flow.getCellCount(); 

      flow.addEventFilter(Event.ANY, new EventHandler<Event>() { 
       @Override 
       public void handle(Event eventus) { 
        IndexedCell first = flow.getFirstVisibleCellWithinViewPort(); 
        autoValue = first.getIndex(); 
        Config.prints(last_value + ""); 
       } 
      }); 
     } 
    } 
}); 

list.setOnMouseDragged(new EventHandler<MouseEvent>() { 
    @Override 
    public void handle(MouseEvent event) { 

     double newYposition = event.getSceneY(); 

     //Config.prints(newYposition + ""); 
     double diff = newYposition - lastYposition; 
     lastYposition = newYposition; 

     if ((firstYposition - lastYposition) > Config.TOUCH_SCREEN_NOISE && (firstYposition - lastYposition) > 0 || (firstYposition - lastYposition) < (Config.TOUCH_SCREEN_NOISE * -1) && (firstYposition - lastYposition) < 0) { 
      list.getSelectionModel().clearSelection(); 
     } 

     if (diff > 0 && diff > Config.MIN_SCROLL_VELOCITY) { 
      diff = Config.MIN_SCROLL_VELOCITY; 
     } else if (diff < 0 && diff < Config.MIN_SCROLL_VELOCITY * -1) { 
      diff = Config.MIN_SCROLL_VELOCITY * -1; 
     } 

     if (diff > 0 && diff > Config.MAX_SCROLL_VELOCITY) { 
      diff = Config.MAX_SCROLL_VELOCITY; 
     } else if (diff < 0 && diff < Config.MAX_SCROLL_VELOCITY * -1) { 
      diff = Config.MAX_SCROLL_VELOCITY * -1; 
     } 

     //prints("diff=>" + diff + " || last_value=>" + last_value); 
     last_value -= diff; 
     //Config.prints("last_value=>" + last_value); 
     if (last_value < 0) { 
      last_value = 0; 
     }else if(last_value > maxScroll){ 
      last_value = maxScroll; 
     } 
     list.scrollTo((int) last_value); 
    } 
}); 

} 

//if you want the scroll to start from a specific position 

    public void setAutoValue(int index) { 


     this.autoValue = index; 
    } 
    } 
} 

public static double MAX_SCROLL_VELOCITY = 1; 

public static double MIN_SCROLL_VELOCITY = 0.5; 

Я поместил этот код внутри объекта «ScrollList» и использовал его так.

protected ArrayList<ScrollList> scrolls = new ArrayList<>();  
protected void setScroll(ListView list, int... index) { 

    ScrollList scrollList = new ScrollList(list); 

    if (index.length > 0) { 
     scrollList.setAutoValue(index[0]); 
    } 

    scrolls.add(scrollList); 

} 

ArrayList - это потому, что в моем случае у меня есть некоторые представления, что у меня есть более одного списка.

GC

0

Вот другой подход:

public class ScrollListener { 

    private BooleanProperty scrolling = new ReadOnlyBooleanWrapper(false); 

    private EventHandler<? super MouseEvent> dragDetectedFilter = e -> scrolling.set(true); 

    private EventHandler<? super MouseEvent> mouseClickedFilter = evt -> { 
     if (scrolling.get()) { 
      scrolling.set(false); 
      evt.consume(); 
     } 
    }; 

    private EventHandler<? super MouseEvent> mouseExitedHandler = e -> scrolling.set(false); 

    private Node observableNode; 

    public ScrollListener(Node observableNode) { 
     this.observableNode = observableNode; 
    } 

    public void enable() { 
     observableNode.addEventFilter(MouseEvent.DRAG_DETECTED, dragDetectedFilter); 
     observableNode.addEventFilter(MouseEvent.MOUSE_CLICKED, mouseClickedFilter); 
     observableNode.addEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler); 
    } 

    public void disable() { 
     observableNode.removeEventFilter(MouseEvent.DRAG_DETECTED, dragDetectedFilter); 
     observableNode.removeEventFilter(MouseEvent.MOUSE_CLICKED, mouseClickedFilter); 
     observableNode.removeEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler); 
    } 

    public ReadOnlyBooleanProperty scrollingProperty() { 
     return scrolling; 
    } 

    public boolean isScrolling() { 
     return scrolling.get(); 
    } 
} 

При добавлении слушателя в ListView по:

ScrollListener scrollListener = new ScrollListener(yourListView); 
scrollListener.enable(); 

MouseEvent.MOUSE_CLICKED получит потребляться, пока вы прокручиваете список

0

Простой в использовании:

import com.sun.javafx.scene.control.skin.VirtualFlow; 
import com.sun.javafx.scene.control.skin.VirtualScrollBar; 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import javafx.beans.InvalidationListener; 
import javafx.beans.Observable; 
import javafx.beans.property.IntegerProperty; 
import javafx.scene.control.ListCell; 
import javafx.scene.control.ListView; 

public class ListViewHelper 
{ 
    public static VirtualFlow getVirtualFlow(ListView lv) 
    { 
     return (VirtualFlow) lv.lookup(".virtual-flow"); 
    } 

    public static VirtualScrollBar getVbar(VirtualFlow vf) 
    { 
     try { 
      final Method method = VirtualFlow.class.getDeclaredMethod("getVbar"); 
      method.setAccessible(true); 
      return (VirtualScrollBar) method.invoke(vf); 
     } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | 
       InvocationTargetException ex) { 
      throw new RuntimeException(ex); 
     } 
    } 

    public static VirtualScrollBar getHbar(VirtualFlow vf) 
    { 
     try { 
      final Method method = VirtualFlow.class.getDeclaredMethod("getHbar"); 
      method.setAccessible(true); 
      return (VirtualScrollBar) method.invoke(vf); 
     } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | 
       InvocationTargetException ex) { 
      throw new RuntimeException(ex); 
     } 
    } 

} 

Просто позвоните getVbar (getVirtualFlow (listViewInstance)), и у вас будет полоса прокрутки в ваших руках. Затем вы можете добавить слушателя к valueProperty полосы прокрутки.

Смежные вопросы