What am I doing wrong in creating this android floating bubble animation? - java

I am trying to translate this Swift code:
#objc func heartFlurry()
{
let heartImage = UIImage(named: "heartWhite")
let heartImageView = UIImageView(image: heartImage)
let screenSize = UIScreen.main.bounds
let heartWidth = Int(heartImage!.size.width)
let heartHeight = Int(heartImage!.size.height)
let randomX = arc4random_uniform(UInt32(screenSize.width))
heartImageView.frame = CGRect(x: Int(randomX) - Int(Double(heartWidth) * 0.5), y: Int(screenSize.height) + heartHeight, width: heartWidth, height: heartHeight)
view.addSubview(heartImageView)
let randomIntFrom0To4 = Int.random(in: 1..<6)
print(randomIntFrom0To4)
self.updateLove()
self.playSound(sound: "pop_\(randomIntFrom0To4)")
UIView.animate(withDuration: 1.5, animations: {
heartImageView.center = CGPoint(x: heartImageView.center.x, y: CGFloat(-heartHeight))
}) { (finished: Bool) in
heartImageView.removeFromSuperview()
}
}
Into Java, The code (when tapped multiple times) creates an effect that looks like this:
So far I have got this into my Java code:
void heartFlurry() {
Drawable heart = getResources().getDrawable( R.drawable.heart );
View v = new ImageView(getBaseContext());
ImageView imageView;
imageView = new ImageView(v.getContext());
imageView.setImageDrawable(heart);
Integer heartWidth = heart.getIntrinsicWidth();
Integer heartHeight = heart.getIntrinsicHeight();
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Log.e("Width", "" + width);
Log.e("height", "" + height);
final int randomX = new Random().nextInt(size.x);
Log.e("randomX", "" + randomX);
// RelativeLayout. though you can use xml RelativeLayout here too by `findViewById()`
final RelativeLayout relativeLayout = new RelativeLayout(this);
// Setting layout params to our RelativeLayout
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(size.x, size.y);
// Setting position of our ImageView
layoutParams.leftMargin = randomX;
layoutParams.topMargin = 500;
// Finally Adding the imageView to RelativeLayout and its position
relativeLayout.addView(imageView, layoutParams);
ObjectAnimator animationY = ObjectAnimator.ofFloat(imageView, "translationY", -size.y);
animationY.setDuration(500);
animationY.start();
new CountDownTimer(500, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
relativeLayout.removeAllViews();
}
}.start();
}
I feel like I have all the elements there, creating the imageview, adding a relative layout and setting it at the bottom of the screen and using a random Int for a random X position within the screen width, but nothing happens when I run it. What am I missing?
Thank you.

The problem was with the Relative Layout I created, it was not being properly added to the view.
I added a RelativeLayout in XML to the activities content XML rather than creating it programatically, then referred to it:
RelativeLayout relativeLayout;
relativeLayout = findViewById(R.id.heartLayout);
Then I updated the heartFlurry function to add a rule to the heartImageView params, to start at the bottom of the screen, and use the randomX for the leftMargin.
void heartFlurry() {
Drawable heart = getResources().getDrawable( R.drawable.heart );
View v = new ImageView(getBaseContext());
ImageView imageView;
imageView = new ImageView(v.getContext());
imageView.setImageDrawable(heart);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Log.e("Width", "" + width);
Log.e("height", "" + height);
final int randomX = new Random().nextInt(size.x);
Log.e("randomX", "" + randomX);
RelativeLayout.LayoutParams paramsImage = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
paramsImage.addRule(RelativeLayout.CENTER_IN_PARENT);
imageView.setLayoutParams(paramsImage);
relativeLayout.addView(imageView);
RelativeLayout.LayoutParams heartParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT
);
heartParams.leftMargin = randomX;
heartParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
imageView.setLayoutParams(heartParams);
ObjectAnimator animationY = ObjectAnimator.ofFloat(imageView, "translationY", -size.y);
animationY.setDuration(500);
animationY.start();
new CountDownTimer(1000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
relativeLayout.removeAllViews();
Log.e("randomX", "Timer Done");
}
}.start();
}

Related

How to display label using Slider of Material component?

I am using the Slider of Material component:
https://github.com/material-components/material-components-android/blob/master/docs/components/Slider.md
I am trying to display a label when the thumb is moving, which seem to be supported with the labelFormatter attribute.
here is what my code looks like:
Slider s = new Slider(context);
s.setLabelFormatter(new Slider.LabelFormatter() {
#NonNull
#Override
public String getFormattedValue(float value) {
return "MY STRING";
}
});
When I go line by line with debugger it goes through this function:
private void drawLabelText(#NonNull Canvas canvas, int width, int top) {
labelTextPaint.getTextBounds(labelText, 0, labelText.length(), labelTextBounds);
int left = trackSidePadding + (int) (thumbPosition * width) - labelTextBounds.width() / 2;
canvas.drawText(labelText, left, top - labelTextTopOffset - thumbRadius, labelTextPaint); }
but no text is displayed only the slider...
I am kind of new in androïd and I am surely missing something.
Thanks for help :)
EDIT 1:
Here is the whole code simplified :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CoordinatorLayout layout = new CoordinatorLayout(this);
setContentView(layout);
// I am Using Coordinator Layout for current activity so...
CoordinatorLayout.LayoutParams layoutParams = new CoordinatorLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
//Setting gravity to CENTER
layoutParams.gravity = Gravity.CENTER;
Slider slider = new Slider(this);
slider.setLabelFormatter(new Slider.LabelFormatter() {
#NonNull
#Override
public String getFormattedValue(float value) {
return "MY STRING";
}
});
layout.addView(slider, layoutParams);
}
But still not working ...
output result
https://youtu.be/obV4K-Nxu-0
EDIT 2:
Updating Material component from version: '1.2.0-alpha02' to version: '1.2.0-alpha05' fixed the issue.
Actually i wanted to comment but because of Reputation Constraints i couldn't,
Looks like you are adding a view programatically in your activity. Here i have implemented new MaterialComponent Slider with LabelFormatter
ViewGroup group = findViewById("YOUR_ACTIVITY_LAYOUT");
// I am Using Coordinator Layout for current activity so...
CoordinatorLayout.LayoutParams layoutParams = new CoordinatorLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
//Setting gravity to CENTER
layoutParams.gravity = Gravity.CENTER;
Slider slider = new Slider(this);
slider.setLabelFormatter(new Slider.LabelFormatter() {
#NonNull
#Override
public String getFormattedValue(float value) {
return "MY STRING";
}
});
group.addView(slider, layoutParams);
}
And then there you go...

How to center text vertically in a TextView with Java code?

I know this question has been asked many times on SO. I have read most of them, but they don't work for me, so don't bother marking duplicates.
Here is my code, and what I have tried so far:
RelativeLayout container = new RelativeLayout(this.getContext());
TextView tv = new TextView(this.getContext());
tv.setText(txt); // a single digit like '3'
tv.setLines(1);
tv.layout(0, offsety, cellszie, offsety+cellsize);
tv.setTextAlignment(TextView.TEXT_ALIGNMENT_CENTER);
tv.setGravity(Gravity.CENTER);
// I also tried CENTER_VERTIAL and the following line
// tv.setGravity(CENTER_VERTIAL| CENTER_HORIZONTAL);
// I also tried giving LayoutParams to tv like this:
// tv.setLayoutParams(new LayoutParams(cellsize, cellsize));
// tv.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
// tv.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT));
container.addView(tv);
The character is horizontally centered, but it floats on the top of the TextView vertically. Setting gravity and LayoutParams doesn't change its behavior.
What should I do to make it center vertically?
use this class for VerticalTextView.
public class VerticalTextView extends TextView {
final boolean topDown;
public VerticalTextView(Context context, AttributeSet attrs){
super(context, attrs);
final int gravity = getGravity();
if(Gravity.isVertical(gravity) && (gravity&Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) {
setGravity((gravity&Gravity.HORIZONTAL_GRAVITY_MASK) | Gravity.TOP);
topDown = false;
}else
topDown = true;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
#Override
protected void onDraw(Canvas canvas){
TextPaint textPaint = getPaint();
textPaint.setColor(getCurrentTextColor());
textPaint.drawableState = getDrawableState();
canvas.save();
if(topDown){
canvas.translate(getWidth(), 0);
canvas.rotate(90);
}else {
canvas.translate(0, getHeight());
canvas.rotate(-90);
}
canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());
getLayout().draw(canvas);
canvas.restore();
}
}
you can do it like this
RelativeLayout container = new RelativeLayout(this.getContext());
View view = layoutInflater.inflate(R.layout.my_layout_file, null);
container.addView(view);
where R.layout.my_layout_file contains textview with gravity center. and here you can get object of textview like this
textviewObject = (TextView)view.findViewById(R.id.textViewId)
Try setting RelativeLayout.LayoutParams to you RelativeLayout
RelativeLayout.LayoutParams relativeLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
container.setLayoutParams(relativeLayoutParams)
Then set the gravity for your TextView:
tv.setGravity(Gravity.CENTER);
Then add the view to your RelativeLayout:
container.addView(tv);

Height and Width of a view are always 0 ( getMeasuredHeight() and getHeight() both are not working )

I have a LinearLayout inside a LinearLayout and child linearlayout have its layout params where height and width are defined as
LinearLayout linearLayout=new LinearLayout(context);
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(50,50);
linearLayout.setLayoutParams(lp);
now after view created i am trying to get height of a view from getHeight() and getMeasuredHeight() but both methods returning 0 . ?
int heightofView=linearLayout.getHeight();
int heightofview=linearLayout.getMeasuredHeight();
why both these methods are returning 0 height of a view ? when these methods return the actual result ? how to get height of my created view ?
Try this code.
imageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int width = imageView.getWidth();
int height = imageView.getHeight();
//you can add your code here on what you want to do to the height and width you can pass it as parameter or make width and height a global variable
imageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
Do as below -
linearLayout.post(new Runnable() {
#Override
public void run() {
int linearLayoutHeight = linearLayout.getHeight();
Log.e("MS", "linearLayout Ht = " + linearLayoutHeight);
}
});

Measure height of multi-line TextView before rendering

What i've tried to far:
Calling measure()
tv.measure(0, 0);
int height = tv.getMeasuredHeight();
Calling measure() with specified sizes/modes
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(99999, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
tv.measure(widthMeasureSpec, heightMeasureSpec);
int height = tv.getMeasuredHeight();
Calling getTextBounds()
Rect bounds = new Rect();
tv.getPaint().getTextBounds(tv.getText().toString(), 0, tv.getText().length(), bounds);
int height = bounds.height();
Calling measure() and then calling getTextBounds()
Calling getLineCount() * getLineHeight()
None seem to work. They all return incorrect values (container view gets incorrect height - it's either too small or too large)
Ideas on how to calculate this simple thing??
You need to specify the available width so the height can be properly calculated.
Note: In cases where you just need to get the height of a view that is already drawn, use ViewTreeObserver. See this question for a thing to consider in that case.
This is why I do, in a piece of code where I want to scale a view from hidden to its full necessary height:
int availableWidth = getParentWidth(viewToScale);
int widthSpec = View.MeasureSpec.makeMeasureSpec(availableWidth, View.MeasureSpec.AT_MOST);
int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
viewToScale.measure(widthSpec, heightSpec);
int measuredHeight = viewToScale.getMeasuredHeight();
// Offtopic: Now I animate the height from 1 to measuredHeight (0 doesn't work)
You may pass the availableWidth yourself, but I calculate it from the parent:
private int getParentWidth(View viewToScale)
{
final ViewParent parent = viewToScale.getParent();
if (parent instanceof View) {
final int parentWidth = ((View) parent).getWidth();
if (parentWidth > 0) {
return parentWidth;
}
}
throw new IllegalStateException("View to scale must have parent with measured width");
}
Where are you calling those methods?
The best way to do what you are trying to do is to use ViewTreeObserver and add onPreDrawListener.
Take a look at this i think it will help
What you can do here is get ViewTreeObserver associated with this TextView and add OnGlobalLayoutListener to it:
final ViewTreeObserver vto = textView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// textView dimensions are calculated at this stage, but textView
// isn't rendered yet. Do what you need to do and remove OnGlobalLayoutListener
// after
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
textView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
}
I had a similar problem recently, trying to measure the height of a ViewGroup containing several multiline TextView.
What worked for me was to measure() the TextView, then add (lineCount-1)*lineHeight to its measuredHeight.
Here is the code to measure only one TextView :
private int getMeasuredHeight(TextView textView) {
textView.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
int height = textView.getMeasuredHeight();
height += (textView.getLineCount()-1) * textView.getLineHeight();
return height;
}
And in the case of a ViewGroup with many TextViews, here is my code :
private int getMeasuredHeight(ViewGroup viewGroup) {
viewGroup.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
int height = viewGroup.getMeasuredHeight();
for(TextView textView : findAllTextView(viewGroup)) {
height += (textView.getLineCount()-1) * textView.getLineHeight();
}
return height;
}
private List<TextView> findAllTextView(ViewGroup v) {
List<TextView> result = new ArrayList<>();
for (int i = 0; i < v.getChildCount(); i++) {
Object child = v.getChildAt(i);
if (child instanceof TextView)
result.add((TextView) child);
else if (child instanceof ViewGroup)
for(TextView tv: findAllTextView((ViewGroup) child))
result.add(tv);
}
return result;
}

Scroll TextView to text position

I want to scroll my TextView to make visible a specific position in the text. How can I do that? I tried bringPointIntoView (int offset) but without success.
Source code:
public class TextScrollActivity extends Activity {
public void onCreate (final Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
final int position = 500;
final TextView textView = new TextView (this);
final ScrollView scrollView = new ScrollView (this);
scrollView.addView (textView);
Button button = new Button (this);
button.setText ("Scroll to " + position);
LinearLayout layout = new LinearLayout (this);
layout.setOrientation (LinearLayout.VERTICAL);
layout.addView (scrollView,
new LayoutParams (LayoutParams.FILL_PARENT, 200));
layout.addView (button, new LayoutParams (LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
StringBuilder builder = new StringBuilder ();
for (int i = 0; i < 1000; i++)
builder.append (String.format ("[ %05d ] ", i));
textView.setText (builder);
setContentView (layout);
button.setOnClickListener (new OnClickListener () {
public void onClick (View v) {
System.out.println (textView.bringPointIntoView (position * 10));
// scrollView.scrollTo (0, position * 10); // no
}
});
}
}
For those who have the same problem, I finally made my own implementation of bringPointIntoView:
public static void bringPointIntoView (TextView textView,
ScrollView scrollView, int offset)
{
int line = textView.getLayout ().getLineForOffset (offset);
int y = (int) ((line + 0.5) * textView.getLineHeight ());
scrollView.smoothScrollTo (0, y - scrollView.getHeight () / 2);
}
Don't hesitate if you have a better solution.
Does adding a movement method to the text view solve the problem?
textView.setMovementMethod(new ScrollingMovementMethod());
Just FYI for anyone else with the same problem, on a listView with large listItems, the overloaded bringPointIntoView can be passed a ListView instead of a ScrollView and use the ScrollTo method instead of smoothScrollTo.

Categories

Resources