как использовать hsplitview на swift - PullRequest
0 голосов
/ 03 августа 2020

Я пишу приложение Ma c с типичной панелью навигации слева и панелью содержимого справа. Я хочу, чтобы панель начиналась с панели навигации, составляющей 1/4 ширины, а панель содержимого - 3/4 ширины, но я хочу, чтобы вы могли перетаскивать размер панели, ie - как и любое другое приложение.

итак - я нашел HSplitview - который, кажется, мне нужен - я делаю


     HSplitView() 
     {
         NavigationPane()
         ContentPane()
     }

, и это вроде работает. Но на самом деле это не так - проблемы, которые мне нужно исправить:

  • при запуске панель навигации крошечная - больше похоже на 1/20, чем на 1/4, которую я хочу
  • странный интервал между панелью навигации и панелью содержимого, слева от разделителя
  • перетаскиваемый разделитель имеет нулевую ширину - мне нужно точно выровнять курсор с границей панели содержимого, чтобы позволить ему перетаскивать
  • Я хочу сохранить, а затем восстановить позицию, если пользователь перетащит его

так что - любая идея, как я достигну того, что я хотите с hsplitview? Самое странное, что я, похоже, не могу найти какую-либо документацию по нему вообще - официальный Apple do c в основном просто говорит: «Да, есть класс с таким именем».

1 Ответ

0 голосов
/ 04 августа 2020

это оказалось слишком сложно - просто написал свой собственный, который делает именно то, что я хочу - вот он, если кто-то еще этого хочет:

//
//  SplitView.swift
//  CoderExplorer
//
//  Created by Darren Oakey on 3/8/20.
//  Copyright © 2020 Darren Oakey. All rights reserved.
//


import SwiftUI

///
/// a splitter view that has a left and right pane, the splitter can be dragged or set and read programamatically
///
struct SplitView<Left:View, Right:View>: View
{
    ///
    /// provides the view for the left pane
    ///
    @State var left : () -> Left
    
    ///
    /// provides the view for the right pane
    ///
    @State var right : () -> Right
    
    ///
    /// how wide is the draggable section in between the two panes
    ///
    @State var splitterWidth = 10
    
    ///
    /// the x start coordinate of the splitter
    ///
    @State var splitterLocation = 200
    
    ///
    /// used for dragging - where we originally started - we have to keep our own, because the drag coordinates are relative to the location
    /// of the splitter, but we keep changing it while dragging
    ///
    @State var originalLocation = 0
    
    ///
    /// we use this to basically simulate a "dragStart" - as oddly enough swift only gives change and done
    ///
    @State var dragging = false
    
    ///
    /// if being dragged - the alteration to the current splitter location
    ///
    @State var offset : CGFloat = 0
    
    ///
    /// works out what the splitter location should be
    ///
    var splitterLocationComputed : Int 
    {
        if (dragging)
        {
            return originalLocation + Int( offset)
        }
        return splitterLocation
    }
    
    ///
    /// this moves the splitter based on how we've dragged
    ///
    func dragChange( gesture : DragGesture.Value )
    {
        if (!self.dragging)
        {
            self.originalLocation = self.splitterLocation
            self.dragging = true
        }
        self.offset = gesture.location.x + offset - gesture.startLocation.x
    }
    
    ///
    /// dragging is finished - commit the change to the splitter location
    ///
    func dragDone( gesture : DragGesture.Value )
    {
        self.dragging = false
        self.splitterLocation += Int(self.offset)
        self.offset = 0
    }
    
    ///
    /// the view is pretty simple - left pane, splitter, right pane
    ///
    var body: some View
    {
        GeometryReader()
        {
            geometry in
            HStack( spacing:0)
            {
                left().frame( width:CGFloat(self.splitterLocationComputed), height: geometry.size.height)
                Spacer().frame( width : CGFloat( splitterWidth), height : CGFloat( geometry.size.height))
                    .background(Color.blue).gesture( DragGesture().onChanged( dragChange)
                                                        .onEnded(dragDone ))
                right().frame(width: geometry.size.width - CGFloat( self.splitterWidth + self.splitterLocationComputed), height: geometry.size.height)
            }
        }
    }
}


///
/// provide a simple preview
///
struct SplitView_Previews: PreviewProvider
{
    static var previews: some View
    {
        SplitView( left: {Text("green").background(Color.green)},
                   right: {Text("red")}).frame(width:300, height:100)
    }
}


...