简体   繁体   中英

SwiftUI zIndex inside List

The zIndex property on a view inside a ForEach inside List does not seem to work whereas if you have zIndex inside a ForEach inside a ScrollView , it does.

Does not work for me:

List {
    ForEach { index
       View()
          .zIndex(index == 1 ? 1 : 0)
    }
}

Works:

VStack {
    ScrollView {
        ForEach { index
           View()
              .zIndex(index == 1 ? 1 : 0)
        }
    }
}

Does anyone have an idea why?

It seems zIndex is not working inside List in SwiftUI (even SwiftUI 2). One workaround could be to introspect the UITableViewCell and change its zPosition of the layer, Like the following;

 var body: some View {
    List {
        Text("First Row")
            .background(Color.green)
            .padding()
            .listRowZIndex(1)
        Text("Second Row")
            .background(Color.red)
            .padding()
            .listRowZIndex(0)
            .offset(x: 0, y: -30)
    }
 }

Then create the ViewModifier;

struct ListRowZIndex: ViewModifier {
    
    @State var zIndex : CGFloat = 0.0
        
    func body(content: Content) -> some View {
        content.background(ListRowZindexHelperView(zIndex: zIndex))
    }
}

extension View {
    func listRowZIndex(_ index: CGFloat = 0.0) -> some View {
            self.modifier(ListRowZIndex(zIndex: index))
    }
}

Required implementation;

struct ListRowZindexHelperView: UIViewRepresentable {
    let zIndex : CGFloat
    let proxy = ListRowZindexHelperProxy(cellWrapper: UITableViewCellWrapper(cell: UITableViewCell()))
    
    func makeUIView(context: Context) -> UIView {
        return UIView()
    }

    func updateUIView(_ uiView: UIView, context: Context) {
        proxy.catchUITableViewCell(for: uiView)
        proxy.chnageZIndex(zIndex)
    }
}


class ListRowZindexHelperProxy {

    var uiTableViewCellWrapper: UITableViewCellWrapper
    
    init(cellWrapper: UITableViewCellWrapper) {
        uiTableViewCellWrapper = cellWrapper
    }

    func catchUITableViewCell(for view: UIView) {
        if let cell = view.enclosingUITableViewCell() {
            uiTableViewCellWrapper.uiTableViewCell = cell
        }
    }

    func chnageZIndex(_ zIndex: CGFloat = 0.0) {
        uiTableViewCellWrapper.uiTableViewCell.layer.zPosition = zIndex
    }
}

class UITableViewCellWrapper {
    var uiTableViewCell : UITableViewCell
    
    init(cell: UITableViewCell) {
        uiTableViewCell = cell
    }
}

extension UIView {
    func enclosingUITableViewCell() -> UITableViewCell? {
        var next: UIView? = self
        repeat {
            next = next?.superview
            if let asUITableViewCell = next as? UITableViewCell {
                return asUITableViewCell
            }
        } while next != nil
        return nil
    }
}

Result; Preview

The Second row goes behind the first row since first row has a higher zIndex now

Answer is inspired from this answer

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM