toniantunovi / ion-bottom-drawer

Bottom drawer component for Ionic 4
63 stars 16 forks source link

mobile cannot scroll data with overflow scroll of css #10

Open CHUN-WEI-HSU opened 5 years ago

CHUN-WEI-HSU commented 5 years ago

I cannot scroll data with ion-list, even I used following code, hammerjs still influence child elements.

    ion-bottom-drawer{
        .scroll-content{
            touch-action: auto !important;
        }       
    }

this is good plugin. thanks your assistance, sorry for my bad english.

Kernolsie commented 5 years ago

My workaround fix:

Add a scrollable div with a fixed height in the drawer:

<div scrollY="true" id="myScrollDiv">
   your contents or list or whatever
<div>

and on the CSS side:

#myScrollDiv {
  height: 150px;
}

div[scrollx=true], div[scrolly=true] {
  position: relative;
  overflow: hidden;

  ::-webkit-scrollbar {
    display: none;
  }
}

div[scrollx=true] {
  overflow-x: auto;
}

div[scrolly=true] {
  overflow-y: auto;
}

The problem is that the scrolling of the inner div influences the parent drawer to move, we don't want that, so:

Now, you want only the top of your drawer to have a draggable item (you can style this div and size it as your heart desires) which Enables or Disables the disableDrag property of the ion-bottom-drawer on its (touchstart) and (touchend) events. The dashScrollDisabled is a boolean in my class which is toggled by the drawerActuator div as seen below:

<ion-bottom-drawer [(state)]="state" [minimumHeight]="80" [dockedHeight]="80" [shouldBounce]="true"
    [distanceTop]="distanceFromTop" [disableDrag]="dashScrollDisabled">
  <div class="drawer-content" style='height:100%'>
    <div class='drawerActuator' (touchstart)='enableDashScroll()' (touchend)='disableDashScroll()'> 
    </div>
    <div scrollY="true" id="myScrollDiv">
       your contents or list or whatever
    <div>
  <div>
</ion-bottom-drawer>
SirBenedick commented 5 years ago

@Kernolsie it seems like your solution does not work on mobile. My browser is fine but using the DevApp there is no scroll functionality. Any suggestions?

Kernolsie commented 5 years ago

@SirBenedick My implementation is on mobile so I doubt that it is the problem. Is there enough items in your list to overflow the div so that you have something to scroll to? Explain what happens then, is everything including the drawer just stationary or what? iOS or Android?

SirBenedick commented 5 years ago

@Kernolsie test DevApp with iOS. Using the --lab flag my implementation works fine on android and iOS. I used you css (only changed the height to 300px) There are two lists and one card included in myScrollDiv. The lists are definitely long enough. Not quit sure what you mean with 'stationary'. The drawer is always visible on the 'home' page and the contend within the drawer depends on what is selected.

Thanks for helping 🙏

<h1>{{ selectedLocation.title }}</h1>
<div scrollY="true" id="myScrollDiv">
    <ion-item-group *ngIf="selectedLocation.food">
        [...]
    </ion-item-group>
    <ion-item-group *ngIf="selectedLocation.drinks">
        [...]
    </ion-item-group>
    <ion-card>
        [...]
    </ion-card>
</div>
SirBenedick commented 5 years ago

@Kernolsie could you upload a working example? I tried to replicate it again, but I can not get it working.

IvanMoreFlores commented 5 years ago

@Kernolsie Sorry, but you could show the .ts code and the .css of this code, I've been trying to solve the scroll problem for several days, thanks

<div class='drawerActuator' (touchstart)='enableDashScroll()' (touchend)='disableDashScroll()'> 
    </div>
jsmith347 commented 5 years ago

@IvanMoreFlores @toniantunovi This seems to be an issue with hammerjs handling the pan events for the ion-bottom-drawer

My workaround that worked on iOS and Android was to copy the ion-bottom-drawer folder at:

https://github.com/toniantunovi/ion-bottom-drawer/tree/master/src/app/modules/ion-bottom-drawer

and pasting it into my projects components folder and including the copied version where I use the component.

The following change must then be made in the ion-bottom-drawer.ts file:

hammer.get('pan').set({ enable: true, direction: Hammer.DIRECTION_VERTICAL });

must be changed to:

hammer.get('pan').set({ enable: false, direction: Hammer.DIRECTION_VERTICAL }); at line 45.

maximilianloy commented 5 years ago

Same here. Was not working for me on iOS (Android was ok) but with workaround from @jsmith347 its working!

prescindivel commented 5 years ago

I tried with @IvanMoreFlores solution and it worked great on Android, but on ios the ion-bottom-drawer state property has stopped working, I use it to swap a "docked" and "undocked" class.

Bounce also stopped working on iOS.

I tried using @jsmith347 workaround but it didn't work on Android or ios

synapp009 commented 5 years ago

@Kernolsie solution works for me. Add this to your .ts :

export class yourApp { shouldBounce = true; }

enableDashScroll() { this.disableDrag = false; } disableDashScroll() { this.disableDrag = false; }

@prescindivel is right: no Bounce-Animation any more

raminnoodle commented 5 years ago

I cant for the life of me get this working in iOS. Iv tried so many different methods to get scrolling within a drawer to work with no avail. It works fine in the browser but once it goes into the ios simulator or device it doesn't scroll. I tried using a copy of the component with the .get('pan') enabled: false but that totally turns off the ion drawer all the way.

jsmith347 commented 5 years ago

@raminnoodle Have you set the minimumHeight and dockedHeight properties on the ion-bottom-drawer component?

Another thing that I found is that the container of your item list must have a fixed height. For example, in my code I used an ion-grid to hold my list items and defined the height as follows:

     <ion-grid style='height:228px' no-padding>
     ...
     </ion-grid>
raminnoodle commented 5 years ago

Yea I tried that and many other combinations but could never get it to work in the emulator or ios device (spent about 10 hrs). I am pretty sure hammerjs makes changes to the css properties that wont allow anything within the drawer to scroll. In the browser, it worked no problem but never on ios for me. I finally got it to work by using the actuator code mentioned above combined with downloading a local copy of the component source code and modifying it by adding code to the ngOnChange in the ion-bottom-drawer.ts to remove the hammerjs instance when disableDrag was set to true and re-enables hammerjs when the disableDrag is set to false. Finally got it to work!

synapp009 commented 5 years ago

Yea I tried that and many other combinations but could never get it to work in the emulator or ios device (spent about 10 hrs). I am pretty sure hammerjs makes changes to the css properties that wont allow anything within the drawer to scroll. In the browser, it worked no problem but never on ios for me. I finally got it to work by using the actuator code mentioned above combined with downloading a local copy of the component source code and modifying it by adding code to the ngOnChange in the ion-bottom-drawer.ts to remove the hammerjs instance when disableDrag was set to true and re-enables hammerjs when the disableDrag is set to false. Finally got it to work!

I created a <div>Bar in the ion-bottom-drawer.html that disable hammer.js with mousedown/touchstart and at <ion-content></ion-content> the opposit. :)

raminnoodle commented 5 years ago

I tried that as well but it seems that once the pan has been enabled the css doesnt go away when its disabled. I event tried https://hammerjs.github.io/toggle-recognizer/ to create an inline function for the boolean with no luck. I used the code below to remove hammer and re-enable hammer when the disableDrag changes.

ngOnChanges(changes: SimpleChanges) { if (changes.disableDrag) { if (changes.disableDrag.currentValue) { console.log("DISABLED!!!"); this.hammer.off("pan panstart panend", null); this.hammer.remove("pan"); } else { console.log("ENABLED!!!"); this.hammer.off("pan panstart panend", null); this.hammer.remove("pan"); this.hammer = new Hammer(this._element.nativeElement); this.hammer.get("pan").set({ enable: true, direction: Hammer.DIRECTION_VERTICAL }); this.hammer.on("pan panstart panend", (ev: any) => { if (this.disableDrag) { return; } switch (ev.type) { case "panstart": this._handlePanStart(); break; case "panend": this._handlePanEnd(ev); break; default: this._handlePan(ev); } }); } return; }

synapp009 commented 5 years ago

No CSS involved. It's very simple: ion-bottom-drawer.html:

`<div (mousedown)="drawEnable()" (touchstart)="drawEnable()" style="height:30px;width:100%">

<ion-content (mousedown)="drawDissable()" (touchstart)="drawDissable()" id="content" class="ion-bottom-drawer-scrollable-content" no-bounce >

`

ion-bottom-drawer.js:

`drawEnable(){ this.hammer.get('pan').set({ enable: true, direction: Hammer.DIRECTION_VERTICAL }); }

drawDissable(){ this.hammer.get('pan').set({ enable: false, direction: Hammer.DIRECTION_VERTICAL }); }`

At least in Xcode it works fine. Have you tested it on a real device?

raminnoodle commented 5 years ago

Are you using UIWebView or WKWebview?

synapp009 commented 5 years ago

I'm using WKWebView by default ( "cordova-plugin-ionic-webview": "^4.1.1", )

ericjmachado commented 4 years ago

Same problem here, any solution?

rlfrahm commented 4 years ago

The following html/scss only solution worked for me as it allows the user to scroll through a list that is taller than the drawer content area. I can still drag the drawer closed using the top handle though too.

html

<ion-bottom-drawer [(state)]="fontFamilyDrawer.state" [distanceTop]="fontFamilyDrawer.minimumHeight">
  <div class="drawer-content">
    <!-- Step 1: A little handle to grab and drag with and close the drawer -->
    <div padding>
      <div style="background-color: var(--ion-color-medium-tint);width:4rem;height:.25rem;border-radius:6px;display:block;margin:0 auto"></div>
    </div>
    <!-- Step 2: `scrollY="true"` and set a fixed height for the scroll container -->
    <ion-list [style.height]="fontFamilyDrawer.contentHeight" style="overflow-y: auto">
      <!-- ... -->
    </ion-list>
  </div>
</ion-bottom-drawer>

scss

ion-bottom-drawer {
  [scrollY=true] {
    overflow-y: auto;
  }
}

Exhibit A:

Screen Shot 2020-01-05 at 7 00 41 PM

jwburnside commented 4 years ago

@rlfrahm Hey Ryan, thanks for this, it is working almost perfectly in my case. The only small issue is that when scrolling, the catch moves with the list content, so that it disappears from the top. I have been experimenting with trying to get the catch to remain at the top even after scrolling, but have not had much luck so far.

Are you seeing this same behavior? And if not, do you know how I might get the catch to stay visible even while scrolling?

I'm going to continue to mess with it, and will post my results if I succeed, thanks!

DaniilVysotskiy commented 4 years ago

@jwburnside I guess, I've found simple way to control the way the content section inside the drawer is scrolled on touch devices without effecting the drawer state and its position. The solution made up using only ionic native events and drawer options, and keeps up shouldBounce option:

component.html

<ion-bottom-drawer
  class="drawer"
  [(state)]="drawerOptions.drawerState"
  [minimumHeight]="drawerOptions.minimumHeight"
  [dockedHeight]="drawerOptions.dockedHeight"
  [shouldBounce]="drawerOptions.shouldBounce"
  [distanceTop]="drawerOptions.distanceTop"
  [disableDrag]="drawerOptions.disableDrag"
>
  <div class="drawer-content">
    <div class="drawer-toolbar"> // <- Drawer pull-up/pull-down handler area
      <...>
    </div>
    <div
      class="drawer-body"
      (touchstart)="drawDisable()"
      (touchend)="drawEnable()"
    > // <- Drawer inner content area with scrollable list
      <...>
  </div>
</ion-bottom-drawer>

component.ts

// component imports

export class Component implements OnInit {
  drawerOptions: any = {
    shouldBounce: true,
    dockedHeight: 85,
    distanceTop: 56,
    drawerState: DrawerState.Docked,
    states: DrawerState,
    disableDrag: false, // <- By default drag gesture is enabled
    minimumHeight: 85
  };

  constructor( ... ) { ... }

  drawEnable() {
    this.drawerOptions.disableDrag = false;
  }

  drawDisable() {
    this.drawerOptions.disableDrag = true;
  }
}

component.scss

.drawer {
  box-shadow: 0px -1px 3px 0px rgba(0,0,0,.15);
}

.drawer-content {
  position: relative;
}

.drawer-toolbar {
  border-bottom: 2px solid var(--ion-color-light-warm);
  background-color: var(--ion-color-primary-contrast);
  position: fixed;
  top:0;
  left: 0;
  width: 100%;
  z-index: 2;
}

.drawer-body {
  transform: translateY(85px);
  height: calc(100vh - 85px - 56px);
  overflow-y: auto;
}
rlfrahm commented 4 years ago

@rlfrahm Hey Ryan, thanks for this, it is working almost perfectly in my case. The only small issue is that when scrolling, the catch moves with the list content, so that it disappears from the top. I have been experimenting with trying to get the catch to remain at the top even after scrolling, but have not had much luck so far.

Are you seeing this same behavior? And if not, do you know how I might get the catch to stay visible even while scrolling?

I'm going to continue to mess with it, and will post my results if I succeed, thanks!

I'm unfortunately not in front of the project right now, but only my ion-list was scrolling, not the handle. First thing to make sure is that your handle div is outside of the container that you have [scrollY=true] set true on. The second thing is that you have to have [style.height] set for the element that you want to overflow scroll, otherwise I believe the scrolling will bubble up to the parent elements (which sounds like your problem). The way that I test to see what changes I need made is to open up the browser console and just inline edit your drawer to figure out what is going wrong.

rlfrahm commented 4 years ago

@rlfrahm Hey Ryan, thanks for this, it is working almost perfectly in my case. The only small issue is that when scrolling, the catch moves with the list content, so that it disappears from the top. I have been experimenting with trying to get the catch to remain at the top even after scrolling, but have not had much luck so far.

Are you seeing this same behavior? And if not, do you know how I might get the catch to stay visible even while scrolling?

I'm going to continue to mess with it, and will post my results if I succeed, thanks!

I'm unfortunately not in front of the project right now, but only my ion-list was scrolling, not the handle. First thing to make sure is that your handle div is outside of the container that you have [scrollY=true] set true on. The second thing is that you have to have [style.height] set for the element that you want to overflow scroll, otherwise I believe the scrolling will bubble up to the parent elements (which sounds like your problem). The way that I test to see what changes I need made is to open up the browser console and just inline edit your drawer to figure out what is going wrong.

rlfrahm commented 4 years ago

@rlfrahm Hey Ryan, thanks for this, it is working almost perfectly in my case. The only small issue is that when scrolling, the catch moves with the list content, so that it disappears from the top. I have been experimenting with trying to get the catch to remain at the top even after scrolling, but have not had much luck so far.

Are you seeing this same behavior? And if not, do you know how I might get the catch to stay visible even while scrolling?

I'm going to continue to mess with it, and will post my results if I succeed, thanks!

I'm unfortunately not in front of the project right now, but only my ion-list was scrolling, not the handle. First thing to make sure is that your handle div is outside of the container that you have [scrollY=true] set true on. The second thing is that you have to have [style.height] set for the element that you want to overflow scroll, otherwise I believe the scrolling will bubble up to the parent elements (which sounds like your problem). The way that I test to see what changes I need made is to open up the browser console and just inline edit your drawer to figure out what is going wrong.

On Thu, Jan 30, 2020 at 5:53 AM Daniil Vysotskiy notifications@github.com wrote:

@jwburnside https://github.com/jwburnside I guess, I've found simple way to control the way the content section inside the drawer is scrolled on touch devices without effecting the drawer state and its position. The solution made up using only ionic native events and drawer options, and keeps up shouldBounce option:

component.html

<ion-bottom-drawer class="drawer" [(state)]="drawerOptions.drawerState" [minimumHeight]="drawerOptions.minimumHeight" [dockedHeight]="drawerOptions.dockedHeight" [shouldBounce]="drawerOptions.shouldBounce" [distanceTop]="drawerOptions.distanceTop" [disableDrag]="drawerOptions.disableDrag"

// <- Drawer pull-up/pull-down handler area <...>

component.ts

// component imports

export class Component implements OnInit { drawerOptions: any = { shouldBounce: true, dockedHeight: 85, distanceTop: 56, drawerState: DrawerState.Docked, states: DrawerState, disableDrag: false, // <- By default drag gesture is enabled minimumHeight: 85 };

constructor( ... ) { ... }

drawEnable() { this.drawerOptions.disableDrag = false; }

drawDisable() { this.drawerOptions.disableDrag = true; } }

component.scss

.drawer { box-shadow: 0px -1px 3px 0px rgba(0,0,0,.15); }

.drawer-content { position: relative; }

.drawer-toolbar { border-bottom: 2px solid var(--ion-color-light-warm); background-color: var(--ion-color-primary-contrast); position: fixed; top:0; left: 0; width: 100%; z-index: 2; }

.drawer-body { transform: translateY(85px); height: calc(100vh - 85px - 56px); overflow-y: auto; }

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/toniantunovi/ion-bottom-drawer/issues/10?email_source=notifications&email_token=ABIXM5BGLWXJCEWB3O6CKBDRAKWRBA5CNFSM4GJMURZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKKRZVA#issuecomment-580197588, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABIXM5CYQ7CNNUNANU2LN3LRAKWRBANCNFSM4GJMURZA .

roman-rr commented 4 years ago

Hello everyone, don’t sure if this repo under regular maintenance. So try similar component with correct overflow implementation
https://github.com/roman-rr/cupertino-pane/

raminnoodle commented 4 years ago

Hello everyone, don’t sure if this repo under regular maintenance. So try similar component with correct overflow implementation https://github.com/roman-rr/cupertino-pane/

Exactly what iv been looking for! Thank you!

SackeyDavid commented 4 years ago

The following html/scss only solution worked for me as it allows the user to scroll through a list that is taller than the drawer content area. I can still drag the drawer closed using the top handle though too.

html

<ion-bottom-drawer [(state)]="fontFamilyDrawer.state" [distanceTop]="fontFamilyDrawer.minimumHeight">
  <div class="drawer-content">
    <!-- Step 1: A little handle to grab and drag with and close the drawer -->
    <div padding>
      <div style="background-color: var(--ion-color-medium-tint);width:4rem;height:.25rem;border-radius:6px;display:block;margin:0 auto"></div>
    </div>
    <!-- Step 2: `scrollY="true"` and set a fixed height for the scroll container -->
    <ion-list [style.height]="fontFamilyDrawer.contentHeight" style="overflow-y: auto">
      <!-- ... -->
    </ion-list>
  </div>
</ion-bottom-drawer>

scss

ion-bottom-drawer {
  [scrollY=true] {
    overflow-y: auto;
  }
}

Exhibit A:

Screen Shot 2020-01-05 at 7 00 41 PM

Hi @rlfrahm,

How did you get the border radius of the ion-bottom-drawer?

rlfrahm commented 4 years ago

It’s been a while since I did this but I just opened up the Safari console’s elements tab and started applying border-radius until it changed it on the screen.

SackeyDavid commented 4 years ago

It’s been a while since I did this but I just opened up the Safari console’s elements tab and started applying border-radius until it changed it on the screen.

Ok, thank you