How to stop swipping in flutter (after one swipe animation) - flutter

I am using a list to store my items and changing the items indexes if swiped left or right but now when I am trying to swipe it does not stop I want the swipe to go from 1->2 or 2->3 or 3->2 but instead it goes 1->4 or 4->1.
This code below is the part of my program where I am swiping and calling the functions (where I increased the sensitivity to 15).
return GestureDetector(
onHorizontalDragUpdate: (dis) {
if (dis.delta.dx > 15) {
prevPage();
}
else if (dis.delta.dx < -15) { //User swiped from right to left
nextPage();
}
},
And these are the functions which it is calling.
void nextPage() {
if(currPage !=4) {
setState(() {
currPage += 1;
});
}
}
void prevPage() {
if(currPage != 1) {
setState(() {
currPage -= 1;
});
}
}
How can I fix this situation?
Thanks a lot.

Related

there are delays in calling setState if the list is large

I have a list on the screen which can be large, this list has a cursor that shows the selected item from the list and when the loop starts (there is a time pause in the loop: Timer(Duration(milliseconds: 100), () {}); or change the cursor by touching the element, the cursor should quickly change its position, but when setState is called, the cursor changes its position very slowly with a delay of more than 100 milliseconds if the list is large. Is there a solution (example) to this problem?
void cycle() {
var a = data.duration *
(data.position.length);
play();
Timer(Duration(milliseconds: (60000 / a).floor()), () {
setState(() {
cursor =
operations.cursorMoveForward(cursor, data, _scrollController);
});
if (
cursor.position == position.length - 1 || !onPlay) {
} else {
cycle();
}
});
}

Flutter - Fast swipe detection

I am building an application with swipeable cards in a deck.
Swiping works perfectly fine at any speed so long as I am swiping sort of at least 50% of the distance of the screen.
People don't tend to do this however, it is a better user experience to just swipe a very short distance quickly left or right and have the application detect the intent and complete the scroll action.
My code is as follows:
void _onHorizontalDragStart(DragStartDetails details) {
startDrag = details.globalPosition;
startDragPercentScroll = scrollPercent;
}
void _onHorizontalDragUpdate(DragUpdateDetails details) {
final currentDrag = details.globalPosition;
final dragDistance = currentDrag.dx - startDrag.dx;
final singleCardDragPercent = dragDistance / context.size.width;
setState(() {
scrollPercent = (startDragPercentScroll + (-singleCardDragPercent / widget.cards.length)).clamp(0.0, 1.0 - (1 / widget.cards.length));
});
}
void _onHorizontalDragEnd(DragEndDetails details) {
finishScrollStart = scrollPercent;
finishScrollEnd = (scrollPercent * widget.cards.length).round() / widget.cards.length;
finishScrollController.forward(from: 0.0);
setState(() {
startDrag = null;
startDragPercentScroll = null;
});
}
I am certain there is just something wrong with my math there somewhere that is preventing short, quick swipes from working.
What happens instead is the card moves a short distance and then snaps back to the same card.

Flutter - How to sync two or more PageControllers

In Flutter I canĀ“t assing the same PageController to many PageView. So in need to use two or more PageControllers.
I need to synchronize my ViewPages so that when I slide one another it also slides
How can I sync two or more PageController or PageView?
What I want is every PageView can control others PageView make them all sync no matter which slide.
So if a have A, B and C PageView and I slide A then B and C slides as well... if I slide B then A and C slides... and so on.
You can reference https://github.com/braulio94/menu_flutter
The trick is use NotificationListener to listen ScrollUpdateNotification
and compare two page
_backgroundPageController.page != _pageController.page
code snippet at line 183
new NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
if (notification.depth == 0 &&
notification is ScrollUpdateNotification) {
selectedIndex.value = _pageController.page;
if (_backgroundPageController.page != _pageController.page) {
_backgroundPageController.position
// ignore: deprecated_member_use
.jumpToWithoutSettling(_pageController.position.pixels /
_kViewportFraction);
}
setState(() {});
}
return false;
}
full code
https://github.com/braulio94/menu_flutter/blob/master/lib/screens/pager.dart
To sync two pageviews (in case you want to use different viewfractions for example)
create two controllers, upper with view fraction 0,7 and bottom with 1.0
Now to sync add listener to upper and get current scroll offset value.
#override
void initState() {
super.initState();
_controller_upper = new PageController(viewportFraction: 0.7);
_controller_bottom = new PageController();
_controller.addListener(_onScroll);
}
void _onScroll() {
scrollValue = _controller.page;
//page returns value between 0 to 1 for 1st page, 1 to 2 for second and s on, need to multiply it by screen width
_controller_bottom.jumpTo(scrollValue*MediaQuery.of(context).size.width);
}
There is another solution. When you create controllers you can add listeners for each of. In every listener you should describe logic for another controller.
To be more clear I will describe in more detail. If necessary, you can combine the logic into one method, but it will be less clear.
int _previousPage = 0;
bool _isController1 = false;
bool _isController2 = false;
void resetMoveInfo(){
_isController1 = false;
_isController2 = false;
}
void _onController1Scroll() {
if (_isController2)
return;
_isController1 = true;
if (_controller1.page.toInt() == _controller1.page) {
_previousPage = _controller1.page.toInt();
resetMoveInfo();
}
_controller2.position
// ignore: deprecated_member_use
.jumpToWithoutSettling(_controller1.position.pixels * _viewPortFraction);
}
void _onController2Scroll() {
if (_isController1)
return;
_isController2 = true;
if (_controller2.page.toInt() == _controller2.page) {
_previousPage = _controller2.page.toInt();
resetMoveInfo();
}
_controller1.position
// ignore: deprecated_member_use
.jumpToWithoutSettling(_controller2.position.pixels / _viewPortFraction);
}
When you initialize your controller you should add listener for each of them
_controller1 = PageController(
initialPage: _previousPage,
keepPage: false,
viewportFraction: 1)
..addListener(_onController1Scroll);

Unity 2D: Timer in while loop not working, loop stays forever

I want my boost work by starting at 0 when the game starts.
In my game I can pick up boost coins to fill up my booster canister.
public static int boost;
private void OnTriggerEnter2D(Collider2D otherObject)
{
if (otherObject.tag == "Boost")
{
boost++;
GetComponent<AudioSource>().PlaySound(BoostSound, 5.7F);
Destroy(otherObject.gameObject);
}
}
After the player picks up enough boost coins to use the booster in the 2d vehicle.
you need a minimum of 3 boost to start booster. Each booster coin is equal to 1 second of boost.
I just want the player to be able to use the booster if they have over 3 boost coins collected, if they have 3 or more than that represents how many seconds they can use the boost for.
Button call code
public void BoostButton()
{
StartCoroutine("Use_VehicleBoost");
}
Booster code that a button calls.
IEnumerator Use_VehicleBoost()
{
// Check which boost package player picked
int boostLevel = SecurePlayerPrefs.GetInt("BoostLevel");
if (boostLevel == 0)
{
Debug.Log("Boost Level: None");
yield return null;
}
else if (boostLevel == 1)
{
Debug.Log("Boost Level: 1");
float aceleRate = 400, maxFWD = -2500;
while (Player.boost >= 3)
{
vehicleController.GetComponent<CarMovement>().accelerationRate += aceleRate;
vehicleController.GetComponent<CarMovement>().maxFwdSpeed += maxFWD;
// Meant to slowly take one point/ Time second away from boost tank
Player.boost = Player.boost - Mathf.RoundToInt(Time.deltaTime);
}
if (Player.boost <= 0)
{
yield return null;
}
}
yield return null;
}
Problem: code stuck inside while loop so Unity freezes. It can never escape the loop but how if Im calling --boost using deltaTime while the loop running.
If you want to use that while loop to check, use it into IEnumerator and wait every frame. Eg:
IEnumerator Use_VehicleBoost(){
...
while (Player.boost >= 3)
{
yield return null;
}
...
}
I've done this by setting a bool in update to flip true when the ability is activated, and flip false once the conditions are no longer met. A method is also called when that bool flips true that holds the desired behavior. I was actually having the same issue as you and didn't realize yield return null was the solution, so this is what I came up with.
if (ultCharge >= pilotUltMin && !pilotUlting && !pilotUltingPressed)
{
if (Input.GetButton(bumperR1))
{
pilotUltingPressed = true;
pilotUlting = true;
curCharge = ultCharge;
pilotUltingPressed = false;
}
}
if (pilotUlting)
{
PilotUlt();
}
}
private void PilotUlt()
{
if (ultCharge > curCharge - pilotUltMax && ultCharge >= 0)
{
rb.AddRelativeForce(Vector2.up * SwitchController.ShipSpeed * 1.5f, ForceMode2D.Impulse);
ultCharge -= 0.7f;
ultExhaust1.SetActive(true);
ultExhaust2.SetActive(true);
}
else
{
pilotUlting = false;
ultExhaust1.SetActive(false);
ultExhaust2.SetActive(false);
}
}

To restart the game on a button click in unity framework

this is my code
void Start () {
GetComponent<SpriteRenderer>().enabled = false;
animator = transform.GetComponentInChildren<Animator>();
if (animator == null) {
Debug.LogError("Didn't find animator");
}
}
}
GetComponent<Rigidbody2D>().AddForce(Vector2.right * forwardSpeed);
if (didFlap) {
GetComponent<Rigidbody2D>().AddForce (Vector2.up * flapSpeed);
animator.SetTrigger("Doflap");
didFlap = false;
time = 0;
}
// Do graphics & input update
void Update(){
if(Input.GetKeyDown(KeyCode.Space) || (Input.GetMouseButtonDown(0))){
didFlap=true;
}
}
public void TakeDamage(float tim) {
Application.LoadLevel(Application.loadedLevel);
}
// Do physics engine update
void FixedUpdate () {
if (dead) {
Time.timeScale = 0;
GetComponent<SpriteRenderer>().enabled = true;
if(Time.timeScale == 0 && (Input.GetKeyDown (KeyCode.Space) || Input.GetMouseButtonDown (0))){
Application.LoadLevel(Application.loadedLevel);
here when i give the line(Application.LoadLevel(Application.loadedLevel);) with out if the game restarts.but when i give inside the if its not working..on the game dead i set the Time.timeScale to 0,and a restart button appears on the screen.on a touch again i need to restart.but when i gave the code for restart inside the if its not working,when i give it with out if the game suddenly restarts after dead with out giving a space to click the restart button.
i need to restart on the button click
}
}
void OnCollisionEnter2D(Collision2D collision){
animator.SetTrigger("Death");
dead = true;
}
}
When you set the TimeScale to 0, your Inputs will also stop working as they are dependant on the actual Time ;-) You could however still use the Input.GetAxisRaw to achieve similar goal. As it is not depending on the TimeScale.
But a better solution is to just add a UI Button that are available in unity 4.6+, using their new built in UI.