I am attempting to add a gradient to a collection view cell as seen below:
So far the result I get does not cover the entire cell:
I have a
collection view cell:
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var cellView: UIView!
let diagonalGradient = DiagonalGradient()
override func layoutSubviews() {
super.layoutSubviews()
diagonalGradient.frame = cellView.bounds
}
as well as a Custom Gradient Class:
class DiagonalGradient: UIView {
let gradient = CAGradientLayer()
override init(frame: CGRect) {
super.init(frame:frame)
setupGradient(color: UIColor.red))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupGradient(color: UIColor.red))
}
func setupGradient(color: UIColor ) {
gradient.colors = [
UIColor.clear.cgColor,
color.cgColor
]
gradient.startPoint = CGPoint(x: 0, y: 1)
gradient.endPoint = CGPoint(x: 1, y: 0)
gradient.frame = bounds
layer.addSublayer(gradient)
}
}
Lastly, in the story board I assign the class of the cellView to my custom gradient class. How do I fix this?
You're setting the gradient layer frame at the wrong time.
Move it to layoutSubviews():
class DiagonalGradient: UIView {
let gradient = CAGradientLayer()
override init(frame: CGRect) {
super.init(frame:frame)
setupGradient(color: UIColor.red))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupGradient(color: UIColor.red))
}
func setupGradient(color: UIColor ) {
gradient.colors = [
UIColor.clear.cgColor,
color.cgColor
]
gradient.startPoint = CGPoint(x: 0, y: 1)
gradient.endPoint = CGPoint(x: 1, y: 0)
// don't do this here
//gradient.frame = bounds
layer.addSublayer(gradient)
}
override func layoutSubviews() {
super.layoutSubviews()
// do this here
gradient.frame = bounds
}
}
Related
How can I change navigationBarBackButton color in SwiftUI? (by
default it's blue)
How can I change navigationBarBackButton text in SwiftUI?
This is my code (an example):
struct ExercisesList : View {
var exercises : [Exercise]
var body: some View {
NavigationView {
List(self.exercises.identified(by: \.number)) {exercise in
NavigationLink(destination: ExerciseDetailView(exercise: exercise)) {
ExerciseRow(exercisE: exercise)
}
}
.navigationBarTitle(Text("Exercises"))
}
}
}
By default, the navigationBarBackButton in "ExerciseDetailView" has a text of Exercise and color of blue.
My question is how can I manipulate these two?
Here is a solution. Hope it will help. In this way, you can use custom UIColor also.
struct ExercisesList : View {
var exercises : [Exercise]
var body: some View {
UINavigationBar.appearance().tintColor = UIColor.red
return NavigationView {
List(self.exercises.identified(by: \.number)) { exercise in
NavigationLink(destination: ExerciseDetailView(exercise: exercise)) {
ExerciseRow(exercisE: exercise)
}
}
}
.navigationBarTitle(Text("Exercises"))
}
}
Currently, No direct methods are available for that(XCode 11 beta 3).
However You can use UINavigationBar method for that,
see below code :
struct ExercisesList : View {
var exercises : [Exercise]
init() {
//navigationBarBackButton color will change//
UINavigationBar.appearance().tintColor = .purple
// you can also set backgroundColor//
UINavigationBar.appearance().backgroundColor = .white
}
var body: some View {
NavigationView {
List(self.exercises.identified(by: \.number)) {exercise in
NavigationLink(destination: ExerciseDetailView(exercise: exercise)) {
ExerciseRow(exercisE: exercise)
}
}
.navigationBarTitle(Text("Exercises"))
}
}
}
I have 1 custom view that extends ConstraintLayout and contains 1 EditText and 2 TextViews
On my custom view i define this attr (and others) :
<attr name="Text" format="string" />
and i use it like :
app:Text="#={login.email}"
Inside my custom view i define :
companion object {
#JvmStatic #BindingAdapter("Text")
fun setText(nMe : View, nText: String) {
nMe.nInput.setText(nText)
}
#InverseBindingAdapter(attribute = "Text")
fun getText(nMe : View) : String {
return nMe.nInput.text.toString()
}
witch works fine in one-way binding
app:Text="#{login.email}"
But when i try to use it in 2-way binding i get erros pointing to ActivityLoginBinding.java java.lang.String callbackArg_0 = mBindingComponent.null.getText(mEmail);
What to do to get 2-way binding?
L.E : After some research i end up with this :
#InverseBindingMethods(InverseBindingMethod(type =
CustomInput::class,attribute = "bind:Text",event =
"bind:textAttrChanged",method = "bind:getText"))
class CustomEditTextBinder {
companion object {
#JvmStatic
#BindingAdapter(value = ["textAttrChanged"])
fun setListener(editText: CustomInput, listener: InverseBindingListener?) {
if (listener != null) {
editText.nInput.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
}
override fun afterTextChanged(editable: Editable) {
listener.onChange()
}
})
}
}
#JvmStatic
#InverseBindingAdapter(attribute = "Text")
fun getText(nMe: CustomInput): String {
return nMe.nInput.text.toString()
}
#JvmStatic
#BindingAdapter("Text")
fun setText(editText: CustomInput, text: String?) {
text?.let {
if (it != editText.nInput.text.toString()) {
editText.nInput.setText(it)
}
}
}
}
}
But right now i get :
Could not find event TextAttrChanged
I think all you need is event = "android:textAttrChanged".
This works for me (set text to empty String if it is 0):
object DataBindingUtil {
#BindingAdapter("emptyIfZeroText")
#JvmStatic
fun setText(editText: EditText, text: String?) {
if (text == "0" || text == "0.0") editText.setText("") else editText.setText(text)
}
#InverseBindingAdapter(attribute = "emptyIfZeroText", event = "android:textAttrChanged")
#JvmStatic
fun getText(editText: EditText) = editText.text.toString()
}
Im trying to translate this JavaFX class to TornadoFX. Hover im not able to figure out how protected void layoutChildren() should be done with TornadoFX?
This is the code I have so far:
class ReversiSquare(x: Int, y: Int) : View() {
var x by property(x)
fun xProperty() = getProperty(ReversiSquare::y)
var y by property(y)
fun yProperty() = getProperty(ReversiSquare::y)
var highlight: Region by singleAssign()
var highlightTransition: FadeTransition by singleAssign()
val model = ReversiModel
override val root = region {
region {
opacity = 0.0
style = "-fx-border-width: 3; -fx-border-color: dodgerblue"
highlight = this
}
// todo not sure this works with singleAssign
highlightTransition = FadeTransition(Duration.millis(200.0), highlight).apply {
fromValue = 0.0
toValue = 1.0
}
styleProperty().bind(Bindings.`when`(model.legalMove(x, y))
.then("-fx-background-color: derive(dodgerblue, -60%)")
.otherwise("-fx-background-color: burlywood"))
val light = Light.Distant().apply {
azimuth = -135.0
elevation = 30.0
}
effect = Lighting(light)
setPrefSize(200.0,200.0)
this += highlight
addEventHandler(MouseEvent.MOUSE_ENTERED_TARGET) {
if(model.legalMove(x ,y).get()) {
with(highlightTransition) {
rate =1.0
play()
}
}
}
addEventHandler(MouseEvent.MOUSE_EXITED_TARGET) {
with(highlightTransition) {
rate = -1.0
play()
}
}
onDoubleClick {
model.play(x, y)
highlightTransition.rate = -1.0
highlightTransition.play()
}
}
}
I'm not sure what you mean by translating to TornadoFX, but writing the layoutChildren in Kotlin would look something like this:
override fun layoutChildren() {
layoutInArea(highlight, 0.0, 0.0, width, height, baselineOffset, HPos.CENTER, VPos.CENTER);
}
EDIT: You updated the code example to a View, so I think I understand what you want now :)
First, make sure the View doesn't require parameters, because that would make it impossible to inject this view. Either pass parameters using by param() or better yet, inject a ViewModel in the scope of the View, and inject that ViewModel into your View.
Maybe you can add x and y as properties to ReversiModel?
If you need to create a custom Region you can create what would be an anonymous inner class equivalent, in Java speak:
class ReversiSquare : View() {
val model: ReversiModel by inject()
override val root = object : Region() {
// ...
override fun layoutChildren() {
layoutInArea(highlight, 0.0, 0.0, width, height, baselineOffset, HPos.CENTER, VPos.CENTER);
}
}
}
To open this View now, create a new scope and push the ReversiModel into it:
// Create the model, set x, y and other initial state in the model
val model = ReversiModel()
model.x = 42
// Create a new scope and push the ReversiModel into it
val scope = Scope(model)
// Find the ReversiSquare in the new scope
find<ReversiSquare>(scope) {
// Do something with the sequare, like openWindow() or similar
}
*Question is : How can i make the button (when pressed) open the link witch corresponds to the chosen shop on the pin?
I have an array of shops (for pins) (i created a class for it, and a class for pinAnnotation)
here i am creating button and pin image
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "annotationReusedId"
var anView = myMapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if anView == nil {
anView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
} else {
anView!.annotation = annotation
}
anView!.image = UIImage(named: "upcycled")
anView?.frame = CGRect(x: 0, y: 0, width: 35, height: 35)
anView!.backgroundColor = UIColor.clear
anView!.canShowCallout = true
let rightButton = UIButton(type: .infoLight)
rightButton.tag = annotation.hash
rightButton.addTarget(self, action:#selector(openLinkInstagram), for: .touchUpInside)
//anView!.animatesDrop = true
anView!.canShowCallout = true
anView!.rightCalloutAccessoryView = rightButton
return anView
}
here is func for openning link
func openLinkInstagram() {
}
I am simply trying to create a view with a contained view that is 50% as tall and high. In the following code, I set constraints to achieve that when I add the view to the super-view. I set translatesAutoResizingMaskToConstraints to false, add the constraints via anchors. I also tried to call setNeedsUpdateConstraints, and add the same constraints in updateConstraints.
But in the following Playground code, I don't see the constrained subview testView. I expect to see an blue view half the size of the orange view, but all i see is orange.
I'm not sure what I am missing here.
//: Playground - noun: a place where people can play
import UIKit
import PlaygroundSupport
class LView: UIView {
var testView = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .orange
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup() {
addSubview(testView)
testView.backgroundColor = .blue
testView.text = "....."
//testView.setNeedsUpdateConstraints()
testView.translatesAutoresizingMaskIntoConstraints = false
testView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.5).isActive = true
testView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.5).isActive = true
testView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
testView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}
}
let testView = LView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
PlaygroundPage.current.liveView = testView