feat:update demo

This commit is contained in:
pengfei.zhou 2020-03-04 13:58:47 +08:00 committed by osborn
parent e7ac263921
commit 9394e8927e

View File

@ -1,4 +1,4 @@
import { Group, text, gravity, Color, LayoutSpec, vlayout, hlayout, layoutConfig, scroller, Text, ViewHolder, VMPanel, ViewModel, network, loge, HLayout, stack, image, Gravity, takeNonNull, Scroller, Image } from "doric"; import { Group, text, gravity, Color, LayoutSpec, vlayout, hlayout, layoutConfig, scroller, Text, ViewHolder, VMPanel, ViewModel, network, loge, HLayout, stack, image, Gravity, takeNonNull, Scroller, Image, View } from "doric";
import { colors } from "./utils"; import { colors } from "./utils";
import MovieData from './movie.json' import MovieData from './movie.json'
@ -67,15 +67,20 @@ interface DoubanModel {
interface MovieModel { interface MovieModel {
doubanModel?: DoubanModel doubanModel?: DoubanModel
selectedIdx: number selectedIdx: number
anchorPos: number
} }
const frameWidth = 200
const frameHeight = 300
const padding = 20
class MovieVH extends ViewHolder { class MovieVH extends ViewHolder {
title!: Text title!: Text
gallery!: HLayout gallery!: HLayout
scrolled!: Scroller scrolled!: Scroller
movieTitle!: Text movieTitle!: Text
movieYear!: Text movieYear!: Text
anchor!: View
build(root: Group) { build(root: Group) {
vlayout( vlayout(
[ [
@ -110,9 +115,20 @@ class MovieVH extends ViewHolder {
}), }),
vlayout( vlayout(
[ [
text({ stack(
text: "↑", [
this.anchor = image({
imageBase64: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAANb0lEQVR4Xu2de6wcVR3Hv7+9tyTEQLhzS0zUINg7W6Lwjw9QEF9Ay5vykoeI4ut2ZyExJhqNMaIxJBgjiXRnKSjlTWmhtLQ8W4q8hZqYaATc2SbgH8aE7rkYjRrp3WMutFAovTtzdubMnD3f+++e3+N8fueTvfuaEfCPBEhgnwSEbEiABPZNgILwdJDAPAQoCI8HCVAQngESMCPAZxAzbozyhAAF8WTQ3KYZAQpixo1RnhCgIJ4Mmts0I0BBzLgxyhMCFMSTQXObZgQoiBk3RnlCgIJ4Mmhu04wABTHjxihPCFAQTwbNbZoRoCBm3BjlCQEK4smguU0zAhTEjBujPCFAQTwZNLdpRoCCmHFjlCcEKIgng+Y2zQhQEDNujPKEAAXxZNDcphkBCmLGjVGeEKAgngya2zQjQEHMuDHKEwIUxJNBc5tmBCiIGTdGeUKAgngyaG7TjAAFMePGKE8IUBBPBs1tmhGgIGbcGOUJAQriyaC5TTMCFMSMG6M8IUBBPBk0t2lGgIKYcWOUJwQoiCeD5jbNCFAQM26M8oQABSl50BPt7hG12Z2L9NjYpO7rhXPtSE121DR26LHxTm/6sBdLbtHr8hSkhPEvXJF8dHZMzhatzwRwxPwtyDbR/Q2zNbn/1Ub4hxLa9bokBbE4/oPaLxxa0+OXA/pyQBZkKi34H/q4pq9fu+bVyz78cqZYLjYmQEGM0WULnIyTi7XGLyB4b7bIvVb/XYCf9aKwNWQehqcgQEFSQBp2SRAn3wZw9bB59owXjdt6zfDiPHMy194EKEjBp2KynTyqNT5XTBnZqqKp44vJzayvv2FCDMURmIyT32rgs8VVeD3zVhWFlKQgyBSkILBBO3kMGp8pKP3b02r9iGrWT7BSy7MiFKSAgQdx53FAjisg9Twp9RYV1U+0W3P0q1GQnGccxJ0nAPl0zmnTpdPYrJrhknSLuSoNAQqShlLKNUGcPAng2JTLi1r2sIrCpUUl9y0vBclp4kG7+yS0LluO3bt5SEXhSTltzes0FCSH8Qdx8hSAY3JIlWMKeVBFUyfnmNDLVBRkyLEH7eRpaHxqyDTFhGs8qJohJRmCLgUZAl4QJ88A+OQQKWyEPqCi8BQbhUaxBgUxnGoQJ78DcLRhuN0wre9XzfqpdouORjUKYjDHIO48C8hRBqElhsh9Kpo6rcQGnCxNQTKOLYg7zwHyiYxhlVguwKZeFJ5eiWYcaYKCZBhUEHefA7STcuzepgAbe1F4RoZte72UgqQcf9DuboPWH0+5vNLLRGNjr0lJ0gyJgqSgNBEnvxfgYymWOrNEA/fOROHcT375Nw8BCjLgeIzSM8c7t6o1Nsw0w2U0ZN8EKMg8pyNoJdsgGIl/q/a1TQ2sn4nCsyjJuxOgIPs4GaPwgjz1oddyj2pOnZ16vUcLKci7DNvlt3LNz66sU9HUOebxoxlJQd4x1yBOngXg2IeAOR1OrdepZp2S7IGTguwBw6mvj+TkxN5p9N0qqp9bWHrHElOQXQOjHHucXI27VDM8z7GzXEi7FASAI9/KLeQAzJN0rYrCL9ouWrV63gtCOeY5koI1qhGeX7VDa7MfrwWp9I+dbJ6CeWvJnSqauqAy7VhuxFtBglbyNKSivwS0fAgGlhNZrRpTFw5cN4ILvBSkmr8hr/rp0qtVVPdOEu8EqdjVR6puxdv7E32HatQvcqvp4br1SpCKXLdquImVHC3A7b0o/FLJbVgr740gQdx9AtDlXPHQ2jjtFBLBbb2GH7de8EKQUi8HaufMWq8iwK29KPyy9cKWC468IEHcfRzQli8kbXmKJZXTgltmGuElJZW3UnakBbF6CwIr46peEQ3cMhONriQjK0jQSh6DWLo/R/XOrdWONHDzTBR+xWpRS8VGUhBLd3ayNCJXyuibVFT/qivdpu1z5AShHGlHX8A6kRtVY+rSAjKXlnKkBJmMk0c1irphZmkzcq3wKhWFX3Ot6X31OzKCTMTJo0I5qnEuBTeoRvj1ajQzXBcjIchEnGwV4PPDoWB0rgS0vkE1685L4rwglCPXY513st+oKPxG3klt5nNakCBOHgHwBZvAWCszgV+rKPxm5qiKBDgrSNDuboHWx1eEI9uYj4DgetUIv+UiJCcFCdqdLdBCOZw6cXKdiqamnWoZgHOCBHF3M6BPcA00+507bbJSNaaWu8TCKUGCuLMZEMrh0gnbq1d9nYrqzjyTOCNI0E4ehsaJTp8NNr+LgDuSOCFI0Oo8DBHKMUqCaVyvmtV/4V55QYI4eQjAklE6G9zLLgIOvLtVaUGCOHkQwFIeqJEmUOnPSSorCOUYaSneubnKSlJJQYI4eQDASV4dEW62kl9LqZwgQSt5AEI5vPSlgl9wrJQgQZzcD+BkLw8HN/0GAY0bVLM6X5WvjCCUg4a8RUCvUlG9Ej+6qoQgQatzH0RO4REhgT0IVOKXiaULEsTdTYA+lUeDBPYiIPpG1aiX+hv3UgUJ4s4mQCgH3dg3gZIvBFGaIJNxslEDp/FskMBgAuVdUqgUQSbjzkYNoRyDTwZX7P56Y0kXp7MuyGSc3KuB0zl5EshKoIwrOFoVZLKV3KuFcmQ9GFy/xxvAlq8FbE2QiTjZIMAZHDYJDEvA5lXlrQgy0e6uF63PHBYM40lgNwFb9ycpXJCJVrJeBJSDZzt3AjYkKVSQibh7j0Avy50ME5LALgJF3w6uMEEm4uQeASgHj3LhBAT69l5UL+TGooUIErS66yD6rMLJsAAJ7H4mKejuu7kLErQ66yBCOXh07RMo4D7uuQoSxN27AX22fTKsSAJvvii5QzWmLsqLR26CBHFyF4Bz8mqMeUjAnIBeraL6hebxb0XmIgjlyGMUzJEzgTtVFF4wbM6hBQnayVponDtsI4wngQIIDC3JUIIErWQthHIUMFimzIuAxhrVDM83TWcsSBAnawCcZ1qYcSRgjYBgjWqYSWIkyGSrc5UW+Z61DbIQCQxJQICrelH4/axpMgsStLrnQ/TqrIW4ngRKJ6D7F6jm4juz9JFJkIOv3R7O9vubAXwwSxGuJYFqEJCXxmqy5JXli5K0/WQShF8hSYuV66pLQNapaCr153WpBZlYuf1Ime3/sbobZ2ckkI6A6P5RvebibWlWpxYkaHV+BJGfpknKNSRQaQKCq1Uj/E6aHtMLEicvAzgkTVKuIYGKE/ibisL3p+kxlSATcedUgWxKk5BrSMAFAoL+Wb1o8fpBvaYUJLlSgB8MSsbHScAVAhq4ciYKfzio37SCrBCgOSgZHycBVwhojRUzzfDyQf2mFeQmAS4ZlIyPk4A7BNJdzjSVIEG7uw6aP6F1Z/jsdDCBdJ+HpBSkswVajh9clCtIwBUCeouK6icO6jadIHH354D+7qBkfJwEnCGQ8rOQdIK0k6XQmLtnOf9IYCQISB/LepeFGwZtJp0gv0oOxDh6AMYHJeTjJOAAgZ16rLZwZnrRPwb1mkqQuSRBnMw9gywdlJCPk4ADBLaqKEz1mjq9IO3kx9C4woHNs0USmJ+AxhWqGf4kDabUgmDNn/cLduz3OICj0yTmGhKoJAGNZ9X41HGYltfS9JdeEACTK5IzdQ0Dv7+SpjDXkEAZBKQ/u6x32eEDX5zv7i2TIK+/Fml1roXIdBmbY00SGIqA1itVs748S47Mgkys3H6I9PuboHFklkJcSwKlEhD5k67JaTPTi/6apY/MgswlP6j9wqE1veBWQB+bpRjXkkApBDSe6dfGL3q1cdhLWesbCTJX5ICVf1m4YGftFghOylqU60nAIoGHXht7z8X/nH7fDpOaxoLMFfvAL5/e/9/7H3wzLz1qgp4xFgisPXD/8UteuvSw/5rWGkqQ3UWDVrIEoi8FZOiLBZtuhHEk8CYBkTsgtVVq+YfmLlE11F8ugrwlSveYN0TRxwGyeKjOGEwCWQgIngfkKYhepZaHz2QJnW9troLsWWjhVS8egAPG67Na6oKdlCXtxGo1nXap9+s0nu/XxjoLZv+z/ZXmR/5VBI/CBCmiWeYkAdsEKIht4qznFAEK4tS42KxtAhTENnHWc4oABXFqXGzWNgEKYps46zlFgII4NS42a5sABbFNnPWcIkBBnBoXm7VNgILYJs56ThGgIE6Ni83aJkBBbBNnPacIUBCnxsVmbROgILaJs55TBCiIU+Nis7YJUBDbxFnPKQIUxKlxsVnbBCiIbeKs5xQBCuLUuNisbQIUxDZx1nOKAAVxalxs1jYBCmKbOOs5RYCCODUuNmubAAWxTZz1nCJAQZwaF5u1TYCC2CbOek4RoCBOjYvN2iZAQWwTZz2nCFAQp8bFZm0ToCC2ibOeUwQoiFPjYrO2CVAQ28RZzykCFMSpcbFZ2wQoiG3irOcUAQri1LjYrG0CFMQ2cdZzigAFcWpcbNY2AQpimzjrOUWAgjg1LjZrmwAFsU2c9ZwiQEGcGhebtU2AgtgmznpOEaAgTo2LzdomQEFsE2c9pwhQEKfGxWZtE6AgtomznlMEKIhT42KztglQENvEWc8pAhTEqXGxWdsEKIht4qznFAEK4tS42KxtAhTENnHWc4oABXFqXGzWNgEKYps46zlF4P96ztDnxVFciwAAAABJRU5ErkJggg==",
layoutConfig: layoutConfig().just(),
width: 30,
height: 30,
}), }),
],
{
layoutConfig: layoutConfig().fit().configWidth(LayoutSpec.MOST),
}
),
this.movieTitle = text({ this.movieTitle = text({
textSize: 20, textSize: 20,
}), }),
@ -140,51 +156,95 @@ class MovieVM extends ViewModel<MovieModel, MovieVH>{
network(context).get("https://douban.uieee.com/v2/movie/top250").then(ret => { network(context).get("https://douban.uieee.com/v2/movie/top250").then(ret => {
this.updateState(state => state.doubanModel = JSON.parse(ret.data) as DoubanModel) this.updateState(state => state.doubanModel = JSON.parse(ret.data) as DoubanModel)
}) })
this.updateState(state => {
state.anchorPos = padding + frameWidth / 2
state.selectedIdx = 0
})
let scrollX = 0
vh.scrolled.onScroll = (offset) => { vh.scrolled.onScroll = (offset) => {
const frameWidth = 270 / 2 * 1.5 if (offset.x < 0 || offset.x > (state.doubanModel?.count || 0) * frameWidth + padding * 2 - Environment.screenWidth) {
const centerX = offset.x + Environment.screenWidth / 2 return
const idx = Math.floor(centerX / frameWidth) }
if (state.selectedIdx != idx) { const dx = offset.x - scrollX
scrollX = offset.x
const idx = Math.floor((offset.x + state.anchorPos - padding) / frameWidth)
if (state.selectedIdx !== idx) {
this.updateState(state => state.selectedIdx = idx) this.updateState(state => state.selectedIdx = idx)
} }
const overOff = Math.abs(centerX - frameWidth * (idx + 0.5)) takeNonNull(this.images.get(idx))(it => {
const scale = overOff / (frameWidth / 2) const scale = (offset.x + state.anchorPos - (idx + 0.5) * frameWidth - padding) / (frameWidth / 2)
takeNonNull(this.images.get(idx))(v => { it.scaleX = it.scaleY = 1.5 - Math.abs(scale * 0.5)
v.scaleX = v.scaleY = 1.5 - 0.5 * scale })
this.updateArrow()
}
}
updateArrow() {
takeNonNull(this.images.get(this.getState().selectedIdx))(it => {
it.getLocationOnScreen(context).then(ret => {
this.getViewHolder().anchor.centerX = ret.x + frameWidth / 2
})
}) })
} }
onItemClicked(idx: number) {
takeNonNull(this.images.get(this.getState().selectedIdx)?.superview)(it => {
it.scaleX = it.scaleY = 1
})
takeNonNull(this.images.get(idx)?.superview)(it => {
it.getLocationOnScreen(context).then(ret => {
let anchor = this.getState().anchorPos
if (ret.x < 0) {
this.getViewHolder().scrolled.scrollBy(context, { x: ret.x, y: 0 }, true)
anchor = frameWidth / 2
} else if (ret.x > Environment.screenWidth - frameWidth) {
this.getViewHolder().scrolled.scrollBy(
context,
{ x: ret.x - (Environment.screenWidth - frameWidth), y: 0 },
true)
anchor = Environment.screenWidth - frameWidth / 2
} else {
anchor = ret.x + frameWidth / 2
}
this.updateState(state => {
state.selectedIdx = idx
state.anchorPos = anchor
})
})
})
} }
onBind(state: MovieModel, vh: MovieVH) { onBind(state: MovieModel, vh: MovieVH) {
if (state.doubanModel) { if (state.doubanModel) {
vh.title.text = state.doubanModel.title vh.title.text = state.doubanModel.title
vh.gallery.children.length = 0 vh.gallery.children.length = 0
const vm = this
state.doubanModel.subjects.forEach((e, idx) => { state.doubanModel.subjects.forEach((e, idx) => {
vh.gallery.addChild(stack( vh.gallery.addChild(stack(
[ [
image({ image({
layoutConfig: layoutConfig().just().configAlignment(Gravity.Center), layoutConfig: layoutConfig().just().configAlignment(Gravity.Center),
width: 270 / 2, width: frameWidth / 1.5,
height: 400 / 2, height: frameHeight / 1.5,
imageUrl: e.images.large, imageUrl: e.images.large,
onClick: function () { onClick: function () {
const v = (this as Image).superview const v = (this as Image).superview
if (v == undefined) { if (v == undefined) {
return return
} }
v.getLocationOnScreen(context).then(ret => { vm.onItemClicked(idx)
const centerX = ret.x + v.width / 2;
vh.scrolled.scrollBy(context, { x: centerX - Environment.screenWidth / 2, y: 0 }, true)
})
}, },
}).also(it => { }).also(it => {
this.images.set(idx, it) this.images.set(idx, it)
if (state.selectedIdx == idx) {
it.scaleX = it.scaleY = 1.5
}
}) })
], ],
{ {
layoutConfig: layoutConfig().just(), layoutConfig: layoutConfig().just(),
width: 270 / 2 * 1.5, width: frameWidth,
height: 400 / 2 * 1.5, height: frameHeight,
})) }))
}) })
takeNonNull(state.doubanModel.subjects[state.selectedIdx])(it => { takeNonNull(state.doubanModel.subjects[state.selectedIdx])(it => {
@ -192,6 +252,8 @@ class MovieVM extends ViewModel<MovieModel, MovieVH>{
vh.movieYear.text = it.year vh.movieYear.text = it.year
}) })
} }
vh.anchor.centerX = state.anchorPos
this.updateArrow()
} }
} }
@ -205,7 +267,7 @@ class SliderPanel extends VMPanel<MovieModel, MovieVH>{
} }
getState() { getState() {
return { selectedIdx: 0, doubanModel: MovieData } return { selectedIdx: 0, anchorPos: Environment.screenWidth / 2, doubanModel: MovieData }
} }
} }