mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-23 05:58:26 +08:00
fix(item): improve open/close logic, update demos
This commit is contained in:

committed by
Adam Bradley

parent
0660cb6b4a
commit
db9fa7ead3
@ -1,10 +1,95 @@
|
|||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {ionicBootstrap} from 'ionic-angular';
|
import {ionicBootstrap, ItemSliding, Toast, NavController} from 'ionic-angular';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'main.html'
|
templateUrl: 'main.html'
|
||||||
})
|
})
|
||||||
class ApiDemoApp {}
|
class InitialPage {
|
||||||
|
chats: any[];
|
||||||
|
logins: any[];
|
||||||
|
|
||||||
|
constructor(private nav: NavController) {
|
||||||
|
this.chats = [
|
||||||
|
{
|
||||||
|
img: './avatar-cher.png',
|
||||||
|
name: 'Cher',
|
||||||
|
message: 'Ugh. As if.',
|
||||||
|
time: '9:38 pm'
|
||||||
|
}, {
|
||||||
|
img: './avatar-dionne.png',
|
||||||
|
name: 'Dionne',
|
||||||
|
message: 'Mr. Hall was way harsh.',
|
||||||
|
time: '8:59 pm'
|
||||||
|
}, {
|
||||||
|
img: './avatar-murray.png',
|
||||||
|
name: 'Murray',
|
||||||
|
message: 'Excuse me, "Ms. Dione."',
|
||||||
|
time: 'Wed'
|
||||||
|
}];
|
||||||
|
|
||||||
|
this.logins = [
|
||||||
|
{
|
||||||
|
icon: 'logo-twitter',
|
||||||
|
name: 'Twitter',
|
||||||
|
username: 'admin',
|
||||||
|
}, {
|
||||||
|
icon: 'logo-github',
|
||||||
|
name: 'GitHub',
|
||||||
|
username: 'admin37',
|
||||||
|
}, {
|
||||||
|
icon: 'logo-instagram',
|
||||||
|
name: 'Instagram',
|
||||||
|
username: 'imanadmin',
|
||||||
|
}, {
|
||||||
|
icon: 'logo-codepen',
|
||||||
|
name: 'Codepen',
|
||||||
|
username: 'administrator',
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
more(item: ItemSliding) {
|
||||||
|
console.log('More');
|
||||||
|
item.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(item: ItemSliding) {
|
||||||
|
console.log('Delete');
|
||||||
|
item.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
mute(item: ItemSliding) {
|
||||||
|
console.log('Mute');
|
||||||
|
item.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
archive(item: ItemSliding) {
|
||||||
|
console.log('Archive');
|
||||||
|
item.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
download(item: ItemSliding) {
|
||||||
|
item.setClass('downloading', true);
|
||||||
|
setTimeout(() => {
|
||||||
|
const toast = Toast.create({
|
||||||
|
message: 'Item was downloaded!'
|
||||||
|
});
|
||||||
|
this.nav.present(toast);
|
||||||
|
item.setClass('downloading', false);
|
||||||
|
item.close();
|
||||||
|
|
||||||
|
// Wait 2s to close toast
|
||||||
|
setTimeout(() => toast.dismiss(), 2000);
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: '<ion-nav [root]="root"></ion-nav>'
|
||||||
|
})
|
||||||
|
class ApiDemoApp {
|
||||||
|
root = InitialPage;
|
||||||
|
}
|
||||||
|
|
||||||
ionicBootstrap(ApiDemoApp);
|
ionicBootstrap(ApiDemoApp);
|
||||||
|
@ -8,83 +8,37 @@
|
|||||||
Chats
|
Chats
|
||||||
</ion-list-header>
|
</ion-list-header>
|
||||||
|
|
||||||
<ion-item-sliding>
|
<ion-item-sliding *ngFor="let chat of chats; let ref = index" [ref]="ref" #item>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-avatar item-left>
|
<ion-avatar item-left>
|
||||||
<img src="./avatar-cher.png">
|
<img [src]="chat.img">
|
||||||
</ion-avatar>
|
</ion-avatar>
|
||||||
<h2>Cher</h2>
|
<h2>{{chat.name}}</h2>
|
||||||
<p>Ugh. As if.</p>
|
<p>{{chat.message}}</p>
|
||||||
<ion-note item-right>
|
<ion-note item-right>
|
||||||
9:38 pm
|
{{chat.time}}
|
||||||
</ion-note>
|
</ion-note>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<button secondary>
|
<button secondary (click)="more(item)">
|
||||||
<ion-icon name="menu"></ion-icon>
|
<ion-icon name="menu"></ion-icon>
|
||||||
More
|
More
|
||||||
</button>
|
</button>
|
||||||
<button dark>
|
<button dark (click)="mute(item)">
|
||||||
<ion-icon name="volume-off"></ion-icon>
|
<ion-icon name="volume-off"></ion-icon>
|
||||||
Mute
|
Mute
|
||||||
</button>
|
</button>
|
||||||
<button danger>
|
<button danger (click)="delete(item)">
|
||||||
<ion-icon name="trash"></ion-icon>
|
<ion-icon name="trash"></ion-icon>
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
|
||||||
|
|
||||||
<ion-item-sliding>
|
<ion-item-options side="left">
|
||||||
<ion-item>
|
<button primary expandable (click)="archive(item)">
|
||||||
<ion-avatar item-left>
|
<ion-icon name="archive"></ion-icon>
|
||||||
<img src="./avatar-dionne.png">
|
Archive
|
||||||
</ion-avatar>
|
|
||||||
<h2>Dionne</h2>
|
|
||||||
<p>Mr. Hall was way harsh.</p>
|
|
||||||
<ion-note item-right>
|
|
||||||
8:59 pm
|
|
||||||
</ion-note>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item-options>
|
|
||||||
<button secondary>
|
|
||||||
<ion-icon name="menu"></ion-icon>
|
|
||||||
More
|
|
||||||
</button>
|
|
||||||
<button dark>
|
|
||||||
<ion-icon name="volume-off"></ion-icon>
|
|
||||||
Mute
|
|
||||||
</button>
|
|
||||||
<button danger>
|
|
||||||
<ion-icon name="trash"></ion-icon>
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
</ion-item-options>
|
|
||||||
</ion-item-sliding>
|
|
||||||
|
|
||||||
<ion-item-sliding>
|
|
||||||
<ion-item>
|
|
||||||
<ion-avatar item-left>
|
|
||||||
<img src="./avatar-murray.png">
|
|
||||||
</ion-avatar>
|
|
||||||
<h2>Murray</h2>
|
|
||||||
<p>Excuse me, "Ms. Dione."</p>
|
|
||||||
<ion-note item-right>
|
|
||||||
Wed
|
|
||||||
</ion-note>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item-options>
|
|
||||||
<button secondary>
|
|
||||||
<ion-icon name="menu"></ion-icon>
|
|
||||||
More
|
|
||||||
</button>
|
|
||||||
<button dark>
|
|
||||||
<ion-icon name="volume-off"></ion-icon>
|
|
||||||
Mute
|
|
||||||
</button>
|
|
||||||
<button danger>
|
|
||||||
<ion-icon name="trash"></ion-icon>
|
|
||||||
Delete
|
|
||||||
</button>
|
</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
@ -95,66 +49,26 @@
|
|||||||
Logins
|
Logins
|
||||||
</ion-list-header>
|
</ion-list-header>
|
||||||
|
|
||||||
<ion-item-sliding>
|
<ion-item-sliding *ngFor="let login of logins" #item>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-icon name="logo-twitter" item-left></ion-icon>
|
<ion-icon [name]="login.icon" item-left></ion-icon>
|
||||||
<h2>Twitter</h2>
|
<h2>{{login.name}}</h2>
|
||||||
<p>admin</p>
|
<p>{{login.username}}</p>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options side="left">
|
||||||
<button>
|
|
||||||
edit
|
|
||||||
</button>
|
|
||||||
<button danger>
|
<button danger>
|
||||||
<ion-icon name="trash"></ion-icon>
|
<ion-icon name="trash"></ion-icon>
|
||||||
</button>
|
</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
<ion-item-options (ionSwipe)="download(item)">
|
||||||
|
<button dark (click)="more(item)">
|
||||||
<ion-item-sliding>
|
<ion-icon name="volume-off"></ion-icon>
|
||||||
<ion-item>
|
Mute
|
||||||
<ion-icon name="logo-github" item-left></ion-icon>
|
|
||||||
<h2>GitHub</h2>
|
|
||||||
<p>admin37</p>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item-options>
|
|
||||||
<button>
|
|
||||||
edit
|
|
||||||
</button>
|
</button>
|
||||||
<button danger>
|
<button light expandable (click)="download(item)">
|
||||||
<ion-icon name="trash"></ion-icon>
|
<ion-icon name="download" class="download-hide"></ion-icon>
|
||||||
</button>
|
<div class="download-hide">Download</div>
|
||||||
</ion-item-options>
|
<ion-spinner id="download-spinner"></ion-spinner>
|
||||||
</ion-item-sliding>
|
|
||||||
|
|
||||||
<ion-item-sliding>
|
|
||||||
<ion-item>
|
|
||||||
<ion-icon name="logo-instagram" item-left></ion-icon>
|
|
||||||
<h2>Instagram</h2>
|
|
||||||
<p>imanadmin</p>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item-options>
|
|
||||||
<button>
|
|
||||||
edit
|
|
||||||
</button>
|
|
||||||
<button danger>
|
|
||||||
<ion-icon name="trash"></ion-icon>
|
|
||||||
</button>
|
|
||||||
</ion-item-options>
|
|
||||||
</ion-item-sliding>
|
|
||||||
|
|
||||||
<ion-item-sliding>
|
|
||||||
<ion-item>
|
|
||||||
<ion-icon name="logo-codepen" item-left dark></ion-icon>
|
|
||||||
<h2>Codepen</h2>
|
|
||||||
<p>administrator</p>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item-options>
|
|
||||||
<button>
|
|
||||||
edit
|
|
||||||
</button>
|
|
||||||
<button danger>
|
|
||||||
<ion-icon name="trash"></ion-icon>
|
|
||||||
</button>
|
</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
@ -164,6 +78,19 @@
|
|||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
#download-spinner {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg circle {
|
||||||
|
stroke: white;
|
||||||
|
}
|
||||||
|
.downloading #download-spinner {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.downloading .download-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.chat-sliding-demo ion-note {
|
.chat-sliding-demo ion-note {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
margin-top: -8px;
|
margin-top: -8px;
|
||||||
|
@ -87,10 +87,10 @@ ion-item-sliding.active-slide {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Item Swipeable Animation
|
// Item Expandable Animation
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
button[swipeable] {
|
.button-expandable {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
transition-duration: 0;
|
transition-duration: 0;
|
||||||
@ -105,7 +105,7 @@ ion-item-sliding.active-swipe-left {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-sliding.active-swipe-right button[swipeable] {
|
ion-item-sliding.active-swipe-right .button-expandable {
|
||||||
order: 1;
|
order: 1;
|
||||||
|
|
||||||
padding-left: 90%;
|
padding-left: 90%;
|
||||||
@ -114,7 +114,7 @@ ion-item-sliding.active-swipe-right button[swipeable] {
|
|||||||
transition-property: padding-left;
|
transition-property: padding-left;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-sliding.active-swipe-left button[swipeable] {
|
ion-item-sliding.active-swipe-left .button-expandable {
|
||||||
order: -1;
|
order: -1;
|
||||||
|
|
||||||
padding-right: 90%;
|
padding-right: 90%;
|
||||||
|
@ -269,10 +269,10 @@ export class ItemSliding {
|
|||||||
|
|
||||||
// Check if the drag didn't clear the buttons mid-point
|
// Check if the drag didn't clear the buttons mid-point
|
||||||
// and we aren't moving fast enough to swipe open
|
// and we aren't moving fast enough to swipe open
|
||||||
let isOnResetZone = Math.abs(this._openAmount) < Math.abs(restingPoint / 2);
|
let isCloseDirection = (this._openAmount > 0) === !(velocity < 0);
|
||||||
let isMovingSlow = Math.abs(velocity) < 0.3;
|
let isMovingFast = Math.abs(velocity) > 0.3;
|
||||||
let isDirection = (this._openAmount > 0) === (velocity > 0);
|
let isOnCloseZone = Math.abs(this._openAmount) < Math.abs(restingPoint / 2);
|
||||||
if (isOnResetZone && (isMovingSlow || isDirection)) {
|
if (shouldClose(isCloseDirection, isMovingFast, isOnCloseZone)) {
|
||||||
restingPoint = 0;
|
restingPoint = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,3 +402,23 @@ export class ItemSliding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldClose(isCloseDirection: boolean, isMovingFast: boolean, isOnCloseZone: boolean): boolean {
|
||||||
|
// The logic required to know when the sliding item should close (openAmount=0)
|
||||||
|
// depends on three booleans (isCloseDirection, isMovingFast, isOnCloseZone)
|
||||||
|
// and it ended up being too complicated to be written manually without errors
|
||||||
|
// so the truth table is attached below: (0=false, 1=true)
|
||||||
|
// isCloseDirection | isMovingFast | isOnCloseZone || shouldClose
|
||||||
|
// 0 | 0 | 0 || 0
|
||||||
|
// 0 | 0 | 1 || 1
|
||||||
|
// 0 | 1 | 0 || 0
|
||||||
|
// 0 | 1 | 1 || 0
|
||||||
|
// 1 | 0 | 0 || 0
|
||||||
|
// 1 | 0 | 1 || 1
|
||||||
|
// 1 | 1 | 0 || 1
|
||||||
|
// 1 | 1 | 1 || 1
|
||||||
|
// The resulting expression was generated by resolving the K-map (Karnaugh map):
|
||||||
|
let shouldClose = (!isMovingFast && isOnCloseZone) || (isCloseDirection && isMovingFast);
|
||||||
|
return shouldClose;
|
||||||
|
}
|
||||||
|
|
@ -32,7 +32,7 @@
|
|||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item-options side="left" (ionSwipe)="del($event)" *ngIf="slidingEnabled">
|
<ion-item-options side="left" (ionSwipe)="del($event)" *ngIf="slidingEnabled">
|
||||||
<button primary (click)="archive(item1)">Archive</button>
|
<button primary (click)="archive(item1)">Archive</button>
|
||||||
<button danger (click)="del(item1)" swipeable>Delete</button>
|
<button danger (click)="del(item1)">Delete</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
|
|
||||||
@ -43,7 +43,7 @@
|
|||||||
<p>I think I figured out how to get more Mountain Dew</p>
|
<p>I think I figured out how to get more Mountain Dew</p>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item-options side="left" (ionSwipe)="unread($event)" *ngIf="slidingEnabled">
|
<ion-item-options side="left" (ionSwipe)="unread($event)" *ngIf="slidingEnabled">
|
||||||
<button secondary swipeable (click)="unread(item2)">
|
<button secondary expandable (click)="unread(item2)">
|
||||||
<ion-icon name="ios-checkmark"></ion-icon>Unread
|
<ion-icon name="ios-checkmark"></ion-icon>Unread
|
||||||
</button>
|
</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
@ -52,7 +52,7 @@
|
|||||||
<button primary (click)="archive(item2)">
|
<button primary (click)="archive(item2)">
|
||||||
<ion-icon name="mail"></ion-icon>Archive
|
<ion-icon name="mail"></ion-icon>Archive
|
||||||
</button>
|
</button>
|
||||||
<button danger (click)="del(item2)" swipeable>
|
<button danger (click)="del(item2)" expandable>
|
||||||
<ion-icon name="trash"></ion-icon>Delete
|
<ion-icon name="trash"></ion-icon>Delete
|
||||||
</button>
|
</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
@ -65,7 +65,7 @@
|
|||||||
<p>I think I figured out how to get more Mountain Dew</p>
|
<p>I think I figured out how to get more Mountain Dew</p>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item-options side="left" icon-left (ionSwipe)="unread($event)" *ngIf="slidingEnabled">
|
<ion-item-options side="left" icon-left (ionSwipe)="unread($event)" *ngIf="slidingEnabled">
|
||||||
<button secondary swipeable (click)="unread(item3)">
|
<button secondary expandable (click)="unread(item3)">
|
||||||
<ion-icon name="ios-checkmark"></ion-icon>Unread
|
<ion-icon name="ios-checkmark"></ion-icon>Unread
|
||||||
</button>
|
</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
@ -74,7 +74,7 @@
|
|||||||
<button primary (click)="archive(item3)">
|
<button primary (click)="archive(item3)">
|
||||||
<ion-icon name="mail"></ion-icon>Archive
|
<ion-icon name="mail"></ion-icon>Archive
|
||||||
</button>
|
</button>
|
||||||
<button danger (click)="del(item3)" swipeable *ngIf="slidingEnabled">
|
<button danger (click)="del(item3)" expandable *ngIf="slidingEnabled">
|
||||||
<ion-icon name="trash"></ion-icon>Delete
|
<ion-icon name="trash"></ion-icon>Delete
|
||||||
</button>
|
</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
@ -87,7 +87,7 @@
|
|||||||
One Line w/ Icon, div only text
|
One Line w/ Icon, div only text
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item-options icon-left (ionSwipe)="archive($event)">
|
<ion-item-options icon-left (ionSwipe)="archive($event)">
|
||||||
<button primary (click)="archive(item4)" swipeable *ngIf="slidingEnabled">
|
<button primary (click)="archive(item4)" expandable *ngIf="slidingEnabled">
|
||||||
<ion-icon name="archive"></ion-icon>Archive
|
<ion-icon name="archive"></ion-icon>Archive
|
||||||
</button>
|
</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
@ -102,7 +102,7 @@
|
|||||||
One Line w/ Avatar, div only text
|
One Line w/ Avatar, div only text
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<button primary swipeable>
|
<button primary expandable>
|
||||||
<ion-icon name="more"></ion-icon>More
|
<ion-icon name="more"></ion-icon>More
|
||||||
</button>
|
</button>
|
||||||
<button secondary (click)="archive(item5)">
|
<button secondary (click)="archive(item5)">
|
||||||
@ -158,7 +158,7 @@
|
|||||||
<button primary (click)="archive(item8)">
|
<button primary (click)="archive(item8)">
|
||||||
<ion-icon name="archive"></ion-icon>Archive
|
<ion-icon name="archive"></ion-icon>Archive
|
||||||
</button>
|
</button>
|
||||||
<button secondary swipeable (click)="download(item8)">
|
<button secondary expandable (click)="download(item8)">
|
||||||
<ion-icon name="download" class="download-hide"></ion-icon>
|
<ion-icon name="download" class="download-hide"></ion-icon>
|
||||||
<div class="download-hide">Download</div>
|
<div class="download-hide">Download</div>
|
||||||
<ion-spinner id="download-spinner"></ion-spinner>
|
<ion-spinner id="download-spinner"></ion-spinner>
|
||||||
|
@ -366,7 +366,7 @@ export class Menu extends Ion {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
bdClick(ev) {
|
bdClick(ev: Event) {
|
||||||
console.debug('backdrop clicked');
|
console.debug('backdrop clicked');
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
Reference in New Issue
Block a user