JXPagingView

repository·master·Indexed 25 days ago

https://github.com/pujiaxin33/jxpagingview

An iOS library supporting Objective-C and Swift for creating complex paging interfaces similar to Weibo or QQ contact pages. It features nested scrolling (vertical and horizontal), floating headers, pull-to-refresh, and lazy loading of list items.

Tokens
9.3K
Snippets
20
Records
47
Agent score
85%

What's inside jxpagingview

  1. Overview of JXCategoryView

    master

    JXCategoryView is a powerful and highly customizable category view component for iOS (Objective-C). It is designed to handle segmented controls, segment views, paging views, and page controls, similar to those found in mainstream apps like Tencent News, Toutiao, QQ Music, and Weibo.

    Key advantages include:

    • Customizable Indicators: Uses protocols to encapsulate indicator logic, allowing for complete customization of indicator effects.
    • Rich Effects: Provides a wide range of built-in, highly customizable visual effects.
    • Subclass-based Cell Management: Uses subclassing to manage cell styles, making logic clearer and extensions easier.
    • Encapsulated List Containers: Highly encapsulated list containers that support the full lifecycle of list views.
  2. Handle full-screen pop gestures in JXPagerView

    master

    To support full-screen pop gestures (like FDFullscreenPopGesture) within a JXPagerView, you must provide a custom scroll view class that implements the necessary gesture recognition logic.

    1. Implement the scrollViewClassInlistContainerViewInPagerView: delegate method in your JXPagerViewDelegate to return your custom scroll view class.
    2. In your custom scroll view class, implement the UIGestureRecognizerDelegate method gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: to allow simultaneous recognition when the scroll view is at its leftmost position (contentOffset.x <= 0) and the other gesture is a full-screen pop gesture.
    // 1. In your JXPagerViewDelegate implementation
    - (Class)scrollViewClassInlistContainerViewInPagerView:(JXPagerView *)pagerView {
        return [FullScreenGestureScrollView class];
    }
    
    // 2. In your custom FullScreenGestureScrollView class
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
        if (collectionView.contentOffset.x <= 0) {
            if ([otherGestureRecognizer.delegate isKindOfClass:NSClassFromString("_FDFullscreenPopGestureRecognizerDelegate")]) {
                return YES;
            }
        }
        return NO;
    }
  3. Use JXPagerSmoothView for smooth header scrolling

    master

    Standard JXPagerView (and JXPagingView in Swift) may stop abruptly when a user scrolls upward forcefully from the top header. To achieve a smooth transition similar to apps like Taobao or Zhuanzhuan—where the list continues to scroll smoothly after the header has been scrolled past—use JXPagerSmoothView (or JXPagingSmoothView in Swift).

    Note that JXPagerSmoothView uses a different implementation principle than JXPagerView, but the user experience remains consistent.

  4. Install JXCategoryView

    master

    You can install JXCategoryView either manually or via CocoaPods.

    Manual Installation

    1. Clone the repository.
    2. Drag the Sources folder into your Xcode project.
    3. Import the header: #import "JXCategoryView.h".

    CocoaPods Installation

    Add the following to your Podfile:

    target '<Your Target Name>' do
        pod 'JXCategoryView'
    end

    Then run pod repo update followed by pod install.

  5. Handle swipe-to-back gesture conflicts with JXPagingView

    master

    When using JXPagingView inside a UINavigationController, the interactive pop gesture (swipe-to-back) may conflict with the paging view's internal scroll gestures. To resolve this, you must set the UIGestureRecognizerDelegate of the interactivePopGestureRecognizer to your ViewController and implement the gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) method to allow simultaneous recognition when the JXPagingView scroll view is at its leftmost position (offset x <= 0).

    // 1. Set the delegate for the navigation controller's interactive pop gesture
    self.navigationController?.interactivePopGestureRecognizer?.delegate = self
    
    // 2. Implement the delegate method in your ViewController
    // MARK: - UIGestureRecognizerDelegate
    extension xxVC: UIGestureRecognizerDelegate {
        func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
            // Check if the other gesture belongs to a JXPagingView's UIScrollView
            if String(describing: otherGestureRecognizer.view.self).contains("JXPagingView"), 
               let scrollView = otherGestureRecognizer.view as? UIScrollView {
                // Allow simultaneous recognition only when the paging view is at the first page (offset x <= 0)
                if scrollView.contentOffset.x <= 0 {
                    return true
                }
            }
            return false
        }
    }
  6. Use JXSegmentedListContainerView for list management

    master

    For managing list views (like UIViewController or UIView) alongside the segmented view, JXSegmentedListContainerView is the highly recommended wrapper. It provides lazy loading for better performance and centralized code management.

    To integrate it, you must associate the contentScrollView of the JXSegmentedView with the scrollView of the JXSegmentedListContainerView, and manually pass click and scroll events from the JXSegmentedViewDelegate to the container.

    // 1. Initialize Container
    self.listContainerView = JXSegmentedListContainerView(dataSource: self)
    self.view.addSubview(self.listContainerView)
    // Associate the contentScrollView
    self.segmentedView.contentScrollView = self.listContainerView.scrollView
    
    // 2. Implement JXSegmentedListContainerViewDataSource
    func numberOfLists(in listContainerView: JXSegmentedListContainerView) -> Int {
        return self.segmentedDataSource.titles.count
    }
    
    func listContainerView(_ listContainerView: JXSegmentedListContainerView, initListAt index: Int) -> JXSegmentedListContainerViewListDelegate {
        return ListBaseViewController()
    }
    
    // 3. Implement JXSegmentedListContainerViewListDelegate (in your ViewController/View)
    func listView() -> UIView {
        return view // or viewController.view
    }
    
    // 4. Pass events from JXSegmentedViewDelegate to listContainerView (CRITICAL)
    func segmentedView(_ segmentedView: JXSegmentedView, didClickSelectedItemAt index: Int) {
        listContainerView.didClickSelectedItem(at: index)
    }
    
    func segmentedView(_ segmentedView: JXSegmentedView, scrollingFrom leftIndex: Int, to rightIndex: Int, percent: CGFloat) {
        listContainerView.segmentedViewScrolling(from: leftIndex, to: rightIndex, percent: percent, selectedIndex: segmentedView.selectedIndex)
    }
  7. Vertical Scrolling Interaction between Main and Sub-lists

    master

    JXPagingView enables synchronized vertical scrolling between the main list and sub-lists by allowing UIPanGestureRecognizer instances from both the main and sub-lists to respond simultaneously.

    To achieve the effect where the category selector (header) sticks to the top as sub-lists scroll, the following logic is applied to scroll delegates:

    Main List (scrollViewDidScroll) logic:

    • Once the main table view's header has scrolled out of view and a specific sub-list begins scrolling, the mainTableView.contentOffset is fixed to prevent further movement of the main list.
    • When the main table view's header is visible, the sub-list's contentOffset is reset.

    Sub-list (scrollViewDidScroll) logic:

    • While the main table view's header is still visible, the sub-list's scroll offset is forced to 0.
    • Once the main table view's header has just disappeared, the main table view's position is fixed, the sub-list's scroll bar is displayed, and the sub-list is allowed to scroll freely.