TextView does not resize after TextSize is changed - java

I have a ConstraintLayout with a TextView and EditText inside. The TextView is on the left, and when the EditText gains focus, I want the TextView to change its TextSize and move to the right. When it loses focus, I want to reverse that.
This is the Layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/custom_edit_text_constraint_layout"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<EditText
android:id="#+id/custom_edit_text_text_field"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:paddingLeft="#dimen/custom_edittext_def_hint_margin"
android:paddingStart="#dimen/custom_edittext_def_hint_margin"
tools:ignore="RtlSymmetry"
/>
<TextView
android:id="#+id/custom_edit_text_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginLeft="#dimen/custom_edittext_def_hint_margin"
android:layout_marginStart="#dimen/custom_edittext_def_hint_margin"/>
</androidx.constraintlayout.widget.ConstraintLayout>
And this is the code (If I forgot any important parts I can edit it):
hint = findViewById(R.id.custom_edit_text_hint); //TextView
textField = findViewById(R.id.custom_edit_text_text_field); //EditText
textField.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus) {
focusHint();
} else {
unfocusHint();
}
}
});
private void focusHint() {
hint.setTextSize(hintSizeFocused);
hint.setTextColor(hintColorFocused);
moveHintToRight();
}
private void unfocusHint() {
hint.setTextColor(hintColor);
if(textField.getText().toString().isEmpty()) {
hint.setTextSize(hintSize);
moveHintToLeft();
}
}
private void moveHintToRight() {
int horizontalDistance = textField.getWidth() - hint.getRight() - dpToPx(HINT_MARGIN_SIDE);
TranslateAnimation anim = new TranslateAnimation(0, horizontalDistance, 0, 0);
anim.setDuration(ANIMATION_DURATION);
anim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
ConstraintLayout l = findViewById(R.id.custom_edit_text_constraint_layout);
ConstraintSet set = new ConstraintSet();
set.clone(l);
set.clear(R.id.custom_edit_text_hint, ConstraintSet.LEFT);
set.connect(R.id.custom_edit_text_hint, ConstraintSet.RIGHT, R.id.custom_edit_text_constraint_layout, ConstraintSet.RIGHT, dpToPx(HINT_MARGIN_SIDE));
set.applyTo(l);
}
#Override
public void onAnimationRepeat(Animation animation) {}
});
hint.startAnimation(anim);
}
private void moveHintToLeft() {
int horizontalDistance = - hint.getLeft() + dpToPx(HINT_MARGIN_SIDE);
TranslateAnimation anim = new TranslateAnimation(0, horizontalDistance, 0, 0);
anim.setDuration(ANIMATION_DURATION);
anim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
ConstraintSet set = new ConstraintSet();
ConstraintLayout l = findViewById(R.id.custom_edit_text_constraint_layout);
set.clone(l);
set.clear(R.id.custom_edit_text_hint, ConstraintSet.RIGHT);
set.connect(R.id.custom_edit_text_hint, ConstraintSet.LEFT, R.id.custom_edit_text_constraint_layout, ConstraintSet.LEFT, dpToPx(HINT_MARGIN_SIDE));
set.applyTo(l);
}
#Override
public void onAnimationRepeat(Animation animation) {}
});
hint.startAnimation(anim);
}
This works great, but only when I don't resize the TextSize of the TextView. When I resize the TextSize (as shown in the code), hint.getLeft() and hint.getRight() return the values, which the TextView would have with the old TextSize, and this results in that the TextView moves either too far or not far enought. But this doesn't make sense to me because I resize the TextSize BEFORE I start the animation and the TextView's width is set to wrap_content. Does anyone have an idea why this doesn't work and how I can fix it?
EDIT:
To further explain and simplify what exactly the problem is, I have an example:
textView.setTextSize(12);
int width1 = hint.getWidth();
textView.setTextSize(18);
int width2 = hint.getWidth();
As the TextView's width is set to wrap_content, the width should change when I change the textSize (at least I thought so). But width1 and width2 are the same. How can I fix that?
EDIT2:
I solved the problem with
this answer by Eric.

Add right and end constraint of the textview as follows.If you want it to be in middle then set horizontal_bias = 0.5 or if you want it left then 0.0 and lastly in right 1.0
<TextView
android:id="#+id/custom_edit_text_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginLeft="#dimen/custom_edittext_def_hint_margin"
android:layout_marginStart="#dimen/custom_edittext_def_hint_margin"
android:layout_constraintRight_toRightOf = "parent"
android:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintHorizontal_bias="0.0"
/>
Hope this will work.Try it

Related

How to Overcome Aliasing Problem Caused By ConstraintLayout Guidelines?

I am trying to reconcile the following two things:
A) I want a precise, uniform, and clean UI with several identically sized buttons that correspond exactly to the underlying 'grid cells' -- A UI that will look as similar as possible (proportionally to screen size) across as many Android devices as possible.
B) On Android, the screen dimensions (aspect ratio and actual pixel numbers) of the user's device are unknown (to the app) until runtime.
My solution to this was to: (there is a code example below!)
1) Lock the app to portrait mode,
2) Do not define anything in static/absolute terms like dp,px, etc. and instead conceptualize a 'basic unit of measure' that is a function of screen height -- 0.08% in my case -- and base everything off of that.
3) Set horizontal guidelines within a ConstraintLayout whose positions are expressed as a percentage of parent (screen) height.
4) Make all buttons use this 'basic unit' as their height and width by setting their XML layout_constraintDimensionRatio attribute to "1:1" and using the guidelines above (see step 3),
5) Accomplish positioning and dimensions of all views by using constraints to either these guidelines, the parent's bounds, or one additional vertical guideline at 50% of screen width.
The problem is that depending on the pixel height of the screen (whether it happens to be odd or even... or maybe other factors), the dimensions of a view/button, (and thus the paths drawn inside it) constrained between one pair of guidelines does not exactly match those of another view drawn between some other pair... even though the distance between both pairs of guidelines should be the same percentage of parent height. :)
Here is an example showing the Nexus 4 emulator:
At first I thought the problem was simply due to rounding 'error' during Android's dimension calculations, but then why would the view not be square even though they are prescribed the 1:1 ratio attribute?
The only solutions I can think of would be:
A) To do the layout programatically instead of with XML... and set the guideline positions as exact pixel locations instead of percentages, and answer the question, "what is 0.08 x screen height?" myself... making the appropriate corrections to compensate for 'indivisible' screen heights.
B) Override onLayout() in the custom views and "force" their dimensions to be consistent... but then this would defeat the purpose of guidelines. :(
But I'm really hoping there is an easier solution than A or B.
(I know someone is going to suggest GridLayout, but it's not an option, for a few reasons... one of which is that in GridLayout, views inside cells must be set to wrap_content... which means the paths they draw cannot be generated relative to parent at runtime).
Thanks for any other suggestions, though.
Code Example:
I whipped up a simple 'minimal example' below that should be easy to reconstruct in Android Studio. The logs will reveal the issue if it's not immediately apparent.
XML layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.constraint.Guideline
android:id="#+id/guidelineHorizontalTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.08" />
<android.support.constraint.Guideline
android:id="#+id/guidelineHorizontalBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.92" />
<android.support.constraint.Guideline
android:id="#+id/guidelineHorizontalCenter1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.38" />
<android.support.constraint.Guideline
android:id="#+id/guidelineHorizontalCenter2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.46" />
<android.support.constraint.Guideline
android:id="#+id/guidelineHorizontalCenter3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.54" />
<android.support.constraint.Guideline
android:id="#+id/guidelineHorizontalCenter4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.62" />
<com.example.boober.stack_aliasingproblem.CustomButton
android:id="#+id/buttonTopLeft"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonTopLeft"
app:layout_constraintBottom_toTopOf="#+id/guidelineHorizontalTop"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.example.boober.stack_aliasingproblem.CustomButton
android:id="#+id/buttonTopRight"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonTopRight"
app:layout_constraintBottom_toTopOf="#+id/guidelineHorizontalTop"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.example.boober.stack_aliasingproblem.CustomButton
android:id="#+id/buttonBottomLeft"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonBottomLeft"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/guidelineHorizontalBottom" />
<com.example.boober.stack_aliasingproblem.CustomButton
android:id="#+id/buttonBottomRight"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonBottomRight"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/guidelineHorizontalBottom" />
<com.example.boober.stack_aliasingproblem.CustomButton
android:id="#+id/buttonMiddle"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonMiddle"
app:layout_constraintBottom_toBottomOf="#id/guidelineHorizontalCenter3"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#id/guidelineHorizontalCenter2" />
<com.example.boober.stack_aliasingproblem.CustomButton
android:id="#+id/buttonMiddleTopLeft"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonMiddleTopLeft"
app:layout_constraintBottom_toBottomOf="#id/guidelineHorizontalCenter2"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="#id/buttonMiddle"
app:layout_constraintTop_toTopOf="#id/guidelineHorizontalCenter1" />
<com.example.boober.stack_aliasingproblem.CustomButton
android:id="#+id/buttonMiddleTopRight"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonMiddleTopRight"
app:layout_constraintBottom_toBottomOf="#id/guidelineHorizontalCenter2"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toEndOf="#id/buttonMiddle"
app:layout_constraintTop_toTopOf="#id/guidelineHorizontalCenter1" />
</android.support.constraint.ConstraintLayout>
MainActivity.java:
public class MainActivity extends AppCompatActivity {
CustomButton buttonTopLeft;
CustomButton buttonTopRight;
CustomButton buttonMiddle;
CustomButton buttonMiddleTopLeft;
CustomButton getButtonMiddleTopRight;
CustomButton buttonBottomLeft;
CustomButton buttonBottomRight;
CustomButton[] arrayOfCustomButtons;
ConstraintLayout rootView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonTopLeft = findViewById(R.id.buttonTopLeft);
buttonTopRight = findViewById(R.id.buttonTopRight);
buttonBottomLeft = findViewById(R.id.buttonBottomLeft);
buttonBottomRight = findViewById(R.id.buttonBottomRight);
buttonMiddle = findViewById(R.id.buttonMiddle);
buttonMiddleTopLeft = findViewById(R.id.buttonMiddleTopLeft);
getButtonMiddleTopRight = findViewById(R.id.buttonMiddleTopRight);
arrayOfCustomButtons = new CustomButton[]{buttonTopLeft, buttonTopRight, buttonBottomLeft,
buttonBottomRight, buttonMiddle, buttonMiddleTopLeft, getButtonMiddleTopRight};
rootView = findViewById(R.id.rootView);
for (final CustomButton cb : arrayOfCustomButtons) {
cb.setClickable(true);
cb.post(new Runnable() {
#Override
public void run() {
Log.i("XXX", "width of: " + cb.getTag() + " is: "
+ cb.getMeasuredWidth());
}
});
}
rootView.post(new Runnable() {
#Override
public void run() {
Log.i("XXX", "height of rootView is: " + rootView.getMeasuredHeight());
}
});
}
}
CustomButton.java:
public class CustomButton extends View {
Path myOutlinePath;
Paint myThinPaintBrush;
Paint myThickPaintBrush;
boolean isHighlighted = false;
public CustomButton(Context context) {
super(context);
init();
}
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
float measuredWidth = getMeasuredWidth();
Log.i("XXX", "measured WIDTH Of " + this.getTag() + " is: " + measuredWidth);
Log.i("XXX", "measured HEIGT Of " + this.getTag() + " is: " + getMeasuredHeight());
Log.i("XXX", "\n ");
generateMyOutline(measuredWidth);
myThinPaintBrush.setStrokeWidth(measuredWidth/12);
myThickPaintBrush.setStrokeWidth(measuredWidth/6);
}
private void generateMyOutline(float W) {
Path path = new Path();
path.moveTo(0,0);
path.lineTo(W, 0);
path.lineTo(W, W);
path.lineTo(0, W);
path.lineTo(0,0);
myOutlinePath = path;
}
private void init() {
myOutlinePath = new Path();
myThinPaintBrush = new Paint();
myThinPaintBrush.setAntiAlias(false); // setting this to true does not solve the problem.
myThinPaintBrush.setStyle(Paint.Style.STROKE);
myThinPaintBrush.setStrokeCap(Paint.Cap.ROUND);
myThickPaintBrush = new Paint();
myThickPaintBrush.setAntiAlias(false);
myThickPaintBrush.setStyle(Paint.Style.STROKE);
myThickPaintBrush.setStrokeCap(Paint.Cap.ROUND);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (this.isClickable()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isHighlighted = true;
invalidate();
break;
case MotionEvent.ACTION_UP:
isHighlighted = false;
invalidate();
break;
case MotionEvent.ACTION_CANCEL:
isHighlighted = false;
invalidate();
break;
}
}
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(myOutlinePath, myThinPaintBrush);
if (isHighlighted) {
canvas.drawPath(myOutlinePath, myThickPaintBrush);
}
super.onDraw(canvas);
}
}
I would go for the middle ground: Use your XML layout as is and make adjustments programmatically to the guideline positions. The following code converts percentage guidelines to fixed position guidelines by computing a new layout height that is a multiple of 8% of the height of the initial layout.
All sizes are computed correctly except for the bottom squares that tend to be larger. This can be easily corrected based upon your actual requirements (more important to be at the bottom or a certain distance from the other squares, for instance.)
MainActivity.jav
public class MainActivity extends AppCompatActivity {
CustomButton buttonTopLeft;
CustomButton buttonTopRight;
CustomButton buttonMiddle;
CustomButton buttonMiddleTopLeft;
CustomButton getButtonMiddleTopRight;
CustomButton buttonBottomLeft;
CustomButton buttonBottomRight;
CustomButton[] arrayOfCustomButtons;
ConstraintLayout rootView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonTopLeft = findViewById(R.id.buttonTopLeft);
buttonTopRight = findViewById(R.id.buttonTopRight);
buttonBottomLeft = findViewById(R.id.buttonBottomLeft);
buttonBottomRight = findViewById(R.id.buttonBottomRight);
buttonMiddle = findViewById(R.id.buttonMiddle);
buttonMiddleTopLeft = findViewById(R.id.buttonMiddleTopLeft);
getButtonMiddleTopRight = findViewById(R.id.buttonMiddleTopRight);
rootView = findViewById(R.id.rootView);
rootView.post(new Runnable() {
#Override
public void run() {
int rootViewHeight = rootView.getMeasuredHeight();
Log.i("XXX", "height of rootView is: " + rootViewHeight);
int segHeight = (int) (rootViewHeight * 0.08f);
adjustGuideline(R.id.guidelineHorizontalTop, segHeight);
adjustGuideline(R.id.guidelineHorizontalCenter1, segHeight);
adjustGuideline(R.id.guidelineHorizontalCenter2, segHeight);
adjustGuideline(R.id.guidelineHorizontalCenter3, segHeight);
adjustGuideline(R.id.guidelineHorizontalCenter4, segHeight);
adjustGuideline(R.id.guidelineHorizontalBottom, segHeight);
arrayOfCustomButtons = new CustomButton[]{buttonTopLeft, buttonTopRight, buttonBottomLeft,
buttonBottomRight, buttonMiddle, buttonMiddleTopLeft, getButtonMiddleTopRight};
rootView = findViewById(R.id.rootView);
for (final CustomButton cb : arrayOfCustomButtons) {
cb.setClickable(true);
cb.post(new Runnable() {
#Override
public void run() {
Log.i("MainActivity", "<<<< width of: " + cb.getTag() + " is: "
+ cb.getMeasuredWidth());
}
});
}
}
});
}
private void adjustGuideline(int guideLineId, int segHeight) {
Guideline gl = (Guideline) findViewById(guideLineId);
ConstraintLayout.LayoutParams lp = ((ConstraintLayout.LayoutParams) gl.getLayoutParams());
gl.setGuidelineBegin((int) (segHeight * lp.guidePercent / 0.08f));
gl.setGuidelinePercent(-1f);
}
}

Expand and collapse Relativelayout by button click

I have this RelativeLayout which expand and collapse on button click
it works fine on one button.
I want to reuse same method on more two RelativeLayout
in same layout
and expand using other two buttons.
This code is running fine. just want more layout to do same action.
Layout:
This is my code:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="64dp"
android:background="#FFF"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title"
android:textSize="20sp" />
<Button
android:id="#+id/viewmore"
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_marginLeft="280dp"
android:background="#null"
android:text="viewmore" />
</RelativeLayout>
<RelativeLayout
android:visibility="gone"
android:id="#+id/expandable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:background="#color/colorAccent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="133dp"
android:text="Text messaging, or texting, is the act of composing and sending electronic messages, typically consisting of alphabetic and numeric characters"
android:textSize="20sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title 2"
android:textSize="20sp" />
<Button
android:id="#+id/viewmore1"
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_marginLeft="280dp"
android:background="#null"
android:text="viewmore" />
</RelativeLayout>
<RelativeLayout
android:visibility="gone"
android:animateLayoutChanges="true"
android:id="#+id/expandable1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="30dp"
android:background="#color/colorPrimary">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Text messaging, or texting, is the act of composing and sending electronic messages, typically consisting of alphabetic and numeric characters"
android:textSize="20sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title 3"
android:textSize="20sp" />
<Button
android:id="#+id/viewmore2"
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_marginLeft="280dp"
android:background="#null"
android:text="viewmore" />
</RelativeLayout>
<RelativeLayout
android:visibility="gone"
android:animateLayoutChanges="true"
android:id="#+id/expandable2"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="30dp"
android:background="#color/colorPrimary">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Text messaging, or texting, is the act of composing and sending electronic messages, typically consisting of alphabetic and numeric characters"
android:textSize="20sp" />
</RelativeLayout>
</LinearLayout>
</ScrollView>
Source Code:
RelativeLayout relativeLayout, relativeLayout1, relativeLayout2;
Button viewmore, viewmore1, viewmore2;
ValueAnimator mAnimator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewmore);
relativeLayout = (RelativeLayout) findViewById(R.id.expandable);
relativeLayout1 = (RelativeLayout) findViewById(R.id.expandable1);
relativeLayout2 = (RelativeLayout) findViewById(R.id.expandable2);
viewmore = (Button) findViewById(R.id.viewmore);
viewmore1 = (Button) findViewById(R.id.viewmore1);
viewmore2 = (Button) findViewById(R.id.viewmore2);
viewmore.setOnClickListener(this);
viewmore1.setOnClickListener(this);
viewmore2.setOnClickListener(this);
relativeLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
relativeLayout.getViewTreeObserver().removeOnPreDrawListener(this);
relativeLayout.setVisibility(View.GONE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
relativeLayout.measure(widthSpec, heightSpec);
mAnimator = slideAnimator(0, relativeLayout.getMeasuredHeight());
return true;
}
});
}
private void expand() {
relativeLayout.setVisibility(View.VISIBLE);
mAnimator.start();
}
private void collapse() {
int finalHeight = relativeLayout.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animator) {
//Height=0, but it set visibility to GONE
relativeLayout.setVisibility(View.GONE);
}
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
mAnimator.start();
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//Update Height
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = relativeLayout.getLayoutParams();
layoutParams.height = value;
relativeLayout.setLayoutParams(layoutParams);
}
});
return animator;
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.viewmore:
if (relativeLayout.getVisibility() == View.GONE) {
expand();
} else {
collapse();
}
break;
case R.id.viewmore1:
break;
case R.id.viewmore2:
break;
}
}
To continue with your approach, you will have to make the code apply to all three sections that you have laid out. To do this, you will need to change several of your methods to accept a RelativeLayout as an argument.
First, in your onClick listener, fill in the case blocks so each block calls expand() with the targeted RelativeLayout and maximum height. Call collapse() with the targeted RelativeLayout. You will then need to modify expand() and collapse() to handle the new arguments:
You will notice in the following code that I have changed how and where the animator is created. The animator will need to work with each RelativeLayout.
So, onClick() calls expand() which calls slideAnimator(). For each call, the RelativeLayout that is effected is passed as an argument. In this way, you can generalize the code to work with more than one RelativeLayout.
The pre-draw listener will also need to measure each expandable RelativeLayout.
Here is it all put together:
MainActivity.xml
public class MainActivity extends AppCompatActivity
implements View.OnClickListener {
RelativeLayout relativeLayout, relativeLayout1, relativeLayout2;
Button viewmore, viewmore1, viewmore2;
int height, height1, height2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewmore);
relativeLayout = (RelativeLayout) findViewById(R.id.expandable);
relativeLayout1 = (RelativeLayout) findViewById(R.id.expandable1);
relativeLayout2 = (RelativeLayout) findViewById(R.id.expandable2);
viewmore = (Button) findViewById(R.id.viewmore);
viewmore1 = (Button) findViewById(R.id.viewmore1);
viewmore2 = (Button) findViewById(R.id.viewmore2);
viewmore.setOnClickListener(this);
viewmore1.setOnClickListener(this);
viewmore2.setOnClickListener(this);
relativeLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
relativeLayout.getViewTreeObserver().removeOnPreDrawListener(this);
relativeLayout.setVisibility(View.GONE);
relativeLayout1.setVisibility(View.GONE);
relativeLayout2.setVisibility(View.GONE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
relativeLayout.measure(widthSpec, heightSpec);
height = relativeLayout.getMeasuredHeight();
relativeLayout1.measure(widthSpec, heightSpec);
height1 = relativeLayout.getMeasuredHeight();
relativeLayout2.measure(widthSpec, heightSpec);
height2 = relativeLayout.getMeasuredHeight();
return true;
}
});
}
private void expand(RelativeLayout layout, int layoutHeight) {
layout.setVisibility(View.VISIBLE);
ValueAnimator animator = slideAnimator(layout, 0, layoutHeight);
animator.start();
}
private void collapse(final RelativeLayout layout) {
int finalHeight = layout.getHeight();
ValueAnimator mAnimator = slideAnimator(layout, finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animator) {
//Height=0, but it set visibility to GONE
layout.setVisibility(View.GONE);
}
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
mAnimator.start();
}
private ValueAnimator slideAnimator(final RelativeLayout layout, int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//Update Height
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = layout.getLayoutParams();
layoutParams.height = value;
layout.setLayoutParams(layoutParams);
}
});
return animator;
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.viewmore:
if (relativeLayout.getVisibility() == View.GONE) {
expand(relativeLayout, height);
} else {
collapse(relativeLayout);
}
break;
case R.id.viewmore1:
if (relativeLayout1.getVisibility() == View.GONE) {
expand(relativeLayout1, height1);
} else {
collapse(relativeLayout1);
}
break;
case R.id.viewmore2:
if (relativeLayout2.getVisibility() == View.GONE) {
expand(relativeLayout2, height2);
} else {
collapse(relativeLayout2);
}
break;
}
}
}
You can also create own custom expandable which extend android relative layout. On that custom view you can store expanded or collapsed status. As well as you can create custom attributes for define your view default status like expanded or collapsed. So you don't need to compare view status you will just call your toggle function which toggle your view expanded to collapse or vice versa
If you want to show collapsed view as a default view you should not change view visibility before onMeasure function and store your view measured height. If you change visibility on view constructor onMeasure function skip calculation for that view. You should toggle visibility on onPreDraw function.

Can't get .getwidth() and .getheight() to work

I know there have been a lot of other questions on this topic, but I've looked through all of them, and still not gotten it to work.
I've made this code for testing:
public class MainActivity extends Activity {
RelativeLayout layout;
TextView widthtext;
TextView heighttext;
int width;
int height;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = (RelativeLayout) findViewById(R.id.rela);
widthtext = (TextView) findViewById(R.id.textView);
heighttext = (TextView) findViewById(R.id.textView2);
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
width = layout.getWidth();
height = layout.getHeight();
}
});
widthtext.setText(width);
heighttext.setText(height);
}
and
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:id="#+id/rela">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="123"
android:id="#+id/textView"
android:layout_alignTop="#+id/textView2"
android:layout_toLeftOf="#+id/textView2"
android:layout_toStartOf="#+id/textView2"
android:layout_marginRight="50dp"
android:layout_marginEnd="50dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="123"
android:id="#+id/textView2"
android:layout_marginRight="50dp"
android:layout_marginEnd="50dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
After a lot of hassle I've now notised that the width and height int's have the right values, though I can't make them display in my TextViews, getting the NullPointerExeption.
Anyone who can make this work?
EXTRA:
public class MainActivity extends Activity {
RelativeLayout layout;
TextView widthtext;
TextView heighttext;
int width;
int height;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = (RelativeLayout) findViewById(R.id.rela);
widthtext = (TextView) findViewById(R.id.textView);
heighttext = (TextView) findViewById(R.id.textView2);
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
width = layout.getWidth();
height = layout.getHeight();
}
});
widthtext.setText(width + "");
heighttext.setText(height + "");
}
}
You are doing this
widthtext.setText(width);
heighttext.setText(height);
outside of your listener so naturally it doesn't have the values yet.
Move them inside
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
width = layout.getWidth();
height = layout.getHeight();
// move here
widthtext.setText(width);
heighttext.setText(height);
}
});
}
As blackbelt pointed out in a comment, you are calling setText() and passing an int. This will look for a resource id of that value. Change those to Strings.
widthtext.setText("" + width);
heighttext.setText("" + height);
setText takes string value
so instead of
setText(width);
setText(height);
do
setText(width+"");
setText(height+"");

Android adding simple animations while setvisibility(view.Gone)

I have designed a simple layout.I have finished the design without animation, but now I want to add animations when textview click event and I don't know how to use it.
Did my xml design looks good or not?
Any suggestions would be appreciated.
My XML
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:longClickable="false"
android:orientation="vertical"
android:weightSum="16" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:background="#00DDA0"
android:layout_weight="3" >
</LinearLayout>
<TextView
android:id="#+id/Information1"
android:layout_width="match_parent"
android:layout_height="1dp"
android:text="Child Information"
android:background="#0390BE"
android:layout_weight="0.75"
android:textColor="#FFFFFF"
android:layout_gravity="center|fill_horizontal"/>
<LinearLayout
android:id="#+id/layout1"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="8.5"
android:background="#BBBBBB"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="TextView" />
</LinearLayout>
<TextView
android:id="#+id/Information2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Parent Information"
android:background="#0390BE"
android:layout_weight="0.75"
android:textColor="#FFFFFF"
android:layout_gravity="center|fill_horizontal"/>
<LinearLayout
android:id="#+id/layout2"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:background="#BBBBBB"
android:layout_weight="8.5" >
<TextView
android:id="#+id/textView2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="TextView" />
</LinearLayout>
<TextView
android:id="#+id/Information3"
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Siblings"
android:background="#0390BE"
android:layout_weight="0.75"
android:textColor="#FFFFFF"
android:layout_gravity="center|fill_horizontal"/>
<LinearLayout
android:id="#+id/layout3"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:background="#BBBBBB"
android:layout_weight="8.5" >
<TextView
android:id="#+id/textView3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="TextView" />
</LinearLayout>
<TextView
android:id="#+id/Information4"
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Teacher Information"
android:background="#0390BE"
android:layout_weight="0.75"
android:textColor="#FFFFFF"
android:layout_gravity="center|fill_horizontal"/>
<LinearLayout
android:id="#+id/layout4"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:background="#BBBBBB"
android:layout_weight="8.5" >
<TextView
android:id="#+id/textView4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="TextView" />
</LinearLayout>
<TextView
android:id="#+id/Information5"
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Grade Information"
android:background="#0390BE"
android:layout_weight="0.75"
android:textColor="#FFFFFF"
android:layout_gravity="center|fill_horizontal"/>
<LinearLayout
android:id="#+id/layout5"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:background="#BBBBBB"
android:layout_weight="8.5" >
<TextView
android:id="#+id/textView5"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="TextView" />
</LinearLayout>
<TextView
android:id="#+id/Information6"
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Health Information"
android:background="#0390BE"
android:layout_weight="0.75"
android:textColor="#FFFFFF"
android:layout_gravity="center|fill_horizontal"/>
<LinearLayout
android:id="#+id/layout6"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:background="#BBBBBB"
android:layout_weight="8.5" >
<TextView
android:id="#+id/textView5"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="TextView"
android:layout_weight="8.5" />
</LinearLayout>
</LinearLayout>
My java
public class Certify_Info extends Activity {
private static TextView tv2,tv3,tv5,tv6,tv4,tv1;
private static LinearLayout l1,l2,l3,l4,l5,l6;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_certify__info);
tv1=(TextView) findViewById(R.id.Information1);
tv2=(TextView) findViewById(R.id.Information2);
tv3=(TextView) findViewById(R.id.Information3);
tv4=(TextView) findViewById(R.id.Information4);
tv5=(TextView) findViewById(R.id.Information5);
tv6=(TextView) findViewById(R.id.Information6);
l1=(LinearLayout) findViewById(R.id.layout1);
l2=(LinearLayout) findViewById(R.id.layout2);
l3=(LinearLayout) findViewById(R.id.layout3);
l4=(LinearLayout) findViewById(R.id.layout4);
l5=(LinearLayout) findViewById(R.id.layout5);
l6=(LinearLayout) findViewById(R.id.layout6);
l2.setVisibility(View.GONE);
l3.setVisibility(View.GONE);
l4.setVisibility(View.GONE);
l5.setVisibility(View.GONE);
l6.setVisibility(View.GONE);
tv1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
l2.setVisibility(View.GONE);
l3.setVisibility(View.GONE);
l4.setVisibility(View.GONE);
l5.setVisibility(View.GONE);
l6.setVisibility(View.GONE);
l1.setVisibility(View.VISIBLE);
}
});
tv2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
l1.setVisibility(View.GONE);
l3.setVisibility(View.GONE);
l4.setVisibility(View.GONE);
l5.setVisibility(View.GONE);
l6.setVisibility(View.GONE);
l2.setVisibility(View.VISIBLE);
}
});
tv3.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
l1.setVisibility(View.GONE);
l2.setVisibility(View.GONE);
l4.setVisibility(View.GONE);
l5.setVisibility(View.GONE);
l6.setVisibility(View.GONE);
l3.setVisibility(View.VISIBLE);
}
});
tv4.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
l1.setVisibility(View.GONE);
l2.setVisibility(View.GONE);
l3.setVisibility(View.GONE);
l4.setVisibility(View.GONE);
l5.setVisibility(View.GONE);
l6.setVisibility(View.GONE);
l4.setVisibility(View.VISIBLE);
}
});
tv5.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
l1.setVisibility(View.GONE);
l2.setVisibility(View.GONE);
l3.setVisibility(View.GONE);
l4.setVisibility(View.GONE);
l6.setVisibility(View.GONE);
l5.setVisibility(View.VISIBLE);
}
});
tv6.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
l1.setVisibility(View.GONE);
l2.setVisibility(View.GONE);
l3.setVisibility(View.GONE);
l4.setVisibility(View.GONE);
l5.setVisibility(View.GONE);
l6.setVisibility(View.VISIBLE);
}
});
}
}
You can do two things to add animations, first you can let android animate layout changes for you. That way every time you change something in the layout like changing view visibility or view positions android will automatically create fade/transition animations. To use that set
android:animateLayoutChanges="true"
on the root node in your layout.
Your second option would be to manually add animations. For this I suggest you use the new animation API introduced in Android 3.0 (Honeycomb). I can give you a few examples:
This fades out a View:
view.animate().alpha(0.0f);
This fades it back in:
view.animate().alpha(1.0f);
This moves a View down by its height:
view.animate().translationY(view.getHeight());
This returns the View to its starting position after it has been moved somewhere else:
view.animate().translationY(0);
You can also use setDuration() to set the duration of the animation. For example this fades out a View over a period of 2 seconds:
view.animate().alpha(0.0f).setDuration(2000);
And you can combine as many animations as you like, for example this fades out a View and moves it down at the same time over a period of 0.3 seconds:
view.animate()
.translationY(view.getHeight())
.alpha(0.0f)
.setDuration(300);
And you can also assign a listener to the animation and react to all kinds of events. Like when the animation starts, when it ends or repeats etc. By using the abstract class AnimatorListenerAdapter you don't have to implement all callbacks of AnimatorListener at once but only those you need. This makes the code more readable. For example the following code fades out a View moves it down by its height over a period of 0.3 seconds (300 milliseconds) and when the animation is done its visibility is set to View.GONE.
view.animate()
.translationY(view.getHeight())
.alpha(0.0f)
.setDuration(300)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
view.setVisibility(View.GONE);
}
});
The easiest way to animate Visibility changes is use Transition API which available in support (androidx) package. Just call TransitionManager.beginDelayedTransition method then change visibility of the view. There are several default transitions like Fade, Slide.
import androidx.transition.TransitionManager;
import androidx.transition.Transition;
import androidx.transition.Fade;
private void toggle() {
Transition transition = new Fade();
transition.setDuration(600);
transition.addTarget(R.id.image);
TransitionManager.beginDelayedTransition(parent, transition);
image.setVisibility(show ? View.VISIBLE : View.GONE);
}
Where parent is parent ViewGroup of animated view. Result:
Here is result with Slide transition:
import androidx.transition.Slide;
Transition transition = new Slide(Gravity.BOTTOM);
It is easy to write custom transition if you need something different. Here is example with CircularRevealTransition which I wrote in another answer. It shows and hide view with CircularReveal animation.
Transition transition = new CircularRevealTransition();
android:animateLayoutChanges="true" option does same thing, it just uses AutoTransition as transition.
Try adding this line to the xml parent layout
android:animateLayoutChanges="true"
Your layout will look like this
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:longClickable="false"
android:orientation="vertical"
android:weightSum="16">
.......other code here
</LinearLayout>
Please check this link. Which will allow animations like L2R, R2L, T2B, B2T animations.
This code shows animation from left to right
TranslateAnimation animate = new TranslateAnimation(0,view.getWidth(),0,0);
animate.setDuration(500);
animate.setFillAfter(true);
view.startAnimation(animate);
view.setVisibility(View.GONE);
if you want to do it from R2L then use
TranslateAnimation animate = new TranslateAnimation(0,-view.getWidth(),0,0);
for top to bottom as
TranslateAnimation animate = new TranslateAnimation(0,0,0,view.getHeight());
and vice a versa..
Base on #ashakirov answer, here is my extension to show/hide view with fade animation
fun View.fadeVisibility(visibility: Int, duration: Long = 400) {
val transition: Transition = Fade()
transition.duration = duration
transition.addTarget(this)
TransitionManager.beginDelayedTransition(this.parent as ViewGroup, transition)
this.visibility = visibility
}
Example using
view.fadeVisibility(View.VISIBLE)
view.fadeVisibility(View.GONE, 2000)
I was able to show/hide a menu this way:
MenuView.java (extends FrameLayout)
private final int ANIMATION_DURATION = 500;
public void showMenu()
{
setVisibility(View.VISIBLE);
animate()
.alpha(1f)
.setDuration(ANIMATION_DURATION)
.setListener(null);
}
private void hideMenu()
{
animate()
.alpha(0f)
.setDuration(ANIMATION_DURATION)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
setVisibility(View.GONE);
}
});
}
Source
Based on the answer of #Xaver Kapeller I figured out a way to create scroll animation when new views appear on the screen (and also animation to hide them).
It goes from this state:
Button
Last Button
to
Button
Button 1
Button 2
Button 3
Button 4
Last Button
and viceversa.
So, when the user clicks on the first button, the elements "Button 1", "Button 2", "Button 3" and "Button 4" will appear using fade animation and the element "Last Button" will move down till end. The height of the layout will change as well, allowing using scroll view properly.
This is the code to show elements with animation:
private void showElements() {
// Precondition
if (areElementsVisible()) {
Log.w(TAG, "The view is already visible. Nothing to do here");
return;
}
// Animate the hidden linear layout as visible and set
// the alpha as 0.0. Otherwise the animation won't be shown
mHiddenLinearLayout.setVisibility(View.VISIBLE);
mHiddenLinearLayout.setAlpha(0.0f);
mHiddenLinearLayout
.animate()
.setDuration(ANIMATION_TRANSITION_TIME)
.alpha(1.0f)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
updateShowElementsButton();
mHiddenLinearLayout.animate().setListener(null);
}
})
;
mLastButton
.animate()
.setDuration(ANIMATION_TRANSITION_TIME)
.translationY(mHiddenLinearLayoutHeight);
// Update the high of all the elements relativeLayout
LayoutParams layoutParams = mAllElementsRelativeLayout.getLayoutParams();
// TODO: Add vertical margins
layoutParams.height = mLastButton.getHeight() + mHiddenLinearLayoutHeight;
}
and this is the code to hide elements of the animation:
private void hideElements() {
// Precondition
if (!areElementsVisible()) {
Log.w(TAG, "The view is already non-visible. Nothing to do here");
return;
}
// Animate the hidden linear layout as visible and set
mHiddenLinearLayout
.animate()
.setDuration(ANIMATION_TRANSITION_TIME)
.alpha(0.0f)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
Log.v(TAG, "Animation ended. Set the view as gone");
super.onAnimationEnd(animation);
mHiddenLinearLayout.setVisibility(View.GONE);
// Hack: Remove the listener. So it won't be executed when
// any other animation on this view is executed
mHiddenLinearLayout.animate().setListener(null);
updateShowElementsButton();
}
})
;
mLastButton
.animate()
.setDuration(ANIMATION_TRANSITION_TIME)
.translationY(0);
// Update the high of all the elements relativeLayout
LayoutParams layoutParams = mAllElementsRelativeLayout.getLayoutParams();
// TODO: Add vertical margins
layoutParams.height = mLastButton.getHeight();
}
Note there is a simple hack on the method to hide the animation. On the animation listener mHiddenLinearLayout, I had to remove the listener itself by using:
mHiddenLinearLayout.animate().setListener(null);
This is because once an animation listener is attached to an view, the next time when any animation is executed in this view, the listener will be executed as well. This might be a bug in the animation listener.
The source code of the project is on GitHub:
https://github.com/jiahaoliuliu/ViewsAnimated
Happy coding!
Update: For any listener attached to the views, it should be removed after the animation ends. This is done by using
view.animate().setListener(null);
My solution extension
fun View.slideVisibility(visibility: Boolean, durationTime: Long = 300) {
val transition = Slide(Gravity.BOTTOM)
transition.apply {
duration = durationTime
addTarget(this#slideVisibility)
}
TransitionManager.beginDelayedTransition(this.parent as ViewGroup, transition)
this.isVisible = visibility
}
Use:
textView.slideVisibility(true)
Find the below code to make visible the view in Circuler reveal, if you send true, it'll get Invisible/Gone. If you send false, it'll get visible. anyView is the view you're going to visible/hide, it could be any view (Layouts, Buttons etc)
private fun toggle(flag: Boolean, anyView: View) {
if (flag) {
val cx = anyView.width / 2
val cy = anyView.height / 2
val initialRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat()
val anim = ViewAnimationUtils.createCircularReveal(anyView, cx, cy, initialRadius, 0f)
anim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
anyView.visibility = View.INVISIBLE
}
})
anim.start()
} else {
val cx = anyView.width / 2
val cy = anyView.height / 2
val finalRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat()
val anim = ViewAnimationUtils.createCircularReveal(anyView, cx, cy, 0f, finalRadius)
anyView.visibility = View.VISIBLE
anim.start()
}
}

Android : custom Drawable for the layout background . Child items are not clear?

My layout file is like this :
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="282dp"
android:layout_height="wrap_content"
android:layout_x="20dp"
android:layout_y="208dp"
android:alpha="155"
android:orientation="vertical" >
<EditText
android:id="#+id/txtUserName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="155"
android:hint="#string/hintUsername"
android:padding="2dp" >
<requestFocus />
</EditText>
<EditText
android:id="#+id/txtPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="155"
android:hint="#string/hintPassword"
android:inputType="textPassword"
android:padding="2dp" />
<Button
android:id="#+id/butBrowse"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="255"
android:text="#string/but_browse" />
</LinearLayout>
And I set a custom Drawable to the layout programatically as follows :
ViewGroup layoutView = (ViewGroup) getLayoutInflater().inflate(
R.layout.login_layout, null); // (ViewGroup)
layoutView.setBackground(new CustomDrawable(this) {
});
private class CustomDrawable extends Drawable {
private Context ctx;
private Bitmap bitmap;
public CustomDrawable(Context ctx) {
this.ctx = ctx;
init();
}
private void init() {
//draw dynamic stuff to the 'bitmap'
}
#Override
public void draw(Canvas canvas) {
canvas.save();
Paint p = new Paint();
canvas.drawBitmap(this.bitmap,0,0,p);
canvas.restore();
}
#Override
public int getOpacity() {
return 15;
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
}
Now my login_layout looks like this:
As can be seen in the picture , my child elements (edittext,password area, button) are not clearly visible.
My questions :
1.How to achieve something like above ?Do I have to apply another Drawable to the inner 'LinearLayout' ?
2.Is it possible to change the alpha level of the Textfields,Button so that it is more visible ?
you need to change the opacity for your custom drawable which is currently set to 15. Increasing the opacity will make it more visible.
#Override
public int getOpacity() {
return 15; // increase this value
}

Categories

Resources