GithubHelp home page GithubHelp logo

q-mobile / qgrid Goto Github PK

View Code? Open in Web Editor NEW
1.6K 1.6K 105.0 61.35 MB

πŸŽ› QGrid: The missing SwiftUI collection view.

License: MIT License

Swift 100.00%
declarative-ui grid ios swift swift5 swiftui swiftui-example

qgrid's People

Contributors

bryanbartow avatar chabose avatar davedelong avatar giiiita avatar karolkulesza avatar kristianpennacchia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

qgrid's Issues

Trouble importing package

Tried to bring QGrid into a SwiftUI project via package manager , Xcode 11.4.1, received a very vague error: "QGrid could not be resolved" "An unknown error occurred"

Grid with static cells

Hi @karolkulesza,

Amazing stuff mate, been waiting for this since SwiftUI was introduced! : )

Im trying to make a simple grid without data (static cells), but got the error bellow. Any idea what is wrong?

I am using:
Xcode 11 Beta 5
Catalina Beta 5

Screenshot 2019-08-11 at 15 02 02

`// GridView.swift

import QGrid
import SwiftUI

struct GridView: View {
var body: some View {
QGrid(columns: 4, { ProductCell() }
}
}

#if DEBUG
struct GridView_Previews : PreviewProvider {
static var previews: some View {
GridView()
}
}
#endif`

add to project

I try to add this to my project but it's falied ,The Xcode show me
Showing All Messages
: The repository could not be found. Make sure a valid repository exists at the specified location and try again.

I don't know why

GeomertyReader seems to cause problems

When using the GeometryReader inside of a cell, the grid is not rendered as expected. The cells are overlapping as shown in the image below.

struct DataPoint: Identifiable{
    var id = UUID()
    var name:String
}


struct ContentView: View {
    var data:Array<DataPoint> = [DataPoint(name: "A"), DataPoint(name: "B"), DataPoint(name: "C"), DataPoint(name: "D"), DataPoint(name: "E"), DataPoint(name: "F"), DataPoint(name: "G"), DataPoint(name: "H"), DataPoint(name: "J"), DataPoint(name: "K"), DataPoint(name: "L"), DataPoint(name: "M")]
    
    var body: some View {
        QGrid(data,
              columns: 3,
              columnsInLandscape: 4,
              vSpacing: 0,
              hSpacing: 0,
              vPadding: 0,
              hPadding: 0,
              content: {data in
                GeometryReader{g in
                    VStack{
                        Text(data.name)
                    }.frame(width:g.size.width, height: g.size.width).background(Color.yellow)
                }
        })
    }
}

Screenshot 2019-10-28 at 1 53 35

Any suggestions how to make sure that every cell is squared, independent from the screen size?

Not Lazy?

Testing this in the simulator and every cell is generated on launch, not as you scroll (like SwiftUI List).

Or have I misunderstood something?

On iPad, NavigationLink sometimes doesn't work in DoubleColumnNavigationViewStyle()

When NavigationLink is embedded like this:

CollectionView(self.Containers.containers, columns: 3) { container in
	NavigationLink(destination: ContainerDetailView(container: container)) {
		ContainerCell(container: container)
		.environmentObject(self.Containers)
		.accentColor(.primary)
	}
}

tapping on it sometimes doesn't open NavigationLink destination. onTapGesture works always though.

There is also another issue: when NavigationLink destination is open, NavigationLink destination from navigationBarItems opens and closes instantly after opening.

Safe Area causing some problems when contained in a NavigationView

I noticed that the QGrid only works well when not contained in a NavigationView.

It seems to not correctly respect the safe area and cuts off part of the UI that seem to have the hight of the navigation bar.

Here are some examples of what I mean:

Simulator Screen Shot - iPhone 11 Pro Max - 2019-10-22 at 11 22 03

As you can see part of the UI underneath the navigation bar is cut out.
Also the lower part of the grid is cut out due to the home indicator.

NavigationView {
    QGrid(profiles, columns: 2) { profile in
        ProfileCardView(profile: profile)
    }
}

If I add the .edgesIgnoringSafeArea([.all]) to the grid, this is what happens:

Simulator Screen Shot - iPhone 11 Pro Max - 2019-10-22 at 11 24 24

NavigationView {
    QGrid(profiles, columns: 2) { profile in
        ProfileCardView(profile: profile)
    }
    .edgesIgnoringSafeArea(.all)
}

Wrapping the GridCell in a NavigationLink does not display the image

struct GridCell: View {
var person: Person

var body: some View {
NavigationLink(
destination: Text("")
) {
VStack() {
Image(person.imageName)
.resizable()
.scaledToFit()
.clipShape(Circle())
.shadow(color: .primary, radius: 5)
.padding([.top, .leading, .trailing], 7)
Text(person.firstName).lineLimit(1)
Text(person.lastName).lineLimit(1)
}
.font(.headline).foregroundColor(.white)
}
}
}

Screen Shot 2019-09-15 at 2 33 21 PM

Content not refreshed when creating new views

I have the QGrid setup to render a list of objects that are converted to views inside the QGrid’s block.
When my API fetches updated data the view is rebuilt.
I confirmed that the QGrid is called again, yet, it keeps rendering the initial list of views and not the newly created views.
If I switch to List it works properly. Only with QGrid it doesn’t refresh.
Here is the code in question:

    var body: some View { self.makeView()
        .onReceive(timer) { _ in
            self.refreshView()
        }
    }
    
    private func makeView() -> some View {
        VStack {
                Text("Dashboard").font(.largeTitle)
            if self.circuits.count > 0 {
                // need to use an if, b/c showing scrollable view without content will not refresh later on
                    QGrid<[CircuitInfo], CircuitCell>(self.circuits, columns: 2, columnsInLandscape: 4, vSpacing: 10, vPadding: 10, isScrollable: true) { circuit in
                        CircuitCell(circuit: circuit)
                }
            }
            Spacer()
            HStack {
                Text("\(self.circuitsCount())").font(.footnote).padding(5)
                Spacer()
                Text("Updated: \(lastUpdated)").font(.footnote).padding(5)
            }
        }
    }

Any ideas as to what I might be doing wrong?

Cocoapods support?

This library looks awesome, but probably not going to use it without cocoapods support. For me, it's probably not worth using two dependency managers in the same project (especially with SPM being such a new technology).

I totally understand if you don't want to support multiple dependency managers, but if you did, you'd probably get more traction, usage, and PRs.

Paging

Hi,

Is it possible to add paging functionality when sliding. Thanks.

Andy

Crash on macOS with images in the grid

Environment

  • macOS 10.15.3
  • Xcode 11.3.1
  • QGrid 5.13.2

Steps to reproduce:

  1. Init a new macOS app project
  2. Add QGrid as dependency
  3. Change the content of ContentView.swift as follows:
    import SwiftUI
    import QGrid
    
    struct Item: Identifiable {
        let id = UUID()
    }
    
    struct ContentView: View {
        let array = Array(repeating: Item(), count: 15)
    
        var body: some View {
            QGrid(array, columns: 3) { value in
                Image("") // empty image is being used for simplicity. Using real image doesn't prevent the crash
            }
        }
    }
    
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
  4. Run the app
  5. Resize the app window by dragging

What do I expect

The app window resized.

What did I see

The app crashed with the following log:

2020-03-25 13:26:59.993525+0800 qgrid test[40447:1852701] *** Assertion failure in -[_TtC7SwiftUIP33_A874FC5B9DB530D4375C25AE2AA39DF215HostingClipView setBoundsOrigin:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/AppKit/AppKit-1894.30.142/AppKit.subproj/NSView.m:5645
2020-03-25 13:26:59.994618+0800 qgrid test[40447:1852701] [General] Invalid parameter not satisfying: !isnan(newOrigin.x)
2020-03-25 13:26:59.998896+0800 qgrid test[40447:1852701] [General] (
	0   CoreFoundation                      0x00007fff2c4f48ab __exceptionPreprocess + 250
	1   libobjc.A.dylib                     0x00007fff627ae805 objc_exception_throw + 48
	2   CoreFoundation                      0x00007fff2c51dd10 +[NSException raise:format:arguments:] + 88
	3   Foundation                          0x00007fff2ec16241 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 191
	4   AppKit                              0x00007fff296bc20f -[NSView setBoundsOrigin:] + 621
	5   AppKit                              0x00007fff296bbf80 -[NSClipView setBoundsOrigin:] + 42
	6   SwiftUI                             0x00007fff39950033 $s7SwiftUI15HostingClipView33_A874FC5B9DB530D4375C25AE2AA39DF2LLC12setFrameSizeyySo6CGSizeVF + 547
	7   SwiftUI                             0x00007fff39950720 $s7SwiftUI15HostingClipView33_A874FC5B9DB530D4375C25AE2AA39DF2LLC12setFrameSizeyySo6CGSizeVFTo + 48
	8   AppKit                              0x00007fff29687ca2 -[NSView setFrame:] + 423
	9   AppKit                              0x00007fff296e45f0 -[NSScrollView _setContentViewFrame:] + 328
	10  AppKit                              0x00007fff296e3f34 -[NSScrollView _applyContentAreaLayout:] + 1054
	11  AppKit                              0x00007fff296e125e -[NSScrollView tile] + 773
	12  AppKit                              0x00007fff296e0f3c -[NSScrollView _tileWithoutRecursing] + 35
	13  AppKit                              0x00007fff2977ae5b -[NSScrollView _update] + 27
	14  AppKit                              0x00007fff29675cf6 -[NSView setFrameSize:] + 1714
	15  AppKit                              0x00007fff2977abb4 -[NSScrollView setFrameSize:] + 242
	16  AppKit                              0x00007fff29687ca2 -[NSView setFrame:] + 423
	17  SwiftUI                             0x00007fff397f29b3 $s7SwiftUI16PlatformViewHostC012updateHostedD6BoundsyyF + 195
	18  SwiftUI                             0x00007fff397f7245 $s7SwiftUI16PlatformViewHostC6layoutyyFTo + 21
	19  AppKit                              0x00007fff2969d100 _NSViewLayout + 600
	20  AppKit                              0x00007fff2969cba3 -[NSView _layoutSubtreeWithOldSize:] + 388
	21  AppKit                              0x00007fff2969ccfd -[NSView _layoutSubtreeWithOldSize:] + 734
	22  AppKit                              0x00007fff2969ccfd -[NSView _layoutSubtreeWithOldSize:] + 734
	23  AppKit                              0x00007fff2969bfd2 -[NSView _layoutSubtreeIfNeededAndAllowTemporaryEngine:] + 1137
	24  AppKit                              0x00007fff2969ba6e -[NSWindow(NSConstraintBasedLayout) _layoutViewTree] + 148
	25  AppKit                              0x00007fff29698434 -[NSWindow _oldPlaceWindow:fromServer:] + 805
	26  AppKit                              0x00007fff296966dd -[NSWindow _setFrameCommon:display:fromServer:] + 1352
	27  AppKit                              0x00007fff29a1ef8a -[NSWindow(NSWindowResizing) _resizeWithEvent:] + 2664
	28  AppKit                              0x00007fff298f76a6 -[NSTitledFrame attemptResizeWithEvent:] + 177
	29  AppKit                              0x00007fff298f7387 -[NSThemeFrame handleMouseDown:] + 294
	30  AppKit                              0x00007fff29992004 -[NSThemeFrame mouseDown:] + 30
	31  AppKit                              0x00007fff29879b0d -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 4907
	32  AppKit                              0x00007fff297e3c5c -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 2612
	33  AppKit                              0x00007fff297e3005 -[NSWindow(NSEventRouting) sendEvent:] + 349
	34  AppKit                              0x00007fff297e137c -[NSApplication(NSEvent) sendEvent:] + 352
	35  AppKit                              0x00007fff2962d0cf -[NSApplication run] + 707
	36  AppKit                              0x00007fff295ff465 NSApplicationMain + 777
	37  qgrid test                          0x000000010000535d main + 13
	38  libdyld.dylib                       0x00007fff63b1c7fd start + 1
	39  ???                                 0x0000000000000003 0x0 + 3
)
2020-03-25 13:27:00.018820+0800 qgrid test[40447:1852701] It's not legal to call -layoutSubtreeIfNeeded on a view which is already being laid out.  If you are implementing the view's -layout method, you can call -[super layout] instead. Break on void _NSDetectedLayoutRecursion(void) to debug.  This will be logged only once.  This may break in the future.

Use of unresolved identifier 'UIDevice'

Upon adding the Swift Package, I get the compile time error Use of unresolved identifier 'UIDevice'even when not using the package yet.

The line throwing the error is

private var cols: Int {
    UIDevice.current.orientation.isLandscape ? columnsInLandscape : columns
}

in QGrid.swift.

Target is macOS Catalina.

Demo of QGridTestApp problem

If you embed the ZStack in a List as in the following:

var body: some View {
    GeometryReader { geometry in
        List {
            ZStack {
                self.backgroundGradient
                    .edgesIgnoringSafeArea(.all)
                VStack {
                    if (QConstants.showDesigner) { self.designerView(geometry) }
                    self.gridView(geometry)
                }
            }
        }
    }
}

Then you get this in the simulator:

Screenshot 2019-11-12 at 12 42 31

I have tried various experiments and the best I can come up with is to add a frame modifier as in:

var body: some View {
    GeometryReader { geometry in
        List {
            ZStack {
                self.backgroundGradient
                    .edgesIgnoringSafeArea(.all)
                VStack {
                    if (QConstants.showDesigner) { self.designerView(geometry) }
                    self.gridView(geometry)
                    .frame(width: geometry.size.width,
                           height: geometry.size.height)
                }
            }
        }
    }
}

But this is still wrong because the grid is in the wrong place (see screenshot) and I can't work out how to fix it. Any ideas?

Screenshot 2019-11-12 at 12 50 06

Inconsistent state after rotation

I have a 1 x 8 grid in portrait mode and 2x4 grid in landscape mode.
I have a button in each view in the grid that toggles using @State
I set button 1 and 2 on (it change color to green).
I rotate the simulator to landscape mode. columns are displayed correctly (2 x 4 grid).
but now, buttons 1 and 3 show the green button.

Looks like there's some recycling going on? Each gridview has the state internally.

Multiple items navigation

Hello,

I am wondering if is there any solution for navigating to different items inside the QGrid.
When clicking in an item it processes all the items click actions and navigates to all the links one after the other.

QGrid(self.dashboardViewModel.dashboardItems, columns: 2, isScrollable: false, showScrollIndicators: false) { dashboardItem in
    NavigationLink(destination: PlayerProfileView(playerLocalId: dashboardItem.actionId)) {
        DashboardItem(dashboardItemVE: dashboardItem)
    }.buttonStyle(PlainButtonStyle())
}

Use QGrid inside another scroll view

I have a use case where I need to have a parent scroll view with some other content and then I have a QGrid view that scrolls by itself
How do I handle this case as the scrolling is not intuitive
I would like to know if I could do something to resolve this

VStack{
                    ScrollView(.vertical , showsIndicators: false){
//                        VStack(alignment: .leading, spacing: 10) {
                            BannerView()
                            CategoryRow().environmentObject(self.latestViewModel)
                            ColorRow().environmentObject(self.latestViewModel)
                    }
                            if(latestViewModel.error.isEmpty){
                               QGrid(latestViewModel.wallpapers,columns: self.columns, vSpacing : 20.0, hSpacing: 5.0,
                                       hPadding: 10.0, endReached: {
                                        //print("End Reached")
                                        self.latestViewModel.getMoreWallpapers()
                                       }){wallpaper in
                                    self.getLatestTabItem(wallpaper: wallpaper)
                                }

Just a code snippet to demonstrate what I exactly want to do

support Core Data NSManagedObjects for initial data

Can this Data.Element : Identifiable remove from

public struct QGrid<Data, Content> : View where Data : RandomAccessCollection, Content : View, Data.Element : Identifiable 

to support Core Data NSManagedObjects

Darkmode override

App keeps crashing if I try to override the darkmode colorscheme for views where I use QGrid

Unexpected behaviour with empty initial value

Hello! Here is an example where I expect the grid appears after button tap, but I got empty grid

struct ContentView: View {
	
	@ObservedObject var viewModel = ContentViewModel()
	
	var body: some View {
		VStack {
			Button("Get all values") {
				self.viewModel.tap()
			}
			Text(String(self.viewModel.models.count))
			QGrid(self.viewModel.models, columns: 3) {
				GridCell(value: $0)
			}
		}
	}
}

class ContentViewModel: ObservableObject {
	
	@Published var models: [String] = [ ]
	
	func tap() {
		self.models = ["1", "2", "3"]
	}
}

extension String: Identifiable {
	public var id: String {
		return self
	}
}

struct GridCell: View {
	var value: String
	
	var body: some View {
		Text(self.value)
	}
}

However it works correctly if models value has at least one initial element. Can you explain what should I do in this case? Or is it a bug?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.