Why is the Jetpack Compose card radius corner not even - android-cardview

I'm having a lazyColumn that wrap items of
#Composable
fun MySimpleListItem(
itemViewState: String,
itemClickedCallback: (() -> Unit)? = null,
) {
Card(
shape = RoundedCornerShape(50.dp),
backgroundColor = Color(0xFFFF0000),
) {
Text(
text = itemViewState,
modifier = Modifier.fillMaxWidth().padding(16.dp),
style = TextStyle(fontSize = 32.sp),
textAlign = TextAlign.Center
)
}
}
Looks like the corner at the top and bottom is rounded differently. Did I do anything wrong?

Your cards height is too small to display the shape correctly. It should be at least twice as large as your radius
Card(
modifier = Modifier.preferredHeight(100.dp),
shape = RoundedCornerShape(50.dp),
backgroundColor = Color(0xFFFF0000),
)
or set the radius of your shape in percent:
Card(
shape = RoundedCornerShape(50),
backgroundColor = Color(0xFFFF0000),
)

Related

Dynamically position widget in stack Flutter

I am trying to create a view that consist of a background image with widgets positioned dynamically in certain places on this image, each widget will have an x and y that needs to be calculated for different screens and for different image sizes.
what i did so far was showing the image in a stack and made a list of widgets where each widget type is being checked then create a flutter widget that corresponds with it adding it to this list and displaying it over the image in the stack, but i am looking for a cleaner way to create this behavior, also when rotating the screen the widgets are not being placed in a correct position,
Thank you for your time.
You can do something like:
Stack(
children: [
Image.asset('YOUR IMAGE HERE', fit: BoxFit.cover), // this is your bg image,
..List.generate(imagesCollection.length, (index) {
// you could encapsulate all this logic in a separate widget
var img = imagesCollection[index];
var r = Random();
// make sure to stay within the bounds of your screen
var screenWidth = MediaQuery.of(context).size.width;
var screenHeight = MediaQuery.of(context).size.height;
var randomX = r.nextInt(screenWidth);
var randomY = r.nextInt(screenHeight);
// before you position the image, check that is within the bounds
// check if the randomX - IMAGE_WITH is less than the screen width, same for the height
return Positioned(
top: randomY,
left: randomX,
child: Image.asset(img, width: IMAGE_WIDTH, height: IMAGE_HEIGHT)
);
}
]
)
Something around those lines.

How to properly center UITabBar items vertically for UITabBar with larger height and no item titles?

I'm working on a custom UITabBar that has a larger height, custom shadow and no item titles.
I am using the following code for my custom UITabBar class to achieve this like:
class CustomUITabBar: UITabBar {
#IBInspectable private var height: CGFloat = .zero
override func sizeThatFits(_ size: CGSize) -> CGSize {
guard let window = UIApplication.shared.windows.first else {
return super.sizeThatFits(size)
}
var sizeThatFits = super.sizeThatFits(size)
if #available(iOS 11.0, *) {
sizeThatFits.height = height + window.safeAreaInsets.bottom
} else {
sizeThatFits.height = height
}
return sizeThatFits
}
}
Here is the result: On iPhones that have notch (iPhone X, XS, 11, etc.) it looks fine, icons are centered properly, like so:
But on iPhones that have home button instead, tab bar items are not propery centered vertically. Is there a solution to this?
Now they are not centered as I see it on both devices. You can play around with this code:
guard let items = tabBar.items else { return }
for item in items {
item.imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
it adjusts image of TabBarItem:)
With this settings they are going to be centered in each TabBarItem.

How do you move the uiimage inside the uiimageview to the right while retaining the aspect ratio of the original image?

I want to move an image to the right when a user imports it using uiimagepicker but when I set content mode = .right this occurs: The image enlarges for some reason and it looks like it moves to the left
Is there any way to keep the aspect ratio of the uiimageview and the aspect ratio of the imported image, and while also moving it to the right inside the image view.
This is how I want it to be
Here is one approach: custom view, using a sublayer with the content set to the image...
add a CALayer as a sublayer
calculate the aspect-scaled rectangle for the image inside the view's bounds
set the image layer's frame to that scaled rect
then set the layer's origin based on the desired alignment
A simple example:
class AspectAlignImageView: UIView {
enum AspectAlign {
case top, left, right, bottom, center
}
// this is an array so we can set two options
// if, for example, we don't know if the image will be
// taller or narrower
// for example:
// [.top, .right] will put a
// wide image aligned top
// narrow image aligned right
public var alignment: [AspectAlign] = [.center]
public var image: UIImage?
private let imgLayer: CALayer = CALayer()
override func layoutSubviews() {
super.layoutSubviews()
// make sure we have an image
if let img = image {
// only add the sublayer once
if imgLayer.superlayer == nil {
layer.addSublayer(imgLayer)
}
imgLayer.contentsGravity = .resize
imgLayer.contents = img.cgImage
// calculate the aspect-scaled rect inside our bounds
var scaledImageRect = CGRect.zero
let aspectWidth:CGFloat = bounds.width / img.size.width
let aspectHeight:CGFloat = bounds.height / img.size.height
let aspectRatio:CGFloat = min(aspectWidth, aspectHeight)
scaledImageRect.size.width = img.size.width * aspectRatio
scaledImageRect.size.height = img.size.height * aspectRatio
// set image layer frame to aspect-scaled rect
imgLayer.frame = scaledImageRect
// align as specified
if alignment.contains(.top) {
imgLayer.frame.origin.y = 0
}
if alignment.contains(.left) {
imgLayer.frame.origin.x = 0
}
if alignment.contains(.bottom) {
imgLayer.frame.origin.y = bounds.maxY - scaledImageRect.height
}
if alignment.contains(.right) {
imgLayer.frame.origin.x = bounds.maxX - scaledImageRect.width
}
}
}
}
class TestAlignViewController: UIViewController {
let testView = AspectAlignImageView()
override func viewDidLoad() {
super.viewDidLoad()
testView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(testView)
NSLayoutConstraint.activate([
// constrain test view 240x240 square
testView.widthAnchor.constraint(equalToConstant: 240.0),
testView.heightAnchor.constraint(equalTo: testView.widthAnchor),
// centered in view
testView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
testView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
if let img = UIImage(named: "bottle") {
testView.image = img
}
testView.alignment = [.right]
// so we can see the actual view frame
testView.backgroundColor = .green
}
}
Using this image:
in a 240x240 view (view background set green so we can see its frame), we get this result:
Set your UIImage Content mode to aspect fill or aspect fit. Then use auto layout.

Why does NSColor.controlTextColor change according to background color?

I'm working on a Cocoa application and I find that as long as the font color of NSTextField is set to NSColor.controlTextColor, the font will change according to the background color of NSTextField.
For example, when I set the background color to white, the font becomes black.
But when I set the background color to black, the font turns white.
I want to define an NSColor to achieve the same effect. How to achieve it?
If you want to pass in any color and then determine which text color would be more ideal - black or white - you first need to determine the luminance of that color (in sRGB). We can do that by converting to grayscale, and then checking the contrast with black vs white.
Check out this neat extension that does so:
extension NSColor {
/// Determine the sRGB luminance value by converting to grayscale. Returns a floating point value between 0 (black) and 1 (white).
func luminance() -> CGFloat {
var colors: [CGFloat] = [redComponent, greenComponent, blueComponent].map({ value in
if value <= 0.03928 {
return value / 12.92
} else {
return pow((value + 0.055) / 1.055, 2.4)
}
})
let red = colors[0] * 0.2126
let green = colors[1] * 0.7152
let blue = colors[2] * 0.0722
return red + green + blue
}
func contrast(with color: NSColor) -> CGFloat {
return (self.luminance() + 0.05) / (color.luminance() + 0.05)
}
}
Now we can determine whether we should use black or white as our text by checking the contrast between our background color with black and comparing it to the contrast with white.
// Background color for whatever UI component you want.
let backgroundColor = NSColor(red: 0.5, green: 0.8, blue: 0.2, alpha: 1.0)
// Contrast of that color w/ black.
let blackContrast = backgroundColor.contrast(with: NSColor.black.usingColorSpace(NSColorSpace.sRGB)!)
// Contrast of that color with white.
let whiteContrast = backgroundColor.contrast(with: NSColor.white.usingColorSpace(NSColorSpace.sRGB)!)
// Ideal color of the text, based on which has the greater contrast.
let textColor: NSColor = blackContrast > whiteContrast ? .black : .white
In this case above, the backgroundColor produces a contrast of 10.595052467245562 with black and 0.5045263079640744 with white. So clearly, we should use black as our font color!
The value for black can be corroborated here.
EDIT: The logic for the .controlTextColor is going to be beneath the surface of the API that Apple provides and beyond me. It has to do with the user's preferences, etc. and may operate on views during runtime (i.e. by setting .controlTextColor, you might be flagging a view to check for which textColor is more legible during runtime and applying it).
TL;DR: I don't think you have the ability to achieve the same effect as .controlTextColor with an NSColor subclass.
Here's an example of a subclassed element that uses its backgroundColor to determine the textColor, however, to achieve that same effect. Depending on what backgroundColor you apply to the class, the textColor will be determined by it.
class ContrastTextField: NSTextField {
override var textColor: NSColor? {
set {}
get {
if let background = self.layer?.backgroundColor {
let color = NSColor(cgColor: background)!.usingColorSpace(NSColorSpace.sRGB)!
let blackContrast = color.contrast(with: NSColor.black.usingColorSpace(NSColorSpace.sRGB)!)
let whiteContrast = color.contrast(with: NSColor.white.usingColorSpace(NSColorSpace.sRGB)!)
return blackContrast > whiteContrast ? .black : .white
}
return NSColor.black
}
}
}
Then you can implement with:
let textField = ContrastTextField()
textField.wantsLayer = true
textField.layer?.backgroundColor = NSColor.red.cgColor
textField.stringValue = "test"
Will set your textColor depending on the layer's background.

shadow not behind text

I've made a function that is called in drawRect() inside a seperate made class for a Label. However, this draws only behind the text, and not behind the background of the label. I want to have a shadow behind the background of the label, not the text. How can I fix this? The same happens in a seperate made class for a View.
let COLOR_SHADOW_COLOR: CGColor = UIColor.gray.cgColor
let COLOR_SHADOW_OFFSET = CGSize(width: 2, height: -2)
let COLOR_SHADOW_RADIUS: CGFloat = 5
let COLOR_SHADOW_OPACITY: Float = 1.0
func setShadow(on object: UIView) {
object.layer.shadowColor = COLOR_SHADOW_COLOR
object.layer.shadowOpacity = COLOR_SHADOW_OPACITY
object.layer.shadowOffset = COLOR_SHADOW_OFFSET
object.layer.shadowRadius = COLOR_SHADOW_RADIUS
}
Fixed my own problem. The background was the same color as the text, but with a lower opacity. Xcode thinks that it should draw around text then. After using the pipet on the same color, it did made the shadow behind the label and view