View disappears when apply ConstraintSet in Constraintlayout android - android-constraintlayout

At the beginning, the ImageView is horizontally center. I'm moving the View to the left in Kotlin. After applying, the ImageView disappears. I don't have any clue to debug this issue
override fun onViewCreated(view: View, savedInstanceState: Bundle?){
super.onViewCreated(view, savedInstanceState)
applyConstraintSet.clone(vConstraint)
}
private fun startAnimation() {
applyConstraintSet.setHorizontalBias(R.id.ivAvatar, 0.2F)
val transition = AutoTransition()
transition.duration = 1500
transition.interpolator = AccelerateDecelerateInterpolator()
TransitionManager.beginDelayedTransition(vConstraint, transition)
applyConstraintSet.applyTo(vConstraint)
}
XML
<android.support.constraint.ConstraintLayout
android:id="#+id/vConstraint"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.facebook.drawee.view.SimpleDraweeView
android:id="#+id/ivAvatar"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginBottom="84dp"
android:scaleX="0"
android:scaleY="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
fresco:roundAsCircle="true" />
</android.support.constraint.ConstraintLayout>

I have the same question today.
I fixed it by adding id for all children of ConstraintLayout.
It works for me in version 1.0.2

Related

How can I make sure my Xamarin.Forms iOS custom renderer of my entry uses the element's width?

In my Xamarin.Forms application I use a custom renderer for entries, since I want them to be made of a single, bottom border. The problem is that I can't find out the right code to make the custom renderer use the element's width. Currently, the situation is like this:
As you can see, the bottom border goes far beyond the real element's width, but I don't understand why. Here I found something, but still I don't understand how to fix this and why this happens. My current code for the renderer class is:
public class CustomEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BorderStyle = UITextBorderStyle.None;
var view = Element as CustomEntry;
var borderLayer = new CALayer
{
Frame = new CGRect(0f, Frame.Height + 5, Frame.Width, 1f),
BorderColor = UIColor.Gray.CGColor,
BackgroundColor = UIColor.Magenta.CGColor,
BorderWidth = 13,
MasksToBounds = true
};
Control.Layer.AddSublayer(borderLayer);
}
}
}
The problem seems to be in that Frame.Width. If I set it to 100, for example, the width of the bottom line of the entry is set to 100, but the problem is that, doing so, I'm not able to horizontally center the line. I want this outcome:

How to adjust position of CAShapeLayer based upon device size?

I'm attempting to create a CAShapeLayer animation that draws an outline around the frame of a UILabel. Here's the code:
func newQuestionOutline() -> CAShapeLayer {
let outlineShape = CAShapeLayer()
outlineShape.isHidden = false
let circularPath = UIBezierPath(roundedRect: questionLabel.frame, cornerRadius: 5)
outlineShape.path = circularPath.cgPath
outlineShape.fillColor = UIColor.clear.cgColor
outlineShape.strokeColor = UIColor.yellow.cgColor
outlineShape.lineWidth = 5
outlineShape.strokeEnd = 0
view.layer.addSublayer(outlineShape)
return outlineShape
}
func newQuestionAnimation() {
let outlineAnimation = CABasicAnimation(keyPath: "strokeEnd")
outlineAnimation.toValue = 1
outlineAnimation.duration = 5
newQuestionOutline().add(outlineAnimation, forKey: "key")
}
The animation performs as expected when running on the simulator for an iPhone 11 which is the device size that I used in the storyboard. However when running the project on a different device with different screen dimensions (like iPhone 8 plus) the shape is drawn out of place and not around the UILabel as it should be. I used autolayout to horizontally and vertically center the UILabel to the center of the view so the UILabel is centered no matter what device.
Any suggestions? Thanks in advance!
Cheers!
A shape layer is not a view, so it is not subject to auto layout. And any time you say something like roundedRect: questionLabel.frame you are making yourself dependent on what questionLabel.frame is at that moment, which is a huge mistake because that is exactly what is not determined until auto layout determines what the frame will be (and can change later if auto layout changes its mind due to changing conditions, such as rotation etc.)
There are two kinds of solution:
Host the shape layer in a view. Now you have something that is subject to autolayout. You will still need to redraw the shape layer whenever the view changes its frame, but you can detect that and perform the redraw.
Implement your view controller's viewDidLayoutSubviews to detect that auto layout has just done its work. Respond by (for example) removing the shape layer and making a new one based on the current conditions.

FlutterFragment is not retaining state

I am trying to embed a Flutter app inside my existing Android app using this steps:
https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps
I am embedding the FlutterFragment inside my Activity in onCreate method, but when I rotate the screen, the fragment does not retain it's state.
This is MainActivity code:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction().also {
it.replace(android.R.id.content, Flutter.createFragment(null), "flutter")
}.commit()
} else {
val flutterFragment = supportFragmentManager.findFragmentByTag("flutter")
supportFragmentManager.beginTransaction().also {
it.attach(flutterFragment!!)
}.commit()
}
}
}
You are probably not declaring your Activity properly. The configChanges are very important for Flutter to work with Android's lifecycle.
You have to declare it on the AndroidManifest like this:
<activity
android:launchMode="singleTop"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
android:name=".MainActivity"
android:theme="#style/AppTheme.NoActionBar"/>

Swift 3 - Most appropriate way to create a button with a scalable image above text

In Android I was able to accomplish this custom button by creating a LinearLayout with 2 children-an ImageView and a TextView, and just controlling the layout properties (and adding onClick, etc. to recreate button functionality). Using weights, I was able to have the image scale to fill the button while allowing the appropriate proportions for the text.
For Example:
<LinearLayout
android:id="#+id/my_button"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/button_background"
android:clickable="true"
android:focusable="true"
android:onClick="onClickFunction"
android:orientation="vertical" >
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="5"
android:layout_marginTop="-8dp"
android:src="#mipmap/icon_test" />
<TextView
android:id="#+id/my_button_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button Text"
android:textSize="14sp"
android:textAllCaps="true"
android:textStyle="bold"
android:textColor="#color/text_color"
android:textAlignment="center" />
</LinearLayout>
Produces:
What is the most appropriate way to do this in Swift 3? I've read about using insets to control the positioning (even setting negative "Left" insets on the image to position it above the text), but the image dimensions would have to be managed manually. I've also been made aware that setting the image as the background would have it scale, but I don't want to have the text overlap the image. My thought process is that there could be a "workaround" of sorts similar to my example above for Android, but I doubt the solution will be similar.
Furthermore, I'm pretty dependent on the IB (my app is not very complex so it's easily managed), so I'm using this for my button so far:
import UIKit
#IBDesignable
class RoundButton: UIButton {
#IBInspectable var cornerRadius: CGFloat = 0{
didSet{
self.layer.cornerRadius = cornerRadius
}
}
#IBInspectable var borderWidth: CGFloat = 0{
didSet{
self.layer.borderWidth = borderWidth
}
}
#IBInspectable var borderColor: UIColor = UIColor.clear{
didSet{
self.layer.borderColor = borderColor.cgColor
}
}
}
If it's not asking too much I'd like to be able to build off of this.
Here is the example how you can achieve that:
let btnSort = UIButton(type: .system)
btnSort.frame = CGRect(x: 2, y: 74, width: 140, height: 140)
btnSort.tintColor = UIColor.white
btnSort.setImage(UIImage(named:"lamp"), for: .normal)
btnSort.imageEdgeInsets = UIEdgeInsets(top: 6,left: 20,bottom: 30,right: 20)
btnSort.titleEdgeInsets = UIEdgeInsets(top: 100,left: -250,bottom: 0,right: 0)
btnSort.setTitle("BUTTON TEXT", for: .normal)
btnSort.layer.borderWidth = 1.0
btnSort.backgroundColor = UIColor.red
btnSort.layer.borderColor = UIColor.white.cgColor
self.view.addSubview(btnSort)
And result will be:
And here is the original post. I have changed EdgeInsets as per your requirement.

UIView transparent gradient

Given an arbitrary UIView on iOS, is there a way using Core Graphics (CAGradientLayer comes to mind) to apply a "foreground-transparent" gradient to it?
I can't use a standard CAGradientLayer because the background is more complex than a UIColor. I also can't overlay a PNG because the background will change as my subview is scrolled along its parent vertical scrollview (see image).
I have a non-elegant fallback: have my uiview clip its subviews and move a pre-rendered gradient png of the background as the parent scrollview is scrolled.
This was an embarrassingly easy fix: apply a CAGradientLayer as my subview's mask.
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = _fileTypeScrollView.bounds;
gradientLayer.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor, (id)[UIColor clearColor].CGColor, nil];
gradientLayer.startPoint = CGPointMake(0.8f, 1.0f);
gradientLayer.endPoint = CGPointMake(1.0f, 1.0f);
_fileTypeScrollView.layer.mask = gradientLayer;
Thanks to Cocoanetics for pointing me in the right direction!
This is how I'll do.
Step 1 Define a custom gradient view (Swift 4):
import UIKit
class GradientView: UIView {
override open class var layerClass: AnyClass {
return CAGradientLayer.classForCoder()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let gradientLayer = self.layer as! CAGradientLayer
gradientLayer.colors = [
UIColor.white.cgColor,
UIColor.init(white: 1, alpha: 0).cgColor
]
backgroundColor = UIColor.clear
}
}
Step 2 - Drag and drop a UIView in your storyboard and set its custom class to GradientView
As an example, this is how the above gradient view looks like:
https://github.com/yzhong52/GradientViewDemo
I used the accepted (OP's) answer above and ran into the same issue noted in an upvoted comment - when the view scrolls, everything that started offscreen is now transparent, covered by the mask.
The solution was to add the gradient layer as the superview's mask, not the scroll view's mask. In my case, I'm using a text view, which is contained inside a view called contentView.
I added a third color and used locations instead of startPoint and endPoint, so that items below the text view are still visible.
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.contentView!.bounds
gradientLayer.colors = [UIColor.white.cgColor, UIColor.clear.cgColor, UIColor.white.cgColor]
// choose position for gradient, aligned to bottom of text view
let bottomOffset = (self.textView!.frame.size.height + self.textView!.frame.origin.y + 5)/self.contentView!.bounds.size.height
let topOffset = bottomOffset - 0.1
let bottomCoordinate = NSNumber(value: Double(bottomOffset))
let topCoordinate = NSNumber(value: Double(topOffset))
gradientLayer.locations = [topCoordinate, bottomCoordinate, bottomCoordinate]
self.contentView!.layer.mask = gradientLayer
Before, the text that started offscreen was permanently invisible. With my modifications, scrolling works as expected, and the "Close" button is not covered by the mask.
I just ran into the same issue and wound up writing my own class. It seems like serious overkill, but it was the only way I could find to do gradients with transparency. You can see my writeup and code example here
It basically comes down to a custom UIView that creates two images. One is a solid color, the other is a gradient that is used as an image mask. From there I applied the resulting image to the uiview.layer.content.
I hope it helps,
Joe
I hate to say it, but I think that you are into the CUSTOM UIView land. I think that I would try to implement this in a custom UIView overiding the drawRect routine.
With this, you could have that view, place on top of your actual scrollview, and have your gradient view (if you will) "pass-on" all touch events (i.e. relinquish first responder).