В последнее время направление развития компании смещено в сторону мобильного терминала. Вот меня и перевели делать RN(react-native),и опыт не плохой.Текущая потребность в эффекте засасывания потолка в середине главной страницы.Хотя давно не писал стиль, этот общий стиль должен быть таким-легким.Я хочу перевернуть машину, но я не могу найти несколько решений в Интернете.Наконец, я иду на github, чтобы скопировать упакованную библиотеку, чтобы реализовать это, и теперь записываю процесс опрокидывания.
эффект спроса
процесс пролонгации
первый вариант失败
Идея в начале такова, публичная идея, нам нужно следить за состоянием прокрутки страницы, когда страница прокручивается до позиции, где должен быть размещен верхний элемент, мы устанавливаем фиксированное позиционирование, но, к сожалению, RN предоставляет только два метода макета для атрибута position: абсолютный и относительный, ни фиксированный, ни экспериментальный API: sticky. стыдно 😅
Второй вариант失败
Но не паникуйте, смотрите в интернете есть второе решение, займите второе и третье места на карте какScrollView
,ПотомScrollView
Сдвинув дистанцию мониторинга, установите marginTop первого блока в отрицательное значение, но первую часть нельзя сдвинуть, что не соответствует требованиям, проход
Третий вариант完全失败
Найдите в интернете третье решение, то есть одну, две или три части какScrollView
,
первая частьposition
установить какabsolute
, остальные не заданы, по умолчанию относительные
Вторая часть (потолочная часть) marginTop устанавливается (setState) в состояние высоты первой части,
добавить свайпсобытие onScroll=> Расстояние скольжения y равно состоянию marginTop второй части, но когда скольжение превышает высоту первой части, вторая часть (часть потолка)position
установить какabsolute
, и установил его marginTop в 0, выглядит хорошо, но я потерял дар речи, как только запустил его с симулятором ios 😅, эффект очень странный, когда палец скользит, он не засасывает верх и скрывает большую часть его, а когда он свободен, он внезапно засасывает. . .
Смотри ниже
В системе ios при прокрутке пальцем по экрану всегда срабатывает onScroll, если в нем есть метод setState, то он продолжит выполнение и вычислениеstate
, но изменение состояния реакции происходит асинхронно, пока палец не покидает экран, измененное состояние не вступит в силу (триггер отрисовки интерфейса)
План реализации
Я наконец-то понял, что из-за механизма ios механизм state of react не может удовлетворить потребности, и должен быть способ использовать нативный рендеринг в RN, поэтому после того, как github нашел готовую реализацию кода, он был исследован в Любой, у кого есть богатый опыт в RN, также может просто посмотреть на код ниже👇
Аниматор для РН
Библиотека анимации RN's Animator предназначена для решения проблемы с анимацией.Из-за процесса соединения js анимация обычно не может отображаться хорошо.Лучше всего поставить анимациюданныеа такжеИзменить методОн одновременно отправляется нативу и обрабатывается нативом Это основная функция библиотеки Animator.
Я помню, что на анимацию RN все время жаловались, но теперь эффект довольно хороший, может быть, это как-то связано с улучшением аппаратного обеспечения мобильных телефонов в последние годы.
Простое использование
Поскольку Animator инкапсулирует эти четыре компонента,
Я хочу сделать некоторую обработку анимации в этих компонентах, данные также являются состоянием реакции, но присваивание должно быть дано Animated.Value следующим образом👇
this.state = {
scrollY: new Animated.Value(0)
}
Хотя здесь по-прежнему используется нативное состояние, после обработки Animated механизм рендеринга совершенно другой.
простой принцип
Компонент, обернутый Animator, будет проходить по входящим свойствам и своему собственному состоянию, выяснять, существует ли экземпляр Animated.Value, и связывать его с соответствующей нативной операцией. При изменении пропсов и собственного состояния значения Animated.Value конвертируются в обычные значения одно за другим, а затем передаются нативу для рендеринга, но стоит отметить, что рендер реакта не сработает здесь, и не будет domdiff.Специальная обработка, похожая на то, что каждый shouldUpdateComponent возвращает false при изменении Animated.Value (производительность миллисекундного рендеринга не может этого вынести), функция shouldUpdateComponent оценивает Animated.Value, а затем отправляет данные изменения в нативном компоненте
Для полного ознакомления, пожалуйста, переместитеЗнакомство с библиотекой Animator на официальном китайском сайте
Реализовать идеи
Теперь, когда используется компонент Animator, проблема рендеринга решена.Следующая идея состоит в том, чтобы динамически установить свойство translateY компонента потолка.style:{ transform: [{ translateY:translateY }] }
- При свайпе вниз, независимо от этого
- Проведите вверх, но оставьте голову в покое, если она не полностью скрыта
- Сдвиньте вверх, голова полностью исчезла, затем сдвиньте еще немного вверх, тогда его перевод Y должен быть = общее расстояние движения вверх - высота головы, поэтому, чем больше вы скользите вверх, сильно нажимайте на потолочную сборку вниз, чтобы потолок компонент прочно прикреплен к верхней части
Используйте следующееинтерполяцияреализовать
const translateY = ScrollY.interpolate({
inputRange: [-1, 0, headerHeight, headerHeight + 1],
outputRange: [0, 0, 0, 1],
});
интерполяцияinterpolate
Немного сложно понять, нужна небольшая основа, эта статья слишком длинная, чтобы ее здесь подробно описывать.Введение на официальном сайте,
Если не знаете, можете поискать в сети
Реализовать исходный код
Основной код функции потолка во второй части реализованного рисунка преобразован в режим функциональных хуков ниже.
import * as React from 'react';
import { StyleSheet, Animated } from "react-native";
/**
* 滑动吸顶效果组件
* @export
* @class StickyHeader
*/
export default class StickyHeader extends React.Component{
static defaultProps = {
stickyHeaderY: -1,
stickyScrollY: new Animated.Value(0)
}
constructor(props) {
super(props);
this.state = {
stickyLayoutY: 0,
};
}
// 兼容代码,防止没有传头部高度
_onLayout = (event) => {
this.setState({
stickyLayoutY: event.nativeEvent.layout.y,
});
}
render() {
const { stickyHeaderY, stickyScrollY, children, style } = this.props
const { stickyLayoutY } = this.state
let y = stickyHeaderY != -1 ? stickyHeaderY : stickyLayoutY;
const translateY = stickyScrollY.interpolate({
inputRange: [-1, 0, y, y + 1],
outputRange: [0, 0, 0, 1],
});
return (
<Animated.View
onLayout= { this._onLayout }
style = {
[
style,
styles.container,
{ transform: [{ translateY }] }
]}
>
{ children }
</Animated.View>
)
}
}
const styles = StyleSheet.create({
container: {
zIndex: 100
},
});
крючки использовать
export default function StickyHeader(props: IStickyHeaderProps){
const [stickyLayoutY, setStickyLayoutY] = useState(0);
// 函数可以提出去
const _onLayout = (event) => {
setStickyLayoutY(
event.nativeEvent.layout.y,
);
}
const { stickyHeaderY = -1, stickyScrollY = new Animated.Value(0), children, style } = props;
const y = stickyHeaderY != -1 ? stickyHeaderY : stickyLayoutY;
const translateY = stickyScrollY.interpolate({
inputRange: [-1, 0, y, y + 1],
outputRange: [0, 0, 0, 1],
});
return (
<Animated.View
onLayout= { _onLayout }
style = {
[
style,
{ zIndex: 100,transform: [{ translateY }] }
]}
>
{ children }
</Animated.View>
)
}
на страницеПрактическое использованиеследующим образом
// 在页面constructor里声明state
this.state = {
scrollY: new Animated.Value(0),
headHeight:-1
};
<Animated.ScrollView
style={{ flex: 1 }}
onScroll={
Animated.event(
[{
nativeEvent: { contentOffset: { y: this.state.scrollY } } // 记录滑动距离
}],
{ useNativeDriver: true }) // 使用原生动画驱动
}
scrollEventThrottle={1}
>
<View onLayout={(e) => {
let { height } = e.nativeEvent.layout;
this.setState({ headHeight: height }); // 给头部高度赋值
}}>
// 里面放入第一部分组件
</View>
<StickyHeader
stickyHeaderY={this.state.headHeight} // 把头部高度传入
stickyScrollY={this.state.scrollY} // 把滑动距离传入
>
// 里面放入第二部分组件
</StickyHeader>
// 这是第三部分的列表组件
<FlatList
data={this.state.dataSource}
renderItem={({item}) => this._createListItem(item)}
/>
</Animated.ScrollView>
окончание
Конкретный код реализован таким образом. Это относительно идеальное решение, особенно заботясь о производительности. Вы можете реализовать более сложные требования на основе этого пакета. Принцип, вероятно, этот принцип. В области анимации переднего плана вы на самом деле только начинают. , если есть проблема, пожалуйста, укажите на нее напрямую.
Кроме того, это тот, который я искалкомпонентыгитхабАдрес кода: https://github.com/jiasongs/react-native-stickyheader, исходный адрес прилагается, рекомендуется, если проект использует звезду