mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-14 18:12:09 +08:00
feat(ios): searchAutoHide wip
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||||
<Page.actionBar>
|
<Page.actionBar>
|
||||||
<ActionBar title="Dev Toolbox" icon="" class="action-bar" iosLargeTitle="true" iosShadow="false">
|
<ActionBar title="Dev Toolbox" icon="" class="action-bar">
|
||||||
</ActionBar>
|
</ActionBar>
|
||||||
</Page.actionBar>
|
</Page.actionBar>
|
||||||
<StackLayout>
|
<StackLayout>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<GridLayout backgroundColor="#efefef">
|
<GridLayout backgroundColor="#efefef">
|
||||||
<ListView class="list-group" items="{{ countries }}" itemTap="{{ componentsItemTap }} " separatorColor="#00000000" itemTemplateSelector="{{ selectItemTemplate }}" stickyHeader="true" sectioned="true" stickyHeaderTopPadding="false" stickyHeaderTemplate="<GridLayout><Label text='{{ title }}' fontSize='18' fontWeight='bold' color='#009bff' padding='8 0 8 12' borderBottomWidth='1' borderBottomColor='#ccc' borderTopWidth='1' borderTopColor='#ccc' backgroundColor='#fff' /></GridLayout>" stickyHeaderHeight="45" itemLoading="{{ itemLoading }}"
|
<ListView class="list-group" items="{{ countries }}" itemTap="{{ componentsItemTap }} " separatorColor="#00000000" itemTemplateSelector="{{ selectItemTemplate }}" stickyHeader="true" sectioned="true" stickyHeaderTopPadding="false" stickyHeaderTemplate="<GridLayout><Label text='{{ title }}' fontSize='18' fontWeight='bold' color='#009bff' padding='8 0 8 12' borderBottomWidth='1' borderBottomColor='#ccc' borderTopWidth='1' borderTopColor='#ccc' backgroundColor='#fff' /></GridLayout>" stickyHeaderHeight="45" itemLoading="{{ itemLoading }}"
|
||||||
showSearch="true"
|
showSearch="true"
|
||||||
|
searchAutoHide="true"
|
||||||
searchChange="{{ onSearchTextChange }}">
|
searchChange="{{ onSearchTextChange }}">
|
||||||
<ListView.itemTemplates>
|
<ListView.itemTemplates>
|
||||||
<template key="main">
|
<template key="main">
|
||||||
|
15
packages/core/ui/list-view/index.d.ts
vendored
15
packages/core/ui/list-view/index.d.ts
vendored
@ -146,7 +146,7 @@ export class ListView extends View {
|
|||||||
sectioned: boolean;
|
sectioned: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or sets a value indicating whether the ListView should show a search bar.
|
* Gets or sets whether search functionality is enabled.
|
||||||
* When enabled on iOS, uses native UISearchController for optimal performance.
|
* When enabled on iOS, uses native UISearchController for optimal performance.
|
||||||
*
|
*
|
||||||
* @nsProperty
|
* @nsProperty
|
||||||
@ -154,6 +154,14 @@ export class ListView extends View {
|
|||||||
showSearch: boolean;
|
showSearch: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Gets or sets whether the search bar should auto-hide when scrolling (iOS only).
|
||||||
|
* When true, the search bar will automatically hide when the user scrolls down
|
||||||
|
* and reappear when scrolling up, using iOS native behavior.
|
||||||
|
* Only applies when showSearch is true and running on iOS with navigation controller.
|
||||||
|
*
|
||||||
|
* @nsProperty
|
||||||
|
*/
|
||||||
|
searchAutoHide: boolean; /**
|
||||||
* Forces the ListView to reload all its items.
|
* Forces the ListView to reload all its items.
|
||||||
*/
|
*/
|
||||||
refresh();
|
refresh();
|
||||||
@ -339,3 +347,8 @@ export const sectionedProperty: Property<ListView, boolean>;
|
|||||||
* Represents the observable property backing the showSearch property of each ListView instance.
|
* Represents the observable property backing the showSearch property of each ListView instance.
|
||||||
*/
|
*/
|
||||||
export const showSearchProperty: Property<ListView, boolean>;
|
export const showSearchProperty: Property<ListView, boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the observable property backing the searchAutoHide property of each ListView instance.
|
||||||
|
*/
|
||||||
|
export const searchAutoHideProperty: Property<ListView, boolean>;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ItemEventData, SearchEventData, ItemsSource } from '.';
|
import { ItemEventData, SearchEventData, ItemsSource } from '.';
|
||||||
import { ListViewBase, separatorColorProperty, itemTemplatesProperty, iosEstimatedRowHeightProperty, stickyHeaderProperty, stickyHeaderTemplateProperty, stickyHeaderHeightProperty, sectionedProperty, showSearchProperty } from './list-view-common';
|
import { ListViewBase, separatorColorProperty, itemTemplatesProperty, iosEstimatedRowHeightProperty, stickyHeaderProperty, stickyHeaderTemplateProperty, stickyHeaderHeightProperty, sectionedProperty, showSearchProperty, searchAutoHideProperty } from './list-view-common';
|
||||||
import { CoreTypes } from '../../core-types';
|
import { CoreTypes } from '../../core-types';
|
||||||
import { View, KeyedTemplate, Template } from '../core/view';
|
import { View, KeyedTemplate, Template } from '../core/view';
|
||||||
import { Length } from '../styling/length-shared';
|
import { Length } from '../styling/length-shared';
|
||||||
@ -499,24 +499,41 @@ export class ListView extends ListViewBase {
|
|||||||
// 2. Tell it who will update results
|
// 2. Tell it who will update results
|
||||||
this._searchController.searchResultsUpdater = this._searchDelegate;
|
this._searchController.searchResultsUpdater = this._searchDelegate;
|
||||||
|
|
||||||
// 3. Don't dim or obscure your table by default
|
// 3. Critical: Don't dim or obscure the table, and prevent extra content
|
||||||
this._searchController.obscuresBackgroundDuringPresentation = false;
|
this._searchController.obscuresBackgroundDuringPresentation = false;
|
||||||
|
this._searchController.dimsBackgroundDuringPresentation = false;
|
||||||
|
this._searchController.hidesNavigationBarDuringPresentation = false;
|
||||||
|
|
||||||
// 4. Placeholder text
|
// 4. Placeholder text and styling
|
||||||
this._searchController.searchBar.placeholder = 'Search';
|
this._searchController.searchBar.placeholder = 'Search';
|
||||||
this._searchController.searchBar.searchBarStyle = UISearchBarStyle.Minimal;
|
this._searchController.searchBar.searchBarStyle = UISearchBarStyle.Minimal;
|
||||||
|
|
||||||
// 5. CRITICAL: Make sure the search bar doesn't remain on screen if the user navigates
|
// 5. CRITICAL: Proper presentation context setup
|
||||||
const viewController = this._getViewController();
|
const viewController = this._getViewController();
|
||||||
if (viewController) {
|
if (viewController) {
|
||||||
viewController.definesPresentationContext = true;
|
viewController.definesPresentationContext = true;
|
||||||
|
viewController.providesPresentationContextTransitionStyle = true;
|
||||||
|
|
||||||
// 6a. If we're in a UINavigationController...
|
// 6a. If we're in a UINavigationController (iOS 11+)...
|
||||||
if (SDK_VERSION >= 11.0 && viewController.navigationItem) {
|
if (SDK_VERSION >= 11.0 && viewController.navigationItem) {
|
||||||
viewController.navigationItem.searchController = this._searchController;
|
viewController.navigationItem.searchController = this._searchController;
|
||||||
viewController.navigationItem.hidesSearchBarWhenScrolling = false;
|
|
||||||
|
// Set auto-hide behavior based on searchAutoHide property
|
||||||
|
viewController.navigationItem.hidesSearchBarWhenScrolling = this.searchAutoHide;
|
||||||
|
|
||||||
|
// Optional: Enable large titles for better auto-hide effect when searchAutoHide is true
|
||||||
|
// if (this.searchAutoHide && viewController.navigationController && viewController.navigationController.navigationBar) {
|
||||||
|
// // Only set large titles if not already configured
|
||||||
|
// if (!viewController.navigationController.navigationBar.prefersLargeTitles) {
|
||||||
|
// viewController.navigationController.navigationBar.prefersLargeTitles = true;
|
||||||
|
// }
|
||||||
|
// // Set large title display mode for this specific view controller
|
||||||
|
// if (viewController.navigationItem.largeTitleDisplayMode === UINavigationItemLargeTitleDisplayMode.Automatic) {
|
||||||
|
// viewController.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayMode.Always;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
} else {
|
} else {
|
||||||
// 6b. Or just put it at the top of our table
|
// 6b. Fallback: put it at the top of our table
|
||||||
this.nativeViewProtected.tableHeaderView = this._searchController.searchBar;
|
this.nativeViewProtected.tableHeaderView = this._searchController.searchBar;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -524,11 +541,20 @@ export class ListView extends ListViewBase {
|
|||||||
this.nativeViewProtected.tableHeaderView = this._searchController.searchBar;
|
this.nativeViewProtected.tableHeaderView = this._searchController.searchBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure search bar is properly sized
|
// 7. Ensure search bar is properly sized and prevent content inset issues
|
||||||
this._searchController.searchBar.sizeToFit();
|
this._searchController.searchBar.sizeToFit();
|
||||||
|
|
||||||
|
// 8. Disable automatic content inset adjustment that can cause spacing issues
|
||||||
|
if (this.nativeViewProtected.respondsToSelector('setContentInsetAdjustmentBehavior:')) {
|
||||||
|
// iOS 11+ - prevent automatic content inset adjustments
|
||||||
|
this.nativeViewProtected.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Never;
|
||||||
|
} else {
|
||||||
|
// iOS 10 and below - disable automatic content inset
|
||||||
|
this.nativeViewProtected.automaticallyAdjustsScrollIndicatorInsets = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (Trace.isEnabled()) {
|
if (Trace.isEnabled()) {
|
||||||
Trace.write(`ListView: UISearchController setup complete`, Trace.categories.Debug);
|
Trace.write(`ListView: UISearchController setup complete with searchAutoHide: ${this.searchAutoHide}`, Trace.categories.Debug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,6 +571,15 @@ export class ListView extends ListViewBase {
|
|||||||
this.nativeViewProtected.tableHeaderView = null;
|
this.nativeViewProtected.tableHeaderView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset content inset adjustment behavior
|
||||||
|
if (this.nativeViewProtected.respondsToSelector('setContentInsetAdjustmentBehavior:')) {
|
||||||
|
// iOS 11+ - restore automatic content inset adjustments
|
||||||
|
this.nativeViewProtected.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Automatic;
|
||||||
|
} else {
|
||||||
|
// iOS 10 and below - restore automatic content inset
|
||||||
|
this.nativeViewProtected.automaticallyAdjustsScrollIndicatorInsets = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup references
|
// Cleanup references
|
||||||
this._searchController.searchResultsUpdater = null;
|
this._searchController.searchResultsUpdater = null;
|
||||||
this._searchController = null;
|
this._searchController = null;
|
||||||
@ -1087,4 +1122,32 @@ export class ListView extends ListViewBase {
|
|||||||
this._cleanupSearchController();
|
this._cleanupSearchController();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[searchAutoHideProperty.getDefault](): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
[searchAutoHideProperty.setNative](value: boolean) {
|
||||||
|
if (Trace.isEnabled()) {
|
||||||
|
Trace.write(`ListView: searchAutoHide set to ${value}`, Trace.categories.Debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If search is already enabled, update the existing search controller
|
||||||
|
if (this.showSearch && this._searchController) {
|
||||||
|
const viewController = this._getViewController();
|
||||||
|
if (viewController && viewController.navigationItem && SDK_VERSION >= 11.0) {
|
||||||
|
viewController.navigationItem.hidesSearchBarWhenScrolling = value;
|
||||||
|
|
||||||
|
// Enable large titles for better auto-hide effect when searchAutoHide is true
|
||||||
|
// if (value && viewController.navigationController && viewController.navigationController.navigationBar) {
|
||||||
|
// if (!viewController.navigationController.navigationBar.prefersLargeTitles) {
|
||||||
|
// viewController.navigationController.navigationBar.prefersLargeTitles = true;
|
||||||
|
// }
|
||||||
|
// if (viewController.navigationItem.largeTitleDisplayMode === UINavigationItemLargeTitleDisplayMode.Automatic) {
|
||||||
|
// viewController.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayMode.Always;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If search is not enabled yet, the property will be used when _setupSearchController is called
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ export abstract class ListViewBase extends ContainerView implements ListViewDefi
|
|||||||
public stickyHeaderTopPadding: boolean;
|
public stickyHeaderTopPadding: boolean;
|
||||||
public sectioned: boolean;
|
public sectioned: boolean;
|
||||||
public showSearch: boolean;
|
public showSearch: boolean;
|
||||||
|
public searchAutoHide: boolean;
|
||||||
|
|
||||||
get separatorColor(): Color {
|
get separatorColor(): Color {
|
||||||
return this.style.separatorColor;
|
return this.style.separatorColor;
|
||||||
@ -349,3 +350,10 @@ export const showSearchProperty = new Property<ListViewBase, boolean>({
|
|||||||
valueConverter: booleanConverter,
|
valueConverter: booleanConverter,
|
||||||
});
|
});
|
||||||
showSearchProperty.register(ListViewBase);
|
showSearchProperty.register(ListViewBase);
|
||||||
|
|
||||||
|
export const searchAutoHideProperty = new Property<ListViewBase, boolean>({
|
||||||
|
name: 'searchAutoHide',
|
||||||
|
defaultValue: false,
|
||||||
|
valueConverter: booleanConverter,
|
||||||
|
});
|
||||||
|
searchAutoHideProperty.register(ListViewBase);
|
||||||
|
Reference in New Issue
Block a user