Add Read More/Read Less to the end of UILabel SWIFT - uilabel

Hi i need a UILabel with Read More and Read less But didn't find any good answer except this one But the problem is, I don't know what this answer is doing. As i have tried this, but getting errors, also IN THIS ANSWER what is "#IBOutlet weak var lblHeight: NSLayoutConstraint!"
My code
import UIKit
class ExpandedLabelViewController: UIViewController {
#IBOutlet weak var myLabel: UILabel!
#IBOutlet weak var lblHeight: NSLayoutConstraint!
#IBOutlet weak var btn: UIButton!
var isLabelAtMaxHeight = false
override func viewDidLoad()
{
super.viewDidLoad()
myLabel.text = "bla bla blabla bla blabla bla blabla bla blabla bla blabla bla bla"
}
#IBAction func btnAction(_ sender: Any)
{
if isLabelAtMaxHeight {
btn.setTitle("Read more", for: .normal)
isLabelAtMaxHeight = false
lblHeight.constant = 70
}
else {
btn.setTitle("Read less", for: .normal)
isLabelAtMaxHeight = true
lblHeight.constant = getLabelHeight(text: "bla bla bla vvvbla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla bla", width: view.bounds.width, font: myLabel.font)
}
}
func getLabelHeight(text: String, width: CGFloat, font: UIFont) -> CGFloat {
let lbl = UILabel(frame: .zero)
lbl.frame.size.width = width
lbl.font = font
lbl.numberOfLines = 0
lbl.text = text
lbl.sizeToFit()
lbl.adjustsFontSizeToFitWidth = true
return lbl.frame.size.height
}
}
In my code i have 2 out of "myLabel" One is UILabel and second in NSLayoutConstraint.
I'm getting this exception.
2018-05-27 12:28:53.274735+0500 testingControllers[8035:240013] -[UILabel setConstant:]: unrecognized selector sent to instance 0x7fbd0f513e60
2018-05-27 12:28:53.291991+0500 testingControllers[8035:240013] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UILabel setConstant:]: unrecognized selector sent to instance 0x7fbd0f513e60'
Any one here, need help.
Thanks

Please try this:-
class FirstViewController: UIViewController, UIGestureRecognizerDelegate {
#IBOutlet weak var myLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
myLabel.text = "bla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla bla"
myLabel.numberOfLines = 2
let tap:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.labelAction(gesture:)))
myLabel.addGestureRecognizer(tap)
myLabel.isUserInteractionEnabled = true
tap.delegate = self
}
#objc func labelAction(gesture: UITapGestureRecognizer)
{
if myLabel.numberOfLines == 0 {
myLabel.numberOfLines = 2
} else {
myLabel.numberOfLines = 0
}
}
}
If you want to handle using button then :
#IBAction func action(_ sender: Any) {
if myLabel.numberOfLines == 0 {
myLabel.numberOfLines = 2
} else {
myLabel.numberOfLines = 0
}
}
Also, you need to set constraints for the label height like below screenshot:
If you want to show more and less text at the end of label text then add more text and less text in the label accordingly.

Related

Use combineLatest with an array of observables

I have 4 text input fields. When the user enters text into any of the fields, I will enable a button. To accomplish this, I will use the combineLatest by combining 4 observables that receive text in their streams. I am at a loss as to how to access the latest value of each of the observables. NOTE: I want to use an array as eventually there will be more than 4 input fields. I am also looking for a solution in Kotlin.
val text1: PublishSubject<String> = PublishSubject.create()
val text2: PublishSubject<String> = PublishSubject.create()
val text3: PublishSubject<String> = PublishSubject.create()
val text4: PublishSubject<String> = PublishSubject.create()
val inputs = Arrays.asList(
text1, text2, text3, text4
)
Observable.combineLatest(inputs) {
// How do I access the latest value from each observable?
}
Inside the lambda you get an array. The i-th element of this array (arrayOfEmissions in the following example) corresponds to the latest element emitted by the i-th observable.
Observable.combineLatest(inputs) { arrayOfEmissions ->
}
You can combine them and provide a function to wrap the values into a custom class:
Observable.combineLatest(
text1,
text2,
text3,
text4,
Function4<String, String, String, String, LatestResult> { t1, t2, t3, t4 ->
LatestResult(t1, t2, t3, t4)
})
.subscribe { latestResult ->
// Access the latest results here:
println(latestResult.text1)
println(latestResult.text2)
println(latestResult.text3)
println(latestResult.text4)
}
}
data class LatestResult(val text1: String, val text2: String, val text3: String, val text4: String)
You can use any of these extension functions:
// [publisher1, publisher2].combineLatest()
extension Array where Element: Publisher {
func combineLatest() -> AnyPublisher<[Element.Output], Element.Failure> {
Publishers.CombineLatestArray(self)
}
}
// Publishers.CombineLatestArray([publisher1, publisher2])
extension Publishers {
static func CombineLatestArray<P>(_ array: [P]) -> AnyPublisher<[P.Output], P.Failure> where P : Publisher {
array.dropFirst().reduce(into: AnyPublisher(array[0].map{[$0]})) { res, ob in
res = res.combineLatest(ob) { i1, i2 -> [P.Output] in
return i1 + [i2]
}.eraseToAnyPublisher()
}
}
}

Swift: Typecasting Objects That Have Identical Selectors

The Situation
Suppose I have two classes:
class Foo: NSObject {
var specialProperty: String = "hello"
}
class Bar: NSObject {
var specialProperty: String = "goodbye"
}
Now suppose I'm working with a collection that I KNOW contains only Foo and Bar instances. I know that every object in the array will respond to the specialProperty selector, so in Objective-C I could just cast, like this:
for id thing in arrayOfThings
{
NSLog(#"specialProperty: %#", ((Foo *)thing).specialProperty);
}
How can I approach this in Swift? I cannot add a common superclass to Foo and Bar, nor can I add a protocol to them. In reality, Foo and Bar are NSManagedObject subclasses that represent model items in my app.
Selector?
I have considered this approach:
let collection: [AnyObject] // Assume this contains Foo and Bar instances.
let sel: Selector = #selector(setter: Foo.specialProperty)
for item in collection
{
if item.respondsToSelector(sel)
{
instance.perform(sel, with: "new value")
}
}
Will calling sel on instances of Bar work, even though I told Swift the type for the selector was Foo.? It seems like it should because the Objective-C selector mechanism doesn't care what the class of the Object is; that's not part of the selector signature. But I'm unsure if there's something in the Swift-ObjectiveC interaction that I'm overlooking.
Context
I am migrating this app from Objective-C.
The correct approach to this, in both Objective C and Swift, is to use a protocol:
protocol Special {
var specialProperty { get set }
}
class Foo: NSObject, Special {
var specialProperty: String = "hello"
}
class Bar: NSObject, Special {
var specialProperty: String = "goodbye"
}
let collection: [Special] = ...
for item in collection {
item.specialProperty = "new value"
}
I think you can consider this approach as well
let collection: [AnyObject] // Assume this contains Foo and Bar instances.
for item in collection
{
guard let aFoo = item as? Foo else {
guard let aBar = item as? Bar else { continue }
  aBar.specialProperty = "New value"
continue
}
aFoo.specialProperty = "New value"
}
Besides using protocol, I believe it can also be done using optional cast
for item in collection
{
if let foo = item as? Foo
{
// only when casting to Foo successfully
foo.specialProperty
}
if let bar = item as? Bar
{
// only when casting to Bar successfully
bar.specialProperty
}
}

Secondary Constructor param

Can someone please help me work this out? My object had 3 main parameters, all Strings. I now want to add a secondary constructor with an single emum parameter, which in turn would set each of the 3 original params, as follows;
class MyObject(var string1: String, var string2: String, var string3: String)
{
constructor(presetCode: PresetCode ) : this("", "", "")
{
when (presetCode)
{
PresetCode.Code1 ->
{
string1 = "aaa"
string2 = "bbb"
string3 = "ccc"
}
}
}
var anotherObject = AnotherObject(string1)
}
The issue is AnotherObject(string1) isn't working, as string1 is just an empty string.
how can I set the 3 params using this secondary constructor and then successfully call AnotherObject(string1)?
thanks
One option is to replace the secondary constructor with an invoke() method on the companion object:
class MyObject(var string1: String, var string2: String, var string3: String) {
companion object {
operator fun invoke(presetCode: PresetCode) = when (presetCode) {
PresetCode.Code1 -> MyObject("aaa", "bbb", "ccc")
else -> MyObject("", "", "")
}
}
var anotherObject = AnotherObject(string1)
}
In use, it looks just like a constructor call, e.g.:
val o = MyObject(PresetCode.Code1)
This approach is simple, concise, and very flexible.  (For example, it could return a cached instance instead of creating a new one.)
Here is a solution I found based on your class design which requires single AnotherObject construction per MyObject instance:
class MyObject
{
constructor(s1: String, s2: String, s3: String)
{
string1 = s1
string2 = s2
string3 = s3
anotherObject = AnotherObject(string1)
}
constructor(presetCode: PresetCode)
{
when (presetCode)
{
PresetCode.Code1 ->
{
string1 = "aaa"
string2 = "bbb"
string3 = "ccc"
}
else ->
{
string1 = ""
string2 = ""
string3 = ""
}
}
anotherObject = AnotherObject(string1)
}
var string1: String
var string2: String
var string3: String
var anotherObject: AnotherObject
}
Hope this helps.

`let` inside `let` in Kotlin: how to access the first `it`

I have one let inside another one
someMethodCall()?.let{
// ....
// some code here
// ....
val resultCall = it
someMethod2Call()?.let {
// ...
val myVariable = it + resultCall
// ...
}
}
Is it possible in Kotlin inside the second let get access to it of first let and avoid using resultCall variable?
it is a default name for the lambda argument. it is convenient for short lambdas, but you should not use it for longer lambdas. For longer lambdas make the code more readable by specifying an explicit argument name:
someMethodCall()?.let {
resultCall ->
// ... some code that uses "resultCall" instead of "it" ...
}
Use different names to avoid shadowing of the variable in the inner block as in your example:
someMethodCall()?.let {
resultCall ->
// ... some code here ...
someMethod2Call()?.let {
resultCall2 ->
// ...
val myVariable = resultCall2 + resultCall
// ...
}
No it's not possible and you should definitely use explicit names for the parameters in such use cases:
someMethodCall()?.let{ v1->
// ....
// some code here
// ....
someMethod2Call()?.let { v2->
}
}
It helps if you name your variables.
someMethodCall()?.let { resultCall ->
// ....
// some code here
// ....
someMethod2Call()?.let { otherResult ->
// ...
val myVariable = resultCall + otherResult
// ...
}
}
you can use this way
someMethodCall()?.let{ nameOne ->
// ....
// some code here
// ....
val resultCall = nameOne
someMethod2Call()?.let { -> nameTwo
// ...
val myVariable = nameTwo + resultCall
// ...
}
}

What are the use cases for `Delegates.observable` when we have property setters?

What are the use cases for Delegates.observable when we can just use property setters?
var foo by Delegates.observable("hell0") { prop, old, new ->
// react to changes in foo
}
var bar = "hello"
set(value) {
field = value
// react to changes in bar
// we can also do validation, set something like `value*2` to field, etc.
}
Property setters require much more code duplication if you want multiple properties to react to modification in the same way:
var foo: Foo = Foo()
set(value) {
println("foo = $value")
field = value
}
var bar: Bar = Bar()
set(value) {
println("bar = $value")
field = value
}
Delegates, in turn, are aimed to allow for reuse of the property accessors logic, like this:
fun <T> printDelegate(init: T) =
Delegates.observable(init) { prop, _, new ->
println("${prop.name} = $new")
}
val foo: Foo by printDelegate(Foo())
val bar: Bar by printDelegate(Bar())
Delegates.observable are commonly used in Android. One such such case is adding text change listener.
Example
interface TextChangedListener {
fun onTextChanged(newText: String)
}
class PrintingTextChangedListener : TextChangedListener {
override fun onTextChanged(newText: String) = println("Text is changed to: $newText")
}
class TextView {
var listener: TextChangedListener? = null
var text: String by Delegates.observable("") { prop, old, new ->
listener?.onTextChanged(new)
}
}
Usage
val textView = TextView()
textView.listener = PrintingTextChangedListener()
textView.text = "Lorem ipsum"
textView.text = "dolor sit amet"
Output
Text is changed to: Lorem ipsum
Text is changed to: dolor sit amet
You can read more patterns here:
https://github.com/dbacinski/Design-Patterns-In-Kotlin