In iOS I'm a big fan of deleting the storyboard and using the Cartography framework to lay everything out in code. This is stolen from Cartography's github:
constrain(view1, view2) { view1, view2 in
view1.width == (view1.superview!.width - 50) * 0.5
view2.width == view1.width - 50
view1.height == 40
view2.height == view1.height
view1.centerX == view1.superview!.centerX
view2.centerX == view1.centerX
view1.top >= view1.superview!.top + 20
view2.top == view1.bottom + 20
}
Is there any equivalent at all for Android? It seems like the new Constraint Layout is a step in the right direction but I would like to do it programmatically.
A little late to the game, but you need to basically treat your views in a constraint layout as regular views that simply have their own LayoutParams.
In the ConstraintLayout case, the documentation is located here: https://developer.android.com/reference/androidx/constraintlayout/widget/ConstraintLayout.LayoutParams
This class contains the different attributes specifying how a view want to be laid out inside a ConstraintLayout. For building up constraints at run time, using ConstraintSet is recommended.
So, the recommended method is to use a ConstraintSet.
There's a nice code sample there, but the core concept is you need to create a new set (by copying/cloning/new, etc), set its properties, and then apply it to your layout.
E.g.: Suppose your layout contains a ConstraintLayout (called mConstraintLayout here) and inside it contains a view (R.id.go_button in the sample), you could do:
ConstraintSet set = new ConstraintSet();
// You may want (optional) to start with the existing constraint,
// so uncomment this.
// set.clone(mConstraintLayout);
// Resize to 100dp
set.constrainHeight(R.id.go_button, (int)(100 * density));
set.constrainWidth(R.id.go_button, (int)(100 * density));
// center horizontally in the container
set.centerHorizontally(R.id.go_button, R.id.rootLayout);
// pin to the bottom of the container
set.connect(R.id.go_button, BOTTOM, R.id.rootLayout, BOTTOM, 8);
// Apply the changes
set.applyTo(mConstraintLayout);
// this is my… (ConstraintLayout) findViewById(R.id.rootLayout);
I ran into the exact same dilemma coming from iOS where I feel like building views programatically is a more common practice.
I am actually porting the Stevia library to android with Kotlin here, since the new ConstraintLayout is quite similar to our beloved Autolayout.
Here is how you define a simple view
class MyView(context: Context): ConstraintLayout(context) {
val label = TextView(context)
init {
// View Hierarchy
subviews(
label
)
// Layout
label.centerInParent()
// Style
label.style {
textSize = 12F
}
}}
Be aware that this is Pure native Constraint layout under the hood, as explained by Martin's answer.
It's only the beginning but it has proven to be a delightful way to write android views in Kotlin so far so I thought I'd share.
Hope this helps :)
Related
I need to stretch the cells on the field, like in chess. Everything worked out with the field itself, but not with the cells. To scale the interface, I used a ConstraintLayout. In it, I found GuideLines that will limit the space of the cell.
I didn't understand how to move the GuideLine and how to attach elements to it.
Here is the board and cells:
I haven't tried placing lines like this yet, because I haven't figured out how to move them.
Given the id of a guideline, you can move it with one of the following methods of ConstraintSet:
setGuidelineBegin()
setGuidelineEnd()
setGuidelinePercent()
To get the ConstraintSet used
ConstraintSet set = new ConstraintSet();
ConstraintLayout layout;
// Get the ConstraintLayout
layout = (ConstraintLayout) findViewById(R.id.layout);
// Get layout info for connections, etc.
set.clone(layout);
// Move guidlines here with one of the above methods working on set
// Apply changes back to the ConstraintLayout
set.applyTo(layout);
I am trying to share react native components between two screens, like what you can do with the hero library in ios. I want the component to animate between the two screens.
I have tried the fluid-transitions library, but I couldnt get it to work.
ie.
In order to do an animation like this you can use TransitionManager, i personally usually use it with constraintLayouts.
What you need in order to do this is 2 constraintLayouts (both need to have all the elements that will appear on screen and the properties that change between layouts should only be the constraints themselves.)
With the 2 layouts you can make an animation from one to the other like this:
final ConstraintSet constraint1 = new ConstraintSet();
constraint1.clone(getApplicationContext(), R.layout.layout_shrunk);
final ConstraintSet constraint2 = new ConstraintSet();
constraint2.clone(getApplicationContext(), R.layout.layout_expanded);
//The view you pass as an argument to both methods should be the layout's root.
TransitionManager.beginDelayedTransition((ConstraintLayout)findViewById(R.id.layout_root));
constraint2.applyTo((ConstraintLayout) findViewById(R.id.layout_root));
Result:
However this kind of animations are also possible to be made in other ways, please check the official docs for reference: https://developer.android.com/training/transitions
Note: to get the reverse animation too just apply the other constraintSet.
I want to create zig-zag layout same as following attached image:
I tried a lot by creating diagonal lines and arranging them with icon but couldn't make it same.
I implemented diagonal lines with the help of accepted answer from following questions:
Diagonal line across view
How rotate line in Android XML?
However I'm stuck to arrange lines with icons exactly same as in image.
I created this custom ZigZagLayout.java file to cater your requirement. You just have to update the package name in the 1st line.
It basically extends RelativeLayout, so you can use it in your layout-xmls just like any other ViewGroup class. Once you have instantiated this layout, just add child-views to it like it is done for RelativeLayout via addView(View child).
Example code snippet with dynamically created view:
ZigZagLayout zigZagLayout = (ZigZagLayout) findViewById(R.id.layout_zigzag);
Button btn = new Button(this);
btn.setText("Test Button");
btn.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
zigZagLayout.addView(btn);
I've also added few interfaces to this ZigZagLayout for your easy interaction like ability to set the connector-line stroke width, visibility, color, margins, etc.
Try it out and let me know if it suffices your requirement. Cheers.
If you have layout for each circular item , you may use relative layout to align them, using align_below, align_left with margin, align_right with margin tags.
Please provide further detail, what are the lines connecting them and exactly what all are requirements for UI and functionality.
How do I avoid this hardcoded math...
<resources>
<dimen name="uno">10dip</dimen>
<dimen name="dos">6dip</dimen>
<dimen name="uno_plus_dos">16dip</dimen>
</resources>
<Button
android:layout_marginTop="#dimen/uno_plus_dos" />
...and covert it to something like this?
<Button
android:layout_marginTop="#dimin/uno + #dimen/dos" />
You don't, sorry. Layout XML files do not support expressions. You either:
Leave it as #dimen/uno_plus_dos, or
Set your margins in Java code, where you can replace a single resource with a bunch of extra lines of code, or
Write your own layout preprocessor that handles expressions like this
UPDATE The data binding library supports some operations in its expressions. I am uncertain if it can handle this specific scenario.
One trick for simple addition is to use margin + padding.
Using databinding:
android:layout_marginTop="#{#dimen/uno + #dimen/dos}"
IFAIK margins adapters are not provided by the sdk. You will need to define it yourself:
#BindingAdapter("android:layout_marginTop")
public static void setBottomMargin(View view, int bottomMargin) {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin,
layoutParams.rightMargin, bottomMargin);
view.setLayoutParams(layoutParams);
}
Make sure databinding is enabled for your project :
dataBinding {
enabled = true
}
in your build.gradle.
The databinding doc is worth reading.
There's a few tricks around this, but it wouldn't be as nice as your proposed solution, which is something I want as well. For example, you can use layout paddings on not just the View (Button in this case), but you can also do it on the view's parent (the layout like LinearLayout/RelativeLayout). You can also put in invisibile Views (a straight View object works often) with fixed dimensions. It would be like
<View
android:layout_width="1px"
andoird:layout_height="#dimen/dos" />
Note that 1px is fine if want to guarantee only 1 pixel will be drawn for a dimension, which is usually what you want if you want use empty views for padding. Some say FrameLayout is better to use for empty padding, but that's descended from View
Sometimes you can combine padding and the layout padding, but that can get messy and have your view cropped. Also you can have something like a FrameLayout or a LinearLayout contain just that view, and use that to have the added padding
I would like to have a Layout for Views in Android that manages itself to use its empty space dynamically and EITHER puts the next view added right to the last view if it still fits OR breaks line and adds the view on the new line on the left...
Example:
||Name|LoooooongName|Ho ||
||SuperLongName|NextLongname ||
||Bob|Sue|Martin|Richard|Joe ||
||Marvin|Homer|Ann-Marie ||
Any clues? Thanks for your help!
This is possible, but not easy. You will have to create a custom layout. Check out the source code to LinearLayout for an example, specifically layoutHorizontal().
You will override ViewGroup.onLayout(). Inside it you will check the size of your children using View.getMeasured{Width,Height}(), making sure they can fit on the line or move to the next.