ObjectAnimator not working properly when view.getX() != 0 - java

I'm using ObjectAnimator to translate a view horizontally to the right edge of the outer view. Both views are children of the same layout, with the second view matching width and height of the parent and enclosing the first view. When my activity starts and ObjectAnimator is called to translate the view, it will only end up at the correct destination when the view starts out at 0.0, 0.0. When start coordinates are 100.00,100.00 , the view ends up 100.00 units past where it's supposed to be.
startX = view.getX();
endX = getRight(layout) - view.getWidth();
Log.i("debugger", "going from x="+startX+" to x="+endX);
translateRight = ObjectAnimator.ofFloat(view, "translationX", startX, endX);
And in the animatorListener
#Override
public void onAnimationEnd(Animator animator) {
Log.i("debugger", "end x = "+view.getX());
}
The method I use to get the X coordinate of the right edge of a view
public int getRight(View view){
return (int)(view.getX()+view.getWidth());
}
Snippet of xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="100"
android:orientation="horizontal"
android:gravity="center">
<RelativeLayout
android:layout_width="0dp"
android:layout_weight="82"
android:layout_height="match_parent">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/outerView"
/>
<View
android:layout_height="#dimen/view_width"
android:layout_width="#dimen/view_width"
android:background="#drawable/view"
android:id="#+id/view"
android:layout_toRightOf="#id/obstacle1"
android:layout_below="#id/obstacle1"
/>
<View
android:id="#+id/obstacle1"
android:layout_height="#dimen/view_width"
android:layout_width="#dimen/view_width"
android:background="#drawable/obstacle"
android:layout_alignParentTop="true"
/>
layout
When the view starts off in the upper left hand corner (where obstacle 1 is), the view ends up flush against the inside right wall of the outerView, where it should be. However, when the view has non-zero coordinates, as in the example where it sits below and to the right of obstacle1, it goes past the right edge and sits flush against the outside wall of the outerView. The funny thing is, if the view is placed in the xml at the upper left hand corner, it can move as supposed to no matter where it becomes positioned. When it doesn't start in the corner, everything's jacked from the get-go.
The logs look as follows for when view starts at 0,0:
going from x=0 to x=1080
end x = 1080
The logs look as follows for when view starts at 100, 100:
going from x=100 to x=1080
end x = 1180
Does anyone know why this is happening? Any help would be greatly appreciated.

You are translating the view on the X axe, with start value 100. If the translationX attribute of your view is 0, then the animation will start by instantly translating your view by 100.
You should do something like this :
translateRight = ObjectAnimator.ofFloat(view, "translationX", view.getTranslationX(), endX - startX);

Related

NestedScrollView fading/moving views in/out on Scroll Up/Down

I have a nested scroll view with child views (wrapped in layout) and I need to fade in/out on scroll up/down.
My issue is trying to get the vertical scroll value reversed (to lessen the alpha value for fading in and out on scroll).
As standard, the ScrollY (vertical Scroll value) increases/starts from
0 as the user scrolls to the bottom of the NestedScroll from the Top
I'm sure there would is a math equation to get the correct value for alpha fading in/out but cant quite stick it but once I do, I could also get values to move views up/down and fade in/out on scroll.
Not wanting to use CoordinatedLayout to collapse etc
NestedScroll View (XML)
<androidx.core.widget.NestedScrollView
android:id="#+id/nested_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Fade In/Out -->
<RelativeLayout
android:id="#+id/fade_me_on_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</RelativeLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
Fragment with NestedScroll View in onCreateView (Kotlin)
//...
//...
//...
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//...
//...
//region NestedScroll
myNestedScroll = binding.NestedScroll
if (myNestedScroll != null) {
myNestedScroll.setOnScrollChangeListener(
NestedScrollView.OnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
//set Scroll Calculation Factor, use in calculation
var scrollCalculateFactor = 25
//set Scroll min range, if ScrollY has passed this value, do processing in the if statement below
var minScrollRange = 10
//set Scroll max range, if ScrollY has passed this value, stop processing
var maxScrollRange = 250
//if scroll is with range, do processing
if(scrollY in minScrollRange..maxScrollRange) {
//wrap in try block just in case it goes paer shaped ...
try {
//set current ScrollY value to alpha value
//issue is here, works correctly as it returns the alpha value (i.e 0.20f)
//but as user scrolls to the Bottom the value (alpha) increases which fades in views (and as user scroll to the Top, fades out views), but I need the opposite to happen so views fade in/out correctly
var currentCalculatedAlpha = scrollY.toFloat() / maxScrollRange.toFloat()
if (scrollY > oldScrollY) {
//region Scrolling to the Bottom
//fade views out here
//fade the View using alpha setting
//however as the scrollY value increases, the alpha increases, fading in the view, need to opposite to happen
//binding.FadeMeOnScroll.alpha = currentCalculatedAlpha
//endregion Scrolling to the Bottom
} else if (scrollY < oldScrollY) {
//region Scrolling to the Top
//fade views back in
//fade the View using alpha setting
//however as the scrollY value decreases, the alpha decreases, fading out the view, need to opposite to happen
//binding.FadeMeOnScroll.alpha = currentCalculatedAlpha
//endregion Scrolling to the Top
} else if(scrollY >= maxScrollRange){
//region Scrolled passed max range
//stop processing or manually fade out
//fade the View using alpha setting
//binding.FadeMeOnScroll.alpha = 0f
//endregion Scrolled passed max range
}
}catch (exception: Exception) {
//log error
Log.e("exception", "exception: " + exception.message)
}
}
})
}
//endregion NestedScroll
}

Determine if a TextView requires scrolling

Inside CursorAdapter's bindView() I bind data to the following layout:
A TextView and two Buttons : "UP" and "DOWN".
The TextView is defined in XML like so:
<TextView
android:id="#+id/tv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="25dp"
android:paddingRight="25dp"
android:paddingTop="25dp"
android:scrollbars="vertical"
android:textAlignment="textStart"
android:textColor="#5c6284"
app:autoSizeMaxTextSize="40sp"
app:autoSizeMinTextSize="20sp"
app:autoSizeTextType="uniform" />
A vertical scrolling behavior is applied to the TextView, which is being controlled by the "UP and "DOWN" Buttons.
I would like to determine if the TextView requires scrolling ( is long enough to not fit its provided drawing area ) so that I can enable/disable the "UP" and "DOWN" buttons accordingly.
I'm currently reading BaseMovementMethod's scrollDown function, thinking of applying its measuring logic to my adapter, though I have the feeling that it should be much simpler. Maybe a built in behavior that I'm not aware of.
Is there a better way to achieve this, other than my suggested approach?
What I would do is put the textview inside a scrollview like so:
<ScrollView
android:id="#+id/scroller"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<TextView
android:id="#+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="test texts here"/>
</ScrollView>
In your activity, execute these lines:
boolean needScrolling = false;
if(scroller.getHeight() < tv_content.getHeight()) needScrolling = true;
You can use Static Layout class. If you set it up with your TextView's parameters you'll be able to calculate the height of the rendered text.
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
float spacingMultiplier = 1;
float spacingAddition = 0;
boolean includePadding = false;
StaticLayout myStaticLayout = new StaticLayout(text, myTextView.getPaint(), myTextView.getWidth(), alignment, spacingMultiplier, spacingAddition, includePadding);
float height = myStaticLayout.getHeight();
Then you can compare the height of your text and height of your TextView and figure out if it will require scrolling or not.
You can also try to manually create a Paint object with your min text size if myTextView.getPaint() approach does not work.
Calculate mTextView's height without data and with data and then compare it
mTextView.post(new Runnable() {
#Override
public void run() {
int lineHeight=mTextView.getCompoundPaddingBottom()+ mTextView.getCompoundPaddingTop()+mTextView.getLineHeight();
int height=mTextView.getHeight()-(mTextView.getCompoundPaddingTop()+mTextView.getLineHeight());
if (height>lineHeight){
}
}
});

Positional differences between creating views in XML or programatically

I have a trouble while creating a kind of view. Let's just say that i'm trying to create something similar to a clock. This means that we have to position numbers in a distance and angle from a center.
I tried to emulate a way to position two elements. A center ImageView and a clock number. In XML I have something similar to:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lyt_rootView"
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/ivCenter"
android:background="#drawable/cid"/>
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/ivNumber"
android:background="#drawable/add_big"
android:layout_marginLeft="-50dp"
android:layout_marginTop="50dp"/>
</RelativeLayout>
And it works pretty well, the images set as they should be, being completly centered the first image (ivCenter) and taking some margin from the center for positioning the second image.
Now I have to do the same programatically so I can create lots of imageViews simulating the numbers. So I have this code:
RelativeLayout lyt = (RelativeLayout) findViewById(R.id.lyt_rootView);
int avatarSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 70, getResources().getDisplayMetrics());
int distance = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics());
// center image
ImageView ivImageCenter = new ImageView(this);
ivImageCenter.setImageResource(R.drawable.cid);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(avatarSize,avatarSize);
lyt.addView(ivImageCenter, lp);
// first image (simulating a number in a clock)
ImageView ivNumber1 = new ImageView(this);
ivNumber1.setImageResource(R.drawable.add_big);
RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(avatarSize,avatarSize);
lp2.setMargins(distance, distance, 0, 0);
lyt.addView(ivNumber1, lp2);
but the result is not similar as the XML example. I don't see what I'm missing. The result of creating the views programatically is that the two imageViews are trying to position in a center space in the screen making the first image not centered to the screen.
What I'm missing?
Finally I solved it by creating a one pixel layout centered in XML that acts as a reference and programatically adding the views in that reference view.

TableRow weights scaling opposite of what I expect when using GraphView in my Android java app

I've created the following layout xml-file:
<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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="some.package.MainActivity" >
<TableLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TableRow
android:id="#+id/mainRow"
android:layout_weight="1" >
<FrameLayout
android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1" />
</TableRow>
<TableRow
android:id="#+id/footerRow"
android:layout_weight="1" >
<FrameLayout
android:id="#+id/footerLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1" />
</TableRow>
</TableLayout>
</RelativeLayout>
... and populate it with graphs from the GraphView api as follows:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int[] assetLayouts = new int[]{
R.id.mainLayout,
R.id.footerLayout,
};
int count = 0;
for (int assetLayout :assetLayouts ) {
GraphViewSeries exampleSeries = new GraphViewSeries(new GraphViewData[] {
new GraphViewData(1, 2.0d)
, new GraphViewData(2, 1.5d)
, new GraphViewData(3, 2.5d)
, new GraphViewData(4, 1.0d)
});
GraphView graphView = new LineGraphView(this, "" + ++count);
graphView.addSeries(exampleSeries);
FrameLayout layout = (FrameLayout) findViewById(assetLayout);
layout.addView(graphView);
}
}
This behaves as expected and divides the screen in two parts, with one graph taking up the first top half, and the second one taking up the other bottom half. Now, I want to give the top graph/row more weight, i.e., it should be proportionally larger than the lower graph/row. So, what i did was set the top row (mainRow) to android:layout_weight="2". I expect that the top row now should be twice as large as the bottom row, however, the opposite happens. The top one only get 33%, while the bottom one gets 66% of the screen real estate. This is opposite of the documentation I found:
For example, if there are three text fields and two of them declare a
weight of 1, while the other is given no weight, the third text field
without weight will not grow and will only occupy the area required by
its content. The other two will expand equally to fill the space
remaining after all three fields are measured. If the third field is
then given a weight of 2 (instead of 0), then it is now declared more
important than both the others, so it gets half the total remaining
space, while the first two share the rest equally.
http://developer.android.com/guide/topics/ui/layout/linear.html
What is going on here?
Sure I can work around it and just give the opposite weights of what I thought was right, but I'd rather do it right.
Also when setting weight, set width (if orientation is horizontal) or height (if vertical) to 0dp. That way the width/height is calculated properly.

Screen height doesn't match actual screen height

Solved:
As Zoltán wrote I didn't take the statusbar and titlebar into consideration (They're both 25 in height)
I used the following code in my onClickListener method inside my Activity and forwarded the results to my Service class and printed it out there:
Rect rectgle = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight = rectgle.top;
int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight = contentViewTop - StatusBarHeight;
serviceIntent.putExtra("Titlebarheight", Integer.toString(TitleBarHeight));
serviceIntent.putExtra("Statusbarheight", Integer.toString(StatusBarHeight));
-----------------------------------------------------------------------------------------
I am trying to set the layout height of my ImageView in my main.xml, but when I set the layout_height to 270dp (or px) it fills up the whole screen from top to bottom, but my screen size is actually 320x240 (HTC magic - Android 1.5) - So it SHOULDN'T fill up the screen from top to bottom!
Code inside Activity:
Display display = getWindowManager().getDefaultDisplay();
Log.i("Screen height", Integer.toString(display.getHeight())); // Returns 320
Log.i("Screen width", Integer.toString(display.getWidth())); // Returns 240
Code inside main.xml:
<ImageView
android:id="#+id/bitmapImageView"
android:layout_height="270dp" // Fills up the whole screen from top to bottom
android:layout_width="50dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="#FFFFFF"
android:src="#drawable/ic_launcher" />
Why is this happening? How can I fix it?
Example when using 270 as layout height:
Example when using 240 as layout height:
The height of the status bar and the title bar of your application seems to be about the same as the width of your ImageView, which is 50px judging from your XML.
So then 50px + 270px = 320px, which is the total height of your screen (including the status and title bar).
See: Screen Resolution of android and
scale-independent pixel
Basically, a dp (display-independent pixel) is not the same size on all displays. At your resolution 1dp =~ .75px
To do a full screen activity see: Fullscreen Activity in Android?
Specifically, set: android:theme="#android:style/Theme.NoTitleBar.Fullscreen" in the android manifest for that activity.

Categories