Can anybody point me in the right direction to how I could use UICollectionViewLayout to create an interface similar to the Pinterest column layout?
I tried searching online, but it looks like there are not many examples out there yet.
The 1000memories "Quilt" view is pinterest-like and open source: http://blog.1000memories.com/168-opensourcing-quilt, and you can dig through that to see how it works.
If you're looking for a more conceptual overview, here's the basic idea of what you're going to want to do. The easiest thing by far, if you just need a Pinterest-style layout, is to subclass UICollectionViewFlowLayout. You get a lot of layout help from this class, and Pinterest style is within its capabilities. You only need to override one method.
Set up a normal UICollectionView using UICollectionViewFlow layout. A quick way to do this is:
Drag a UIViewController onto a storyboard, drop a UICollectionView on that. Set the classes to match your custom classes, etc. You can use a delegate and create a delegate class here but strictly speaking that is not necessary to achieve JUST the Pinterest flow layout (you will almost definitely want to break the selection responsibility stuff into a delegate class in reality though).
Stub out a data source. Implementing the data source protocol for UICollectionView (http://developer.apple.com/library/ios/#documentation/uikit/reference/UICollectionViewDataSource_protocol/Reference/Reference.html) is trivially simple. Make sure you set a reuse identifier on your UICollectionViewCell. You need:
(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
just return 1 for now;
(NSInteteger)collectionView:numberOfItemsInSection:
hardcode a number for now, make it 20.
– (UICollectionViewCell *)collectionView:cellForItemAtIndexPath:
This is one of the places where subclassing the flow layout's gonna do you a favor. All you really need to do here is call dequeueReusableCellWithReuseIdentifier:forIndexPath: with the index path. If you added a UIImageView or some labels to the cell, this would be a great place to actually assign the image, text, etc.
In the viewController's viewDidLoad instantiate a UICollectionViewFlowLayout and set the UICollectionView's datasource to yours and layout to flowlayout. Remember, this class is a subclass of UICollectionViewViewController.
self.collectionView.dataSource = [[YourDataSource alloc] init];
self.collectionView.collectionViewLayout = [[UICollectionViewFlowLayout alloc] init];
Ok. At this point you should be able to run your app and see some stuff on the screen. This is a whirlwind overview. If you need more details about how to set up ViewControllers and so on there's tons of stuff available about that.
Now comes the important part, Pinterest-izing the flow layout.
First, add a new class that is a subclass of UIViewControllerFlowLayout. Change your ViewController's viewDidLoad to instantiate this class and assign as the UICollectionView's collectionViewLayout.
The method you are going to need to implement is - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect.
Here's the thing: The superclass is going to do almost all the work for you. Your code is going to look something like this:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
[attributes enumerateObjectsUsingBlock:^(id attr, NSUInteger idx, BOOL *stop) {
float newYCoord = [calculationMethodYouHaveToWriteFor:attr.frame];
attr.frame = CGRectMake(attr.frame.origin.x, newYCoord, attr.size.width, attr.size.height];
}];
}
Pinterest uses fixed-width columns, all you need to do in your calculation method is figure out what column you are in (`attr.origin.x / _columnWidth), and look up the total height in that column from the ivar you've been saving it in. Don't forget to add it to the new object's height and save it back for the next pass.
The flow layout superclass handles: making cells, determining which cells are visible, figuring out the contents size, figuring out the arrangement of the rows in the x direction, assigning index paths to cells. Lots of junk. And overriding that one method lets you fiddle with the y-pos to your heart's desire.
Heres two from github
https://github.com/jayslu/JSPintDemo
https://github.com/chiahsien/UICollectionViewWaterfallLayout
I've used a modified version of Waterfall in a project now, and I'm investigating JSPint now.
I have created a custom uicollectionviewlayout which is used in my personal project. Here is the link. Hope it helps.
https://github.com/johnny0614/YJZAlbumCollectionViewLayout
You can get anything you want from here:
https://github.com/ParsifalC/CPCollectionViewKit
For example(Both these two layouts are custom UICollectionViewLayout):
Related
I'm using OxyPlot in my wpf application as line recorder. It's like the LiveDemo example.
On a larg visible data set, I get some UI performance issues and may the whole application could freez. It seems to be PlotModel.InvalidatePlot which is called with to many points to often, but I didn't found a better way.
In deep:
Using OxyPlot 2.0.0
I code all in the PlotModel. The Xaml PlotView is only binding to the PlotModel.
I cyclical collect data in a thread an put them in a DataSource (List of List which are ItemSoure for the LineSeries)
I have a class which calculates cyclical in a thread the presentation for x and y axis and a bit more. After all this stuff, it calls PlotModel.InvalidatePlot.
If I
have more than 100 k points on the display (no matter if in multiple LineSeries or not)
and add 1 DataPoint per LineSeries every 500 ms
and call PlotModel.InvalidatePlot every 200 ms
not only the PlotView has performance issues, also the window is very slow in reaction, even if I call PlotModel.InvalidatePlot (false).
My goal
My goal would be that the Windo / Application is working normally. It should not hang up because of a line recorder. The best would be if it has no performance issues, but I'm skeptical.
What I have found or tested
OxyPlot has Performance guidelines. I'm using ItemsSource with DataPoints. I have also tried adding them directly to the LineSeris.Points, but then the Plot doesn’t refresh anyway (even with an ObservableCollection), so I have to call PlotModel.InvalidatePlot, what results in the same effect. I cannot bind to a defined LineSeries in Xaml because I don’t know how much Lines will be there. Maybe I missed something on adding the points directly?
I have also found a Github issue 1286 which is describing a related problem, but this workaround is slower in my tests.
I have also checked the time which is elapsed on the call of PlotModel.InvalidatePlot, but the count of points does not affect it.
I have checked the UI thread and it seems it have trouble to handle this large set of points
If I zoom in to the plot and display under 20 k Points it looks so
Question:
Is there a way to handle this better, except to call PlotModel.InvalidatePlot much less?
Restrictions:
I also must Update Axis and Annotations. So, I think I will not come around to call PlotModel.InvalidatePlot.
I have found that using the OxyPlot Windows Forms implementation and then displaying it using Windows Form integration in WPF gives much better performance.
e.g.
var plotView = new OxyPlot.WindowsForms.PlotView();
plotView.Model = Plot;
var host = new System.Windows.Forms.Integration.WindowsFormsHost();
host.Child = plotView;
PlotContainer = host;
Where 'Plot' is the PlotModel you call InvalidatePlot() on.
And then in your XAML:
<ContentControl Content="{Binding PlotContainer}"/>
Or however else you want to use your WindowsFormsHost.
I have a similar problem and found that you can use a Decimator in LineSeries. It is documented in the examples: LineSeriesExamples.cs
The usage is like this:
public static PlotModel WithXDecimator()
{
var model = new PlotModel { Title = "LineSeries with X Decimator" };
var s1 = CreateSeriesSuitableForDecimation();
s1.Decimator = Decimator.Decimate;
model.Series.Add(s1);
return model;
}
This may solve the problem on my side, and I hope it helps others too. Unfortunately it is not documented in the documentation
For the moment I ended up with calculating the time for calling InvalidatePlot for the next time. I calculate it with the method given in this answer, wich returns the number of visible points. This rededuce the performance issue, but dosent fix the block on the UI Thread on calling InvalidatePlot.
I tryed to create a group box with the _createChildControlImpl()-Methode but the layout looks like crap as you can see her http://tinyurl.com/odzgy3v
But when I implement it without _createChildControlImpl() it works fine: http://tinyurl.com/kwzvdm2
Could anybody please tell me what's the reason for this? Thanks in advance!
Have a look at your browser console - there is already a hint.
When you introduce child controls qooxdoo can't reuse the former default appearance of widgets because the appearance id changed (from "groupbox" to "widget/groupBox"). So you have to add your own appearance theme (which can simply forward by using an alias):
qx.Theme.define("test.myAwesomeTheme", {
extend : playground.theme.Appearance,
appearances :
{
"widget/groupBox" : "groupbox",
}
});
qx.theme.manager.Appearance.getInstance().setTheme(test.myAwesomeTheme);
I'm extending playground.theme.Appearance here which extends qx.theme.indigo.Appearance which again extends qx.theme.simple.Appearance. And their you have the groubox definition we are forwarding to.
Here is the complete playground sample.
You are supposed to implement _createChildControl, but not call it directly. Instead call getChildControl in your constructor and let it call _createChildControl, if needed, since it is also caching the result.
GroupBox seems to be a bad fit for what you want - it seems to assume identically sized and shaped elements inside its frame sub-widget, when filled from within the implementation of _createChildControl().
Use another Composite() inside the main container instead, add "Registration" as yet another child control of type label as the first child of the custom widget, and things will look much better (although not identical).
Quick and sloppy proof of concept: http://tinyurl.com/m7ykhta
I am working on a flash project that dynamically generates navigation from an XML. For now I am trying to get it to work with arrays so that I can adapt it to xml once I know the logic works. I am new to as3 and learning has been a tiny bit bumpy. I have been searching for a solution to this but many of the examples I have seen have either been too simple to answer my question or too complex to understand since I am on the new side. This is the code I am working with.
var clientList:Array = new Array("Client1","Client2","Client3","Client4","Client5","Client6","Client7","Client8","Client9","Client10","Client11","Client12","Client13","Client14","Client15");
for each (var cName in clientList){
var newClientBtn:btnClientNav = new btnClientNav();
newClientBtn.x = workX;
newClientBtn.y = workY;
workY += newClientBtn.height;
newClientBtn.mcClientName.text = cName;
lContent.mcWork.addChild(newClientBtn.name);
trace(newClientBtn);
}
I can't fingure out how to properly refernce the dynamically created clips. I have a dynamic text box in the button but can't figure out how to reference it properly to change it, then my next issue will be referencing the buttons to make rollover and click code. I know this probably something simple to fix but I have been looking at it for too long and my eyes are starting to cross.. Thank you in advance for any advice you can give.
Why not store the clips you are creating in an object you can access later?
If you want to reference a movie clip by name though, one way to do it is:
var referenceMC:MovieClip = MovieClip(containerMC.getChildByName(“targetMC”));
If it was a text field or a button you were after, I believe you would do the same but instead cast the result of getChildByName to your desired control.
I also believe you want to add the button itself as a child, not pass its name into your addChild call?
in my Surface application happens this:
When I put an IdentityTag onto my TagVisualizer, a white cross-hair appears. This TagVisualizer adds no TagVisualization when adding a Tag, it just calls some methods in its "VisualizationAdded"-Event.
In my other TagVisualizers before there were no cross-hair but they always had Visualizations added like this in the initialization of the TagVisualizer: tagDef.Source = new Uri("something.xaml", UriKind.Relative);
But how can I ged rid of this cross-hair?
I cannot find anything about it.
By the way, it looks like this: http://img80.imageshack.us/img80/4728/crosshairc.png
http://img80.imageshack.us/img80/4728/crosshairc.png'/>
I've just run into the same problem because I didn't want a TagVisualization to display when I put a tag down (I wanted some items to be displayed in an already displayed librarystack). I solved it by setting the source of the ByteTagDefinition to null
ByteTagVisualizationDefinition tvBlue = new ByteTagVisualizationDefinition();
tvBlue.Value = 02;
tvBlue.Source = null;
MainTagVisualizer.Definitions.Add(tvBlue);
This gets rid of the crosshair - and I assume will work for IdentityTags, although I have not tried.
the crosshairs are used as the default visualization if you dont specify a custom source. we did this in order to let developers get the layout & configuration working without having to first define the visualization. a crosshair was selected as a default visual because it can be helpful in validating your physical offset properties
-robert (former PM for the Surface controls)
We have lots of immutable value objects in our domain model, one example of this is a position, defined by a latitude, longitude & height.
/// <remarks>When I grow up I want to be an F# record.</remarks>
public class Position
{
public double Latitude
{
get;
private set;
}
// snip
public Position(double latitude, double longitude, double height)
{
Latitude = latitude;
// snip
}
}
The obvious way to allow editing of a position is to build a ViewModel which has getters and setters, as well as a ToPosition() method to extract the validated immutable position instance. While this solution would be ok, it would result in a lot of duplicated code, especially XAML.
The value objects in question consist of between three and five properties which are usually some variant of X, Y, Z & some auxiliary stuff. Given this, I had considered creating three ViewModels to handle the various possibilities, where each ViewModel would need to expose properties for the value of each property as well as a description to display for each label (eg. "Latitude").
Going further, it seems like I could simplify it to one general ViewModel that can deal with N properties and hook everything up using reflection. Something like a property grid, but for immutable objects. One issue with a property grid is that I want to be able to change the look so I can have labels and textboxes such as:
Latitude: [ 32 ] <- TextBox
Longitude: [ 115 ]
Height: [ 12 ]
Or put it in a DataGrid such as:
Latitude | Longitude | Height
32 115 12
So my question is:
Can you think of an elegant way to solve this problem? Are there any libraries that do this or articles about something similar?
I'm mainly looking for:
Code duplication to be minimized
Easy to add new value object types
Possible to extend with some kind of validation
Custom Type Descriptors could be used to solve this problem. Before you bind to a Position, your type descriptor could kick in, and provide get and set methods to temporarily build the values. When the changes are committed, it could build the immutable object.
It might look something like this:
DataContext = new Mutable(position,
dictionary => new Position(dictionary["lattitude"], ...)
);
Your bindings can still look like this:
<TextBox Text="{Binding Path=Lattitude}" />
Because the Mutable object will 'pretend' to have properties like Lattitude thanks to its TypeDescriptor.
Alternatively you might use a converter in your bindings and come up with some kind of convention.
Your Mutable class would take the current immutable object, and a Func<IDictionary, object> that allows you to create the new immutable object once editing completes. Your Mutable class would make use of the type descriptor, which would create PropertyDescriptors that create the new immutable object upon being set.
For an example of how to use type descriptors, see here:
http://www.paulstovell.com/editable-object-adapter
Edit: if you want to limit how often your immutable objects are created, you might also look at BindingGroups and IEditableObject, which your Mutable can also implement.
I found this old question while researching my possible options in the same situation. I figured I should update it in case anyone else stumbles on to it:
Another option (not available when Paul offered his solution since .Net 4 wasn't out yet) is to use the same strategy, but instead of implementing it using CustomTypeDescriptors, use a combination of generics, dynamic objects and reflection to achieve the same effect.
In this case, you define a class
class Mutable<ImmutableType> : DynamicObject
{
//...
}
It's constructor takes an instance of the immutable type and a delegate that constructs a new instance of it out of a dictionary, just like in Paul's answer. The difference here, however, is that you override the TryGetMember and TrySetMember to populate an internal dictionary that you're eventually going to use as the argument for the constructor-delegate. You use reflection in order to verify that the only properties that you're accepting are those that are actually implemented in ImmutableType.
Performance wise, I wager that Paul's answer is faster, and doesn't involve dynamic objects, which are known to put C# developers into fits. But the implementation for this solution is also a little simpler, because Type Descriptors are a bit arcane.
Here's the requested proof-of-concept / example implementation:
https://bitbucket.org/jwrush/mutable-generic-example
Can you think of an elegant way to solve this problem?
Honestly, you just dance around the problem, but don't mention the problem itself ;).
If I correctly guess your problem, then the combination of MultiBinding and IMultiValueConverter should do the trick.
HTH.
P.S. BTW, you have immutable class instances, not value objects. With value objects (which are described by struct keyword) you would dance much more no matter if there were setters or not :).