Задержка при переключении Scrollto StickehheaderindicesAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Задержка при переключении Scrollto Stickehheaderindices

Сообщение Anonymous »

[Введите описание изображения здесь] [1] У меня есть Scrollview с kickyheaderindics = {[1]}. Внутри липкого заголовка я составляю горизонтальный список «чипсов категории». Когда нажимается чип, я вызываю Scrollto ({y, анимированное: true}), чтобы перейти к этому разделу категории (позиции собираются через раздел). На Android, когда липкий заголовок активен, нажатие чипа часто заставляет программного прокрутки Twitch/Jump, а затем отменяется, поэтому содержимое отступает, и целевой раздел не достигнут. Это, скорее всего, произойдет, если я быстро нажму чипсы. < /P>
import React, { useRef, useState, useCallback, useMemo } from 'react';
import { View, ScrollView, Text, TouchableOpacity, StyleSheet, Dimensions } from 'react-native';

const { height: screenHeight } = Dimensions.get('window');

const CATEGORIES = [
{ id: 1, title: 'Appetizers', color: '#FF6B6B' },
{ id: 2, title: 'Main Courses', color: '#4ECDC4' },
{ id: 3, title: 'Desserts', color: '#45B7D1' },
{ id: 4, title: 'Beverages', color: '#96CEB4' },
{ id: 5, title: 'Specials', color: '#FECA57' }
];

const ITEMS_PER_CATEGORY = 8;

export default function ScrollViewAnchorExample() {
const scrollViewRef = useRef(null);
const [selectedCategoryId, setSelectedCategoryId] = useState(1);
const [categoryPositions, setCategoryPositions] = useState(new Map());
const [showTitleInHeader, setShowTitleInHeader] = useState(false);
const [headerPosition, setHeaderPosition] = useState(0);
const [isScrolling, setIsScrolling] = useState(false); // Добавляем флаг скролла
const lastScrollY = useRef(0); // Для throttling

// Скролл к якорю категории с проверками
const scrollToCategory = useCallback((categoryId: number) => {
console.log('=== CATEGORY SELECT DEBUG ===');
console.log('Selected category:', categoryId);
console.log('Current selectedCategoryId:', selectedCategoryId);
console.log('Is scrolling:', isScrolling);
console.log('ScrollView ref exists:', !!scrollViewRef.current);
console.log('Category positions size:', categoryPositions.size);
console.log('Timestamp:', Date.now());

// Проверка на повторные вызовы во время скролла
if (isScrolling) {
console.log('⚠️ Scroll in progress, ignoring category select');
return;
}

const categoryPosition = categoryPositions.get(categoryId);
console.log('Category position for', categoryId, ':', categoryPosition);

if (categoryPosition !== undefined && scrollViewRef.current) {
const offsetY = Math.max(0, categoryPosition - 100);
console.log('Scrolling to offsetY:', offsetY);

// Устанавливаем флаг скролла
setIsScrolling(true);

scrollViewRef.current.scrollTo({
y: offsetY,
animated: true
});

// Обновляем выбранную категорию
setTimeout(() => {
console.log('Setting selected category to:', categoryId);
setSelectedCategoryId(categoryId);
}, 50);

// Сбрасываем флаг скролла через задержку
setTimeout(() => {
console.log('Resetting isScrolling flag');
setIsScrolling(false);
}, 600); // Увеличиваем время для анимации
} else {
console.log('❌ Cannot scroll - missing position or ref');
}

console.log('================================');
}, [categoryPositions, selectedCategoryId, isScrolling]);

// Обработчик layout категории для сохранения позиции якоря
const handleCategoryLayout = useCallback((categoryId: number) => {
return (event: any) => {
const { y } = event.nativeEvent.layout;
console.log(`📍 Category ${categoryId} layout at y:`, y);
setCategoryPositions(prev => new Map(prev.set(categoryId, y)));
};
}, []);

// Обработчик скролла с throttling
const handleScroll = useCallback((event: any) => {
const scrollY = event.nativeEvent.contentOffset.y;

// Throttling для уменьшения частоты обновлений
if (Math.abs(scrollY - lastScrollY.current) < 5) return;
lastScrollY.current = scrollY;

// Показываем заголовок в header при скролле
setShowTitleInHeader(scrollY > headerPosition + 50);

// Автоматическое определение активной категории только если не скроллим вручную
if (!isScrolling) {
let activeCategory = 1;
categoryPositions.forEach((position, categoryId) => {
if (scrollY >= position - 150) {
activeCategory = categoryId;
}
});

if (activeCategory !== selectedCategoryId) {
console.log('🔄 Auto-updating category from', selectedCategoryId, 'to', activeCategory);
setSelectedCategoryId(activeCategory);
}
}
}, [headerPosition, categoryPositions, selectedCategoryId, isScrolling]);

const handleHeaderLayout = useCallback((event: any) => {
const { y } = event.nativeEvent.layout;
setHeaderPosition(y);
console.log('📋 Header position set to:', y);
}, []);

// Обработчик завершения скролла
const handleMomentumScrollEnd = useCallback(() => {
console.log('🏁 Scroll momentum ended');
setIsScrolling(false);
}, []);

// Обработчик начала скролла пользователем
const handleScrollBeginDrag = useCallback(() => {
console.log('👆 User started dragging scroll');
setIsScrolling(true);
}, []);

// Мемоизированные элементы категорий для производительности
const categoryItems = useMemo(() => CATEGORIES, []);

return (

{/* Основной заголовок */}


{showTitleInHeader ? 'Menu Categories' : 'Restaurant Menu'}

{/* Добавляем индикатор состояния для отладки */}

Category: {selectedCategoryId} | Scrolling: {isScrolling ? 'YES' : 'NO'}




{/* Заголовочная секция */}

Welcome to Our Restaurant
Delicious food awaits you


{/* Sticky Header с категориями */}


{categoryItems.map((category) => (
{
console.log('🎯 TouchableOpacity pressed for category:', category.id);
scrollToCategory(category.id);
}}
// Дополнительные свойства для надежности
activeOpacity={0.7}
delayPressIn={0}
disabled={isScrolling} // Блокируем нажатия во время скролла
>

{category.title}


))}



{/* Контент с категориями */}

{categoryItems.map((category) => (


{category.title}


{/* Элементы в категории */}
{Array.from({ length: ITEMS_PER_CATEGORY }, (_, index) => (


{category.title} Item {index + 1}


Description of the delicious {category.title.toLowerCase()} item


${(Math.random() * 20 + 5).toFixed(2)}


))}

))}





);
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#000',
},
header: {
backgroundColor: '#000',
paddingHorizontal: 16,
paddingVertical: 12,
borderBottomWidth: 1,
borderBottomColor: '#333',
},
headerTitle: {
color: 'white',
fontSize: 18,
fontWeight: 'bold',
},
// Добавляем стиль для отладочного текста
debugText: {
color: '#666',
fontSize: 12,
marginTop: 4,
},
heroSection: {
backgroundColor: '#1a1a1a',
padding: 32,
alignItems: 'center',
minHeight: 200,
justifyContent: 'center',
},
heroTitle: {
color: 'white',
fontSize: 28,
fontWeight: 'bold',
marginBottom: 8,
textAlign: 'center',
},
heroSubtitle: {
color: '#ccc',
fontSize: 16,
textAlign: 'center',
},
stickyHeader: {
backgroundColor: '#000',
paddingVertical: 12,
borderBottomWidth: 1,
borderBottomColor: '#333',
},
categoriesContainer: {
paddingHorizontal: 16,
},
categoryChip: {
backgroundColor: '#333',
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 20,
marginRight: 12,
},
categoryChipActive: {
backgroundColor: '#007AFF',
},
categoryText: {
color: '#ccc',
fontWeight: '500',
fontSize: 14,
},
categoryTextActive: {
color: 'white',
fontWeight: 'bold',
},
contentContainer: {
backgroundColor: '#000',
minHeight: screenHeight,
},
categorySection: {
paddingHorizontal: 16,
paddingTop: 24,
},
categoryTitle: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 16,
paddingBottom: 8,
borderBottomWidth: 2,
borderBottomColor: 'currentColor',
},
menuItem: {
backgroundColor: '#1a1a1a',
padding: 16,
marginBottom: 12,
borderRadius: 8,
borderLeftWidth: 4,
},
itemTitle: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
marginBottom: 4,
},
itemDescription: {
color: '#ccc',
fontSize: 14,
marginBottom: 8,
lineHeight: 20,
},
itemPrice: {
color: '#4CAF50',
fontSize: 16,
fontWeight: 'bold',
},
bottomSpacing: {
height: 100,
},
});


Подробнее здесь: https://stackoverflow.com/questions/797 ... derindices
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»