I have problem with making resizable UIImage where corners are not resized. What I want to achieve is to resize middle part using UIImageResizingModeTile. I.e. it should look something like following figure where corners A, B, C, D are original and all other parts are resized:
|-------------|
|A| |B|
|-------------|
| |
| |
|-------------|
|C| |D|
|-------------|
I tried with resizableImageWithCapInsets: but it doesn't resize middle parts well in way they are not made as pattern, but instead then are stretched which looks pretty bad. I noticed that because my image has "bubble" border so it's pretty noticeable. Take a look at sample image, it may be helpful.
Related
This is an extension of my previous question (Get width of a view using in SwiftUI)
I need to implement a layout where number of items per row is determined dynamically, based on their combined width (basically, place items in a row until they no longer fit).
I've been told that using the GeometryReader is a hacky way to do something in a declarative language, which is obviously true.
I have also been directed to this CollectionView-like component https://github.com/Q-Mobile/QGrid but the solution is static as the number of rows and cells per row is determined once, before any components are rendered.
I have no idea how to approach this, so any advice is very valuable for me!
❤️❤️❤️
TL;DR
GeometryReader may be a "hacky" solution, but it is the solution we have at the moment. It is possible to create a solution that reflows a small number of items dynamically, or a large number of items with a delay. My demo code would be unwieldy here, but it sounds like describing my approach may be useful.
Working with what we've got
Behind the scenes, SwiftUI is doing all kinds of optimized constraint solving to layout your views efficiently. In theory, reflowing content like you describe could be part of that constraint solving; in today's SwiftUI, it is not. Therefore, the only way to do what you are describing is some variant of the following:
Let SwiftUI lay everything out based on our data model.
Get the widths that SwiftUI decided on using Geometry reader and preferences/callbacks.
Use these widths to solve our reflow constraints.
Update the data model, which will trigger step 1.
Hopefully, this process converges to a stable layout, rather than entering an endless loop.
My results
After playing around with it, here's what I've gotten so far. You can see that a small number of items (29 in my example) reflow almost instantaneously as the width is changed. With a large number of items (262 in my example), there is a noticable delay. This shouldn't be much of an issue if the content and view width don't change and won't need to be updated frequently. The time is spent almost entirely in step 1, so until we get proper reflow support in SwiftUI, I suspect this is as good as it gets. (In case you're wondering, the vertical scrollview scrolls with normal responsiveness once the reflow is finished.)
My strategy
Essentially, my data model starts with a [String] array and transforms it to a [[String]] array, where each internal array corresponds to one line that will fit horizontally in my view. (Technically it starts with a String that is split on whitespace to form the [String], but in a generalized sense, I've got a collection I want to split into multiple lines.) Then I can lay it out using VStack, HStack, and ForEach.
My first approach was to try to read the widths off the actual views I'm displaying. However, I quickly ran into infinite recursions or weirdly unstable oscillations because it might truncate a Text view (e.g. [Four] [score] [and] [se...]), and then un-truncate once once the reflow changed, back and forth (or just end in a truncated state.
So I decided to cheat. I lay out all the words in a second, invisible horizontal scrollview. This way, they all get to take up as much space as they want, never get truncated, and most importantly, because this layout only depends on the [String] array and not the derived [[String]] array, it can never enter a recursive loop. You may think that laying each view twice (once for measuring width and once for displaying) is inefficient, but I found it to be dozens of times faster than trying to measure the widths from the displayed views, and to produce proper results 100% of the time.
+---------- FIRST TRY - CYCLIC ----------+ +-------- SECOND TRY - ACYCLIC --------+
| | | |
| +--------+ [String] +----------+ | | +-------+ [String] +--------+ |
| | | | | | | |
| | +--------------------------+ | | | v v |
| | | | | | | Hidden +--> Widths +--> [[String]] |
| v v + v | | layout | |
| Display +--> Widths +--> [[String]] | | v |
| layout | | Display |
| | | layout |
+----------------------------------------+ +--------------------------------------+
To read and save the widths, I adapted the GeometryReader/PreferenceKey approach detailed on swiftui-lab.com. The widths are saved in the view model, and updated whenever the number or size of views in the hidden scrollview change. Such a change (or changing the width of the view) then reflows the [String] array to [[String]] based on the widths saved in the model.
Summary
Now, whether any of this is useful in a shipping application will depend on how many items you want to reflow, and whether they will be static once laid out or changing often. But I found it to be a fascinating diversion!
It's a two step process using a GeometryReader.
Measure for each item the width of content(item).
Use measurements to lay items out into rows.
Only problem is that it has to recalculate on each redraw or cache the priorly measured width, which is not necessarily a problem with just a few items though.
I won't post the code here since it uses GeometryReader which is not something the author wants to use.
First time poster, so it won't let me add images.
I've started building my first app ever (outside of "Hello, Word" and "Game of War)
I can't figure out a good strategy to changing container alignments when rotating iOS device.
I would like to make my game playable on iPhone and iPad.
Each 'View' container has a UIImage in it (so I can keep the image at the proper orientation).
In 'Portrait' mode, my containers are lined up like this:
| x |
| y |
| z |
In 'Landscape' mode, I would like my containers to not be aligned horizontally, so I don't have to make my images super small. I really wish I could post an image to show you.
Imagine "x,y,z" above, except 'x' is to the right of 'y', and 'z' to the left of y. The bottom of 'x' is lined up about the center of 'y', and the top of 'z' is lined up about the center of y.
Sorry, I tried making this as clear as possible.
I figured it out on my own using the following article.
http://corsarus.com/2015/adaptive-layout-part-2-working-with-interface-builder/
I hope this helps someone else.
I have a UIControl subclass that changes appearance and size when touched, a bit like the button of an iOS keyboard turns into the typewriter hand when touched:
I’m not sure how to write it. The idea is to draw a different shape when the default button shape is highlighted:
+---+
| |
+---+ | |
| | -> touch -> | |
+---+ +---+
But since the default button is smaller than the highlighted shape, the bigger shape gets clipped. I have considered these options:
Drawing outside the default frame. Does not seem to be possible.
Changing the size of the control when highlighted. Feels quite hacky and error-prone.
Enlarging the control to accomodate the larger shape. Feels “wrong”, I’d like to be able to work with the control in its smaller, default shape.
Is there a best practice for this scenario?
Here are a few approaches:
You can draw outside the frame, you just have to make sure that myView.clipsToBounds is False. This would allow you to draw outside the bounds of the view inside another view and draw whatever extra content you would like.
That is probably the cleanest solution, but is also a bit "hacky" in my opinion. The other approach would be dirty (as you said) and to reset the frame size.
The last approach would be to create another view (the key pressed down) and throw it on top of the original (unpressed key) view.
All in all, it really comes down to what you're drawing / showing inside your view.
Wondering if there is an easy way to remove a rectangular slice across the entire width of an image using Gimp, and have the resulting hole closed up automatically. I hope that makes sense. If I select a slice across an image and do "cut", it leaves a blank "hole" there. I want the new top and bottom of the image to join and fill that hole, reducing the image height by the amount sliced out.
Any easy way to do this?
Here is a method that is quick and often does what you want:
Cut out the middle, leaving a transparent "hole".
Click anywhere to remove the selection (so the hole is not selected).
Click Image > Zealous crop .
This is going to remove the middle part. However, if you also have transparency in other parts of the image (like around the edges) it's going to remove that transparency too.
I believe you're asking to do something like cut out the middle of a page, leaving the header and footer and have the blank space removed with the cut action, effectively joining the header and footer together.
To my knowledge, I don't believe so. Even if you cut, or delete, that space is still part of the image even without content.
But, you would be able to highlight the top or bottom (or left or right) of the remaining space and drag it to align with the other side. It's not ideal for repetitive tasks, but should get you through if you only have to do it a few times.
Install Python and the Python Imaging Library. Back in GIMP, select and cut the full-width areas you don't want to transparent, and export the image to test.png. Then use this Python code (works only if complete lines are transparent; will not work properly if there are 100%-transparent pixels anywhere other than on a full-width row)—
from PIL import Image
i = Image.open("test.png")
b = i.tobytes()
b2 = ''.join(b[n:n+4] for n in xrange(0,len(b),4) if ord(b[n+3]))
newHeight = len(b2)/i.width/4
i2 = Image.frombytes('RGBA',(i.width,newHeight),b2)
i2.save("test.png")
Then re-load test.png and verify that the areas you cut have gone.
In gimp 2.8.1 you can easily create a new image from a selection. So if you select a rectangular than do a copy (Ctrl-C) and a past in a new image
Edit -> Paste as -> new image (or Ctrl-Shift-V).
I am very new in Iphone development.
I have a requirement to display images in a tabular form [row column wise].
---------------------------------------
| Img1 img2 img3 img4 |
| Img6 img7 img8 img9 |
---------------------------------------
Will you please inform me the best way to accomplish this.
Thanks in advance.
Suhas.
You can go for multi column grid table view layout , where you can define each and every row and column.
you can check this tutorial for Drawing a Grid in a iPhone UITableView – Tabular Cell Data
http://usxue.is-programmer.com/posts/14176.html
http://www.iphonedevx.com/?p=153
You should look into using a UIScrollView for this. Set the contentSize accordingly to your needs.