This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
Doric/doric-demo/src/ScrolledSliderDemo.ts

210 lines
6.6 KiB
TypeScript
Raw Normal View History

2020-03-03 13:54:36 +08:00
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";
2020-03-02 14:33:08 +08:00
import { colors } from "./utils";
interface DoubanModel {
count: number
start: number
total: number
subjects: Array<{
rating: {
max: number,
average: number,
details: {
"1": number,
"2": number,
"3": number,
"4": number,
"5": number,
},
stars: number
min: number,
}
genres: string[],
title: string
casts: Array<{
avatars: {
small: string,
large: string,
medium: string,
},
name_en: string
name: string
alt: string
id: string
}>
durations: string[]
collect_count: number
mainland_pubdate: string
has_video: boolean
original_title: string
subtype: string
directors: Array<{
avatars: {
small: string,
large: string,
medium: string,
},
name_en: string
name: string
alt: string
id: string
}>,
pubdates: string[],
year: string,
images: {
small: string,
large: string,
medium: string,
}
alt: string
id: string
}>
title: string
}
interface MovieModel {
doubanModel?: DoubanModel
2020-03-03 13:10:35 +08:00
selectedIdx: number
2020-03-02 14:33:08 +08:00
}
class MovieVH extends ViewHolder {
title!: Text
gallery!: HLayout
2020-03-03 13:10:35 +08:00
scrolled!: Scroller
movieTitle!: Text
movieYear!: Text
2020-03-02 14:33:08 +08:00
build(root: Group) {
vlayout(
[
this.title = text({
layoutConfig: {
widthSpec: LayoutSpec.MOST,
heightSpec: LayoutSpec.JUST,
},
textSize: 30,
textColor: Color.WHITE,
backgroundColor: colors[1],
textAlignment: gravity().center(),
height: 50,
}),
2020-03-03 13:10:35 +08:00
this.scrolled = scroller(
2020-03-02 14:33:08 +08:00
this.gallery = hlayout(
[],
{
2020-03-03 11:59:27 +08:00
layoutConfig: layoutConfig().fit(),
2020-03-03 14:22:33 +08:00
space: 0,
2020-03-03 11:59:27 +08:00
padding: {
top: 20,
left: 20,
right: 20,
bottom: 20,
2020-03-03 13:10:35 +08:00
},
gravity: Gravity.Center,
2020-03-02 14:33:08 +08:00
}),
{
2020-03-03 11:59:27 +08:00
layoutConfig: layoutConfig().most().configHeight(LayoutSpec.FIT),
2020-03-02 14:33:08 +08:00
backgroundColor: Color.parse("#eeeeee"),
2020-03-03 13:10:35 +08:00
}),
vlayout(
[
2020-03-03 13:54:36 +08:00
text({
text: "↑",
}),
2020-03-03 13:10:35 +08:00
this.movieTitle = text({
textSize: 20,
}),
this.movieYear = text({
textSize: 20,
}),
],
{
layoutConfig: layoutConfig().fit().configWidth(LayoutSpec.MOST),
gravity: Gravity.Center
}),
2020-03-02 14:33:08 +08:00
],
{
layoutConfig: layoutConfig().most(),
2020-03-03 13:54:36 +08:00
space: 0,
2020-03-02 14:33:08 +08:00
}).in(root)
}
}
class MovieVM extends ViewModel<MovieModel, MovieVH>{
2020-03-03 16:36:20 +08:00
images: Map<number, Image> = new Map
2020-03-02 14:33:08 +08:00
onAttached(state: MovieModel, vh: MovieVH) {
2020-03-02 14:33:08 +08:00
network(context).get("https://douban.uieee.com/v2/movie/top250").then(ret => {
this.updateState(state => state.doubanModel = JSON.parse(ret.data) as DoubanModel)
})
vh.scrolled.onScroll = (offset) => {
2020-03-03 16:36:20 +08:00
const frameWidth = 270 / 2 * 1.5
const centerX = offset.x + Environment.screenWidth / 2
2020-03-03 16:36:20 +08:00
const idx = Math.floor(centerX / frameWidth)
if (state.selectedIdx != idx) {
this.updateState(state => state.selectedIdx = idx)
}
2020-03-03 16:36:20 +08:00
const overOff = Math.abs(centerX - frameWidth * (idx + 0.5))
const scale = overOff / (frameWidth / 2)
takeNonNull(this.images.get(idx))(v => {
v.scaleX = v.scaleY = 1.5 - 0.5 * scale
})
}
2020-03-02 14:33:08 +08:00
}
2020-03-03 14:43:49 +08:00
2020-03-02 14:33:08 +08:00
onBind(state: MovieModel, vh: MovieVH) {
if (state.doubanModel) {
vh.title.text = state.doubanModel.title
vh.gallery.children.length = 0
2020-03-03 14:22:33 +08:00
state.doubanModel.subjects.forEach((e, idx) => {
2020-03-02 14:33:08 +08:00
vh.gallery.addChild(stack(
[
image({
2020-03-03 14:22:33 +08:00
layoutConfig: layoutConfig().just().configAlignment(Gravity.Center),
2020-03-03 13:54:36 +08:00
width: 270 / 2,
height: 400 / 2,
2020-03-03 13:10:35 +08:00
imageUrl: e.images.large,
2020-03-03 13:54:36 +08:00
onClick: function () {
2020-03-03 14:22:33 +08:00
const v = (this as Image).superview
if (v == undefined) {
return
}
2020-03-03 13:54:36 +08:00
v.getLocationOnScreen(context).then(ret => {
const centerX = ret.x + v.width / 2;
2020-03-03 14:43:49 +08:00
vh.scrolled.scrollBy(context, { x: centerX - Environment.screenWidth / 2, y: 0 }, true)
2020-03-03 13:54:36 +08:00
})
2020-03-03 13:10:35 +08:00
},
2020-03-03 16:36:20 +08:00
}).also(it => {
this.images.set(idx, it)
2020-03-02 14:33:08 +08:00
})
],
{
2020-03-03 14:22:33 +08:00
layoutConfig: layoutConfig().just(),
width: 270 / 2 * 1.5,
height: 400 / 2 * 1.5,
2020-03-02 14:33:08 +08:00
}))
})
2020-03-03 13:10:35 +08:00
takeNonNull(state.doubanModel.subjects[state.selectedIdx])(it => {
vh.movieTitle.text = it.title
vh.movieYear.text = it.year
})
2020-03-02 14:33:08 +08:00
}
}
}
@Entry
class SliderPanel extends VMPanel<MovieModel, MovieVH>{
getViewModelClass() {
return MovieVM
}
getViewHolderClass() {
return MovieVH
}
getState() {
2020-03-03 13:10:35 +08:00
return { selectedIdx: 0 }
2020-03-02 14:33:08 +08:00
}
}