Related
This is my function as extension UIImage:
func scaledWithMaxWidthOrHeightValue(value: CGFloat, spacing: CGFloat = 0, backgroundColor: UIColor = .clear, line: Bool = false, printing: Bool = false) -> UIImage? {
let width = self.size.width
let height = self.size.height
if width < value && height < value {
return self
}
let ratio = width/height
var newWidth = value
var newHeight = value
if ratio > 1 {
newWidth = min(width, value)
newHeight = height * (newWidth/width)
} else {
newHeight = min(height, value)
newWidth = width * (newHeight/height)
}
let rangeWidth = newWidth + spacing * 2
let rangeHeight = newHeight + spacing * 2
UIGraphicsBeginImageContextWithOptions(CGSize(width: rangeWidth, height: rangeHeight), false, 0)
let ctx = UIGraphicsGetCurrentContext()
backgroundColor.setFill()
ctx?.fill(CGRect(x: 0, y: 0, width: rangeWidth, height: rangeHeight))
draw(in: CGRect(x: spacing, y: spacing, width: newWidth, height: newHeight))
if printing {
let length: CGFloat = 7
let stroke: CGFloat = 0.5
ctx?.setFillColor(UIColor.red.cgColor)
ctx?.addRect(CGRect(x: spacing, y: 0, width: stroke, height: length))
ctx?.addRect(CGRect(x: 0, y: spacing, width: length, height: stroke))
ctx?.addRect(CGRect(x: rangeWidth - spacing, y: 0, width: stroke, height: length))
ctx?.addRect(CGRect(x: rangeWidth - 8, y: spacing, width: length, height: stroke))
ctx?.addRect(CGRect(x: rangeWidth - length, y: rangeHeight - spacing, width: length, height: stroke))
ctx?.addRect(CGRect(x: rangeWidth - spacing, y: rangeHeight - length, width: stroke, height: length))
ctx?.addRect(CGRect(x: spacing, y: rangeHeight - length, width: stroke, height: length))
ctx?.addRect(CGRect(x: 0, y: rangeHeight - spacing, width: length, height: stroke))
ctx?.drawPath(using: .fill)
}
if line {
ctx?.setStrokeColor(UIColor.red.cgColor)
ctx?.setLineWidth(0.5)
ctx?.addEllipse(in: CGRect(x: spacing, y: spacing, width: newWidth, height: newHeight))
ctx?.drawPath(using: .stroke)
}
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
And in ios 16 it looks like this:
and before the update it was:
Please, tell me where is the crucial place that is causing the problem?
I think the problem is opaque option in UIGraphicsBeginImageContextWithOptions(::_:).
In documentation
A Boolean flag indicating whether the bitmap is opaque. If you know the
bitmap is fully opaque, specify true to ignore the alpha channel and
optimize the bitmap’s storage. Specifying false means that the bitmap must
include an alpha channel to handle any partially transparent pixels.
I had the same problem. I solved it by setting opaque true in UIGraphicsBeginImageContextWithOptions(::_:)
I'm trying to use values from one class/scrren to multiply with another class screen but keep getting 0.
I know i probably do not carry the variable properly from one class to another but seem to have tried almost everything so if I dont get nontype error I just get 0 value when multiplying anything, like I would carry 0 from my second screen in the values which i have to input in the second screen. Any ideas? as Im brand new on kivy
.py
class SecondWindow(Screen):
ageInput = NumericProperty()
weightInput = NumericProperty()
heightInput = NumericProperty()
def info(self):
age = self.ids.ageInput.text
ageVal = int(age)
height = self.ids.heightInput.text
heightVal = int(height)
weight = self.ids.weightInput.text
weightVal = int(weight)
add = int(age) + int(height) - int(weight)
self.ids.label.text = str(add)
addVal = self.ids.label.text
print (addVal)
return ageVal, heightVal, weightVal
class ThirdWindow(Screen):
male = ObjectProperty()
female = ObjectProperty()
second = ObjectProperty()
def bmrCalc(self, button, weight):
choice = self.ids.lbl.text
if choice == "":
self.ids.lbl.text = button
self.weight = self.second.weightInput
if self.ids.lbl.text == "male":
m = 66.5
mw = 13.75 * int(self.second.weightInput)
mh = 5.003 * int(self.second.heightInput)
ma = 6.75 * int(self.second.ageInput)
print(mw)
.kv file
<SecondWindow>:
id: second
name: "second"
age: ageInput
hheight: heightInput
weight: weightInput
lbl1: label
FloatLayout:
canvas.before:
Color:
rgba: 255, 0, 0, 1
Rectangle:
# self here refers to the widget i.e FloatLay
pos: self.pos
size: self.size
Label:
text: "Calorie Intake Calculator"
font_size: 35
pos_hint: {"x": 0.3, "top": 1}
size_hint: 0.35, 0.1
Label:
text: "Enter your age"
font_size: 30
pos_hint: {"x": 0.1, "y": 0.8}
size_hint: 0.3, 0.1
TextInput:
id: ageInput
font_size: 15
multiline: False
pos_hint: {"x": 0.5 , "y":0.82}
size_hint:0.3, 0.05
Label:
text: "Enter your height(cm)"
font_size: 30
pos_hint: {"x": 0.1, "y": 0.6}
size_hint: 0.3, 0.1
TextInput:
id: heightInput
font_size: 15
multiline: False
pos_hint: {"x": 0.5 , "y":0.62}
size_hint:0.3, 0.05
Label:
text: "Enter your weight(kg)"
font_size: 30
pos_hint: {"x": 0.1, "y": 0.4}
size_hint: 0.3, 0.1
TextInput:
id: weightInput
font_size: 15
multiline: False
pos_hint: {"x": 0.5 , "y":0.42}
size_hint:0.3, 0.05
Button:
pos_hint: {"x":0.35, "y": 0.3}
size_hint: 0.3, 0.05
text: "Submit"
on_press:
root.info()
app.root.current = "third"
root.manager.transition.direction = "left"
Label:
id: label
text: "text"
font_size: 15
pos_hint: {"x": 0.7, "y": 0.1}
size_hint: 0.3, 0.2
Button:
pos_hint: {"x":0.35, "y": 0.15}
size_hint: 0.3, 0.05
text: "Back"
on_release:
app.root.current = "first"
root.manager.transition.direction = "right"
<ThirdWindow>:
id: third
name: "third"
lbl: lbl
male: male
female: female
FloatLayout:
canvas.before:
Color:
rgba: 153, 0, 0, 1
Rectangle:
# self here refers to the widget i.e FloatLayout
pos: self.pos
size: self.size
Label:
text: "Calorie Intake Calculator"
font_size: 35
pos_hint: {"x": 0.3, "top": 1}
size_hint: 0.35, 0.1
Label:
text: "Choose Your gender"
font_size: 30
pos_hint: {"x": 0.32, "top": 0.85}
size_hint: 0.35, 0.1
Button:
id: male
pos_hint: {"x":0.35, "y": 0.6}
size_hint: 0.3, 0.1
text: "Male"
on_press:
root.bmrCalc("male", "weight")
Button:
id: female
pos_hint: {"x":0.35, "y": 0.5}
size_hint: 0.3, 0.1
text: "Female"
on_press:
root.bmrCalc("female")
Label:
id: lbl
text: ""
font_size: 15
pos_hint: {"x": 0.35, "top": 0.3}
size_hint: 0.35, 0.1
Button:
pos_hint: {"x":0.35, "y": 0.1}
size_hint: 0.3, 0.05
text: "Back"
on_press:
app.root.current = "second"
root.manager.transition.direction = "right"
I'm creating a line chart view, inspired by this blog post.
The lines are drawn with Path and the gradient with a LinearGradient and a mask, and they are in overlays on top of each other.
My main issue is that, as you can see in the screenshot, the start of all the gradients have a slope, they seem to close too soon if the value is zero (also the ends seem to be cut too early but it's not my main isssue). The starts also seem to begin too late if the value is > 0 (like the orange one).
What I want is for the gradient to fully fill the parts where the red arrows are pointing (removing the slopes and the abrupt cuts).
But I can't find a solution by just shuffling up the magic numbers. Besides, I'd prefer to understand what's happening rather than just poking around.
What am I doing wrong?
I've made a reproducible example, paste this is a ContentView:
struct ContentView: View {
#State var values: [Double] = [0, 0, 1, 2, 0, 6, 4, 0, 1, 1, 0, 0]
#State var totalMaxnum: Double = 6
var body: some View {
GeometryReader { proxy in
ScrollView {
VStack {
// some other view
VStack {
VStack {
RoundedRectangle(cornerRadius: 5)
.overlay(
ZStack {
Color.white.opacity(0.95)
drawValuesLine(values: values, color: .blue)
}
)
.overlay(
ZStack {
Color.clear
drawValuesGradient(values: values, start: .orange, end: .red)
}
)
.frame(width: proxy.size.width - 40, height: proxy.size.height / 4)
// some other view
}
// some other view
}
}
}
}
}
func drawValuesLine(values: [Double], color: Color) -> some View {
GeometryReader { geo in
Path { p in
let scale = (geo.size.height - 40) / CGFloat(totalMaxnum)
var index: CGFloat = 0
let y1: CGFloat = geo.size.height - 10 - (CGFloat(values[0]) * scale)
let y = y1.isNaN ? 0 : y1
p.move(to: CGPoint(x: 8, y: y))
for _ in values {
if index != 0 {
let x1: CGFloat = 8 + ((geo.size.width - 16) / CGFloat(values.count)) * index
let x = x1.isNaN ? 0 : x1
let yy: CGFloat = geo.size.height - 10 - (CGFloat(values[Int(index)]) * scale)
let y = yy.isNaN ? 0 : yy
p.addLine(to: CGPoint(x: x, y: y))
}
index += 1
}
}
.stroke(style: StrokeStyle(lineWidth: 3, lineCap: .round, lineJoin: .round, miterLimit: 80, dash: [], dashPhase: 0))
.foregroundColor(color)
}
}
func drawValuesGradient(values: [Double], start: Color, end: Color) -> some View {
LinearGradient(gradient: Gradient(colors: [start, end]), startPoint: .top, endPoint: .bottom)
.padding(.bottom, 1)
.opacity(0.8)
.mask(
GeometryReader { geo in
Path { p in
let scale = (geo.size.height - 40) / CGFloat(totalMaxnum)
var index: CGFloat = 0
// Move to the starting point
let y1: CGFloat = geo.size.height - (CGFloat(values[Int(index)]) * scale)
let y = y1.isNaN ? 0 : y1
p.move(to: CGPoint(x: 8, y: y))
// Draw the lines
for _ in values {
if index != 0 {
let x1: CGFloat = 8 + ((geo.size.width - 16) / CGFloat(values.count)) * index
let x = x1.isNaN ? 0 : x1
let yy: CGFloat = geo.size.height - 10 - (CGFloat(values[Int(index)]) * scale)
let y = yy.isNaN ? 0 : yy
p.addLine(to: CGPoint(x: x, y: y))
}
index += 1
}
// Close the subpath
let x1: CGFloat = 8 + ((geo.size.width - 16) / CGFloat(values.count)) * (index - 1)
let x = x1.isNaN ? 0 : x1
p.addLine(to: CGPoint(x: x, y: geo.size.height))
p.addLine(to: CGPoint(x: 8, y: geo.size.height))
p.closeSubpath()
}
}
)
}
}
You can see in the screenshot how the orange gradient doesn't properly fill all the area below the line:
The problem is in this line:
let y1: CGFloat = geo.size.height - (CGFloat(values[Int(index)]) * scale)
y1 becomes the height of the entire graph.
You need to subtract 10, because that's what you've been doing for your blue line and all the gradient's other points.
/// subtract 10
let y1: CGFloat = geo.size.height - 10 - (CGFloat(values[Int(index)]) * scale)
I want to create resizable ui view background. It will resize depend on text. I tried following code:
let capInsetsIncoming = UIEdgeInsets(top: 17, left: 26.5, bottom: 17.5, right: 21)
self.contentView.backgroundColor = UIColor(patternImage: UIImage(named:"profileBioBackground")!.resizableImageWithCapInsets(capInsetsIncoming))
Result:
Expected:
This is my background image:
How can I fix this?
I think the easiest way is to use UIImageView as the background. And also, you have to split the original image so that that can be used as resizable image.
Anyway, here is the code:
class ViewController: UIViewController {
#IBOutlet var contentView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
contentView.backgroundColor = nil
let leftBackgroundView = UIImageView()
let rightBackgroundView = UIImageView()
let image = UIImage(named: "profileBioBackground")!
let scale = image.scale
let size = image.size
let leftRect = CGRect(
x: 0,
y: 0,
width: size.width / 2 * scale,
height: size.height * scale
)
let rightRect = CGRect(
x: size.width / 2 * scale,
y: 0,
width: size.width / 2 * scale,
height: size.height * scale
)
leftBackgroundView.image = UIImage(
CGImage: CGImageCreateWithImageInRect(image.CGImage, leftRect),
scale: scale,
orientation: .Up
)?.resizableImageWithCapInsets(UIEdgeInsets(top: 20, left: 4, bottom: 4, right: 16))
rightBackgroundView.image = UIImage(
CGImage: CGImageCreateWithImageInRect(image.CGImage, rightRect),
scale: scale,
orientation: .Up
)?.resizableImageWithCapInsets(UIEdgeInsets(top: 20, left: 16, bottom: 4, right: 4))
leftBackgroundView.setTranslatesAutoresizingMaskIntoConstraints(false)
rightBackgroundView.setTranslatesAutoresizingMaskIntoConstraints(false)
contentView.insertSubview(leftBackgroundView, atIndex: 0)
contentView.insertSubview(rightBackgroundView, atIndex: 0)
let views = ["left": leftBackgroundView, "right": rightBackgroundView]
contentView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat("H:|[left][right(==left)]|", options: nil, metrics: nil, views: views)
+ NSLayoutConstraint.constraintsWithVisualFormat("V:|[left]|", options: nil, metrics: nil, views: views)
+ NSLayoutConstraint.constraintsWithVisualFormat("V:|[right]|", options: nil, metrics: nil, views: views)
)
}
}
And the Storyboard setup, and the result:
How can I set right, left, top and bottom border with color on UITableview in swift?
Thanks,
Try this for full border:
yourtable.layer.masksToBounds = true
yourtable.layer.borderColor = UIColor( red: 153/255, green: 153/255, blue:0/255, alpha: 1.0 ).CGColor
yourtable.layer.borderWidth = 2.0
This is for bottom border:
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.darkGrayColor().CGColor
border.frame = CGRect(x: 0, y: yourtable.frame.size.height - width, width: yourtable.frame.size.width, height: yourtable.frame.size.height)
border.borderWidth = width
yourtable.layer.addSublayer(border)
yourtable.layer.masksToBounds = true
extension UIView {
func addBorderTop(size size: CGFloat, color: UIColor) {
addBorderUtility(x: 0, y: 0, width: frame.width, height: size, color: color)
}
func addBorderBottom(size size: CGFloat, color: UIColor) {
addBorderUtility(x: 0, y: frame.height - size, width: frame.width, height: size, color: color)
}
func addBorderLeft(size size: CGFloat, color: UIColor) {
addBorderUtility(x: 0, y: 0, width: size, height: frame.height, color: color)
}
func addBorderRight(size size: CGFloat, color: UIColor) {
addBorderUtility(x: frame.width - size, y: 0, width: size, height: frame.height, color: color)
}
private func addBorderUtility(x x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, color: UIColor) {
let border = CALayer()
border.backgroundColor = color.CGColor
border.frame = CGRect(x: x, y: y, width: width, height: height)
layer.addSublayer(border)
}
}
I am going to open source my extension classes at some point.
Edit: Here you go, I update the functions in here https://github.com/goktugyil/EZSwiftExtensions
if you want to give the border to tableview with color use below code
for swift 3 :
yourTableView.layer.borderColor = UIColor.gray.cgColor
yourTableView.layer.borderWidth = 1.0