I am trying to create a coursel with the active dots indicator.
like the one on Instagram I'd like to create a listview when the number of dots grows.
When they are too many you probably wont have an issue of layout but if they are like 2 then I'd like to keep them centered.
I'd also like to know how to shrink the ones on the edges to indicate continuity if possible I can't quite figure out how you can achieve that.
I tried to get the active and center the active dot with something like this
_scrollTo(int index) {
// get the screen width. This is used to check if we have an element off screen
RenderBox tabsContainer =
_tabsContainerKey.currentContext.findRenderObject();
double screenWidth = tabsContainer.size.width;
// get the button we want to scroll to
RenderBox renderBox = _tabKeys[index].currentContext.findRenderObject();
// get its size
double size = renderBox.size.width;
// and position
double position = renderBox.localToGlobal(Offset.zero).dx;
print(position);
// this is how much the button is away from the center of the screen and how much we must scroll to get it into place
double offset = (position + size / 2) - screenWidth / 2;
// if the button is to the left of the middle
if (offset < 0) {
// get the first button
renderBox = _tabKeys[0].currentContext.findRenderObject();
// get the position of the first button of the TabBar
position = renderBox.localToGlobal(Offset(-20.0, 0.0)).dx;
// if the offset pulls the first button away from the left side, we limit that movement so the first button is stuck to the left side
if (position > offset) offset = position;
} else {
// if the button is to the right of the middle
// get the last button
renderBox = _tabKeys.last.currentContext.findRenderObject();
// get its position
position = renderBox.localToGlobal(Offset.zero).dx;
// and size
size = renderBox.size.width;
// if the last button doesn't reach the right side, use it's right side as the limit of the screen for the TabBar
if (position + size < screenWidth) screenWidth = position + size;
// if the offset pulls the last button away from the right side limit, we reduce that movement so the last button is stuck to the right side limit
if (position + size - offset < screenWidth) {
offset = position + size - screenWidth;
}
}
// scroll the calculated amount
_scrollController.animateTo(offset + _scrollController.offset,
duration: new Duration(milliseconds: widget.duration),
curve: Curves.easeInOut);
}
If you want to center the children on ListView widget. You can do this
Center(
child: ListView(
shrinkWrap: true, //make children centered if children is below minimum height or width of its parent
children: [],
),
)
Related
I need to calculate the distance from the bottom of a screen to a container.Is it possible to calculate distance from bottom of a screen to Container and distance from top of a screen to container in separately?
I got the distance from top like this,
RenderBox box = keyGlobal.currentContext!.findRenderObject() as RenderBox;
Offset position = box.localToGlobal(Offset.zero); //this is global position
double y = position.dy;
Is it possible to get distance from bottom?
I'm using Sliding Up Panel package to use sliding panel. Sliding panel located above Scaffold's bottomNavigationBar and it has AnimatedContainer. Sliding panel has an onPanelSlide function witch indicates it state from 0.0 (closed / unexpended) to 1.0 (open / expanded). In gif below i have red sliding panel than on expanded set's AnimatedContainers height to 0 and to initial height at closed state. How can i make it change it height dynamically so it would set it height to 0 at the same time as sliding panel would fully open?
You could simply use a Container with height parameter set every onPanelSlide call
const NAV_BAR_HEIGHT = 100.0;
double height = NAV_BAR_HEIGHT;
onPanelSlide: (double position) {
setState((){
height = NAV_BAR_HEIGHT - position * NAV_BAR_HEIGHT;
});
}
Container(
height:height,
child: MyNavBar(),
)
I have created a scrollable area and i am trying to add a scrollbar underneath the images (the blue scrollbar in the linked image)
Code that i currently have for the scrollable area.
scroll = new ScrollComponent
opacity: 1.00
shadowBlur: 0
scroll.size = screen
Info.parent = scroll.content
scroll.scrollVertical = false
Scroll
I think you're trying to make a scrollbar that moves with the scrolling and shows how far along the user has scrolled, right?
Here's some code how to do that:
scrollbar.parent = scroll
# First make the width of the scrollbar relative to the size of the content.
scrollbar.width = (scroll.width / scroll.content.width) * scroll.width
# When the scroll is moved
scroll.onMove ->
# Calculate the width that we should scroll over
width = scroll.content.width - scroll.width
# Calculate the percentage that has currently been scrolled
percentage = scroll.scrollX / width
# Calculate how much space there for the scrollbar to move in
freeSpace = scroll.width - scrollbar.width
# Set the position of the scrollbar relative to the free space and the percentage scrolled
scrollbar.x = freeSpace * percentage
A full example is here: https://framer.cloud/QtcLD
The Problem
I'm trying to figure out a way to get at which point in the content node the scroll pane's viewport is centered on.
To elaborate on the picture above, the big rectangle is the content (let's say a large image), and the small rectangle is the portion that is shown by the scroll pane. I'm trying to find x and y which would be coordinates from the top left of the content.
What I've Tried
My first thought was to use the getViewportBounds() method of the scroll pane and use its minX and maxX properties to determine the center x point:
Bounds b = scrollPane.getViewportBounds();
double centerX = (b.getMinX() + b.getMaxX()) / 2;
double centerY = (b.getMinY() + b.getMaxY()) / 2;
However, this doesn't work because these numbers are negative and don't seem to accurately describe the x and y I'm looking for anyways.
My next thought was to use the scroll pane's hValue and vValue to get the top left corner of the viewport relative to the content:
Bounds b = scrollPane.getViewportBounds();
double centerX = scrollPane.getHvalue() + b.getWidth() / 2;
double centerY = scrollPane.getVvalue() + b.getHeight() / 2;
This didn't work either though as the hValue and vValue seem to be way too large (when scrolled in only a few pixels, I'm getting numbers like 1600).
My Questions
I seem to have a fundamental misunderstanding of how the viewport works with a scroll pane.
What am I doing wrong here? Can someone explain where these numbers come from? How do I find x and y like in the picture above?
Let (x, y) be the be coordinates of the top, left point shown in the viewport. You can write this as
((contentWidth - viewportWidth) * hValueRel, (contentHeight - viewportHeight) * vValueRel)
vValueRel = vValue / vMax
hValueRel = hValue / hMax
This means assuming hmin and vmin remain 0 you can keep a circle in the center of like this:
// update circle position to be centered in the viewport
private void update() {
Bounds viewportBounds = scrollPane.getViewportBounds();
Bounds contentBounds = content.getBoundsInLocal();
double hRel = scrollPane.getHvalue() / scrollPane.getHmax();
double vRel = scrollPane.getVvalue() / scrollPane.getVmax();
double x = Math.max(0, (contentBounds.getWidth() - viewportBounds.getWidth()) * hRel) + viewportBounds.getWidth() / 2;
double y = Math.max(0, (contentBounds.getHeight() - viewportBounds.getHeight()) * vRel) + viewportBounds.getHeight() / 2;
Point2D localCoordinates = content.parentToLocal(x, y);
circle.setCenterX(localCoordinates.getX());
circle.setCenterY(localCoordinates.getY());
}
private Circle circle;
private Pane content;
private ScrollPane scrollPane;
#Override
public void start(Stage primaryStage) {
// create ui
circle = new Circle(10);
content = new Pane(circle);
content.setPrefSize(4000, 4000);
scrollPane = new ScrollPane(content);
Scene scene = new Scene(scrollPane, 400, 400);
// add listener to properties that may change
InvalidationListener l = o -> update();
content.layoutBoundsProperty().addListener(l);
scrollPane.viewportBoundsProperty().addListener(l);
scrollPane.hvalueProperty().addListener(l);
scrollPane.vvalueProperty().addListener(l);
scrollPane.hmaxProperty().addListener(l);
scrollPane.vmaxProperty().addListener(l);
scrollPane.hminProperty().addListener(l);
scrollPane.vminProperty().addListener(l);
primaryStage.setScene(scene);
primaryStage.show();
}
I have a map app where the user can place waypoints manually. I would like for them to press the waypoint button and have a waypoint placed in the center of their currently visible view on the content view.
I'm afraid you'd have to calculate it yourself. contentSize returns size of the scrolled content, contentOffset gives you the origin of the scroll view inside the content. Then with scrollView.bounds.size you can find the center of the view.
Haven't tested this, but maybe you could convert scrollView.center to your scrolled map like this:
CGPoint viewportCenterInMapCoords =
[scrollView.superview convertPoint:scrollView.center
toView:mapViewInsideScrollView];
Need to account for how zoomed it is, then I can convert the content offset to the size of the full image and add some.
/// this is the full size of the map image
CGSize fullSize = CGPointMake(13900, 8400);
/// determines how the current content size compares to the full size
float zoomFactor = size.width/self.contentSize.width;
/// apply the zoom factor to the content offset , this basically upscales
/// the content offset to apply to the dimensions of the full size map
float newContentOffsetX = self.contentOffset.x*zoomFactor + (self.bounds.size.width/2) *zoomFactor-300;
float newContentOffsetY = self.contentOffset.y*zoomFactor + (self.bounds.size.height/2) * zoomFactor-300;
/// not sure why i needed to subtract the 300, but the formula wasn't putting
/// the point in the exact center, subtracting 300 put it there in all situations though
CGPoint point = CGPointMake(newContentOffsetX,newContentOffsetY );