I have searched for a possible solution to imitating the collapsible toolbar but I can't seem to start it with my current knowledge on handling complex layouts.
From the layout above, I have a docked layout above, an imageview, 2 textviews. What I want to do is when I scroll up, the imageview will transfer its self at the top right, the textview without border will be pushed at the top, and the last textview should disappear.
Just like this.
As of now, I was able to move the ImageView to the required position when scrolling with this code:
private void scaleImage(float x, float y) {
movingView.setScaleX(x);
movingView.setScaleY(y);
movingView.setPivotX(1.3f * movingView.getWidth());
movingView.setPivotY(1.5f * movingView.getHeight());
}
#Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
float offsetFactorDown = (float) (getScrollY()) / (float) scrollRange;
float scaleFactor = 1F - offsetFactorDown * 0.9F;
scaleImage(scaleFactor, scaleFactor);
}
The getScrollY() is not consistent which only gives me the right position when I am scrolling slowly. What else can I use to be the basis for the offset which is consistent?
Related
I'm using the following code to expand a view with an animation:
public class HorizontallyAnimate extends Animation {
private int toWidth;
private int startWidth;
private View view;
private String TAG = HorizontallyAnimate.class.getSimpleName();
private int newWidth;
public HorizontallyAnimate(View view) {
this.view = view;
this.startWidth = this.view.getWidth();
this.toWidth = (this.startWidth == view.getHeight() ? this.startWidth * 4 : view.getHeight());
Log.d(TAG,"Start width" + this.startWidth);
Log.d(TAG,"view hieght " + view.getHeight());
}
protected void applyTransformation(float interpolatedTime, Transformation t) {
newWidth = this.startWidth + (int) ((this.toWidth - this.startWidth) * interpolatedTime);
this.view.getLayoutParams().width = newWidth;
this.view.requestLayout();
}
}
The above code animates the view from left to right when the width changes.
But, I'm trying to animate it from the right to left. In other words, the width should grow in opposite direction. How can I be able to do so?
The problem you're dealing with here is an anchoring issue. A view's anchor (or pivot point) determines which point on the view stays still when other parts change.
A view's anchor when adjusting its dimensions highly depends on how the view is laid out. Since you didn't supply any information on how your view is laid out in the code you posted, I'll assume from the problem you're experiencing that the view's horizontal anchor is its left side.
This anchoring issue would produce a growth which would cause the left-most side to stay still, while the right side expands right-wards.
Making the view's left side to expand leftwards while the right side stays still can be achieved in several ways. One way would be to alter the way the view is laid out in its parent (i.e., if the parent is a RelativeLayout, set the view to alignParentRight=true, or playing with gravity in other containers).
However, since you didn't specify how the view is laid out, I will give you a solution which does not make any assumptions on its container. This solution isn't perfect as it may cause some stuttering, but it should still achieve what you're trying to do.
In your applyTransformation method, you will need to compensate for the right growth by translating leftwards. You can compensate for this by using translationX:
protected void applyTransformation(float interpolatedTime, Transformation t) {
// hold the change in a separate variable for reuse.
int delta = (int) ((this.toWidth - this.startWidth) * interpolatedTime);
newWidth = this.startWidth + delta;
this.view.getLayoutParams().width = newWidth;
// shift the view leftwards so that the right side appears not to move.
// shift amount should be equal to the amount the view expanded, but in the
// opposite direction.
this.view.setTranslationX(-delta);
this.view.requestLayout();
}
As you can see, this is a bit of "trick". While the view is expanding to the right, we are moving it to the left at the exact same ratio which causes the illusion of the view expanding to the left.
Test this code and see if it works for you. I would also recommend seeing if you can play around with the view's alignment or gravity from within its container. Doing this would solve your issue in a more standard manner, i.e., without any "tricks".
Hope this helps.
I am working on an app and I have something similar to the Hangouts app where there is the sliding tabs under the ToolBar but I wanted to integrate it into the ToolBar instead of existing in the Activity/Fragment layout.
I have tried increasing the height of the ToolBar and setting a custom view, but if I do that, the custom view is in the middle of the ToolBar and not underneath the Title and Menu Overflow Button.
I have tried several things. Latest is:
toolBar.setCustomView(customView, layoutParams);
Any help would be great.
EDIT: Should have been more clear...
I want the tabs like this to be in the ToolBar not in the Fragment Layout like this,
https://developer.android.com/samples/SlidingTabsColors/res/layout/fragment_sample.html
You will have to use the OnScrollChanged function in your ScrollView. ActionBar doesn't let you set the opacity , so set a background drawable on the actionbar and you can change its opacity based on the amount of scroll in the scrollview. I have given an example workflow
The function sets gives the appropriate alpha for the view locationImage based on its position WRT window .
this.getScrollY() gives you how much the scrollView has scrolled
public void OnScrollChanged(int l, int t, int oldl, int oldt) {
// Code ...
locationImage.setAlpha(getAlphaForView(locationImageInitialLocation- this.getScrollY()));
}
private float getAlphaForView(int position) {
int diff = 0;
float minAlpha = 0.4f, maxAlpha = 1.f;
float alpha = minAlpha; // min alpha
if (position > screenHeight)
alpha = minAlpha;
else if (position + locationImageHeight < screenHeight)
alpha = maxAlpha;
else {
diff = screenHeight - position;
alpha += ((diff * 1f) / locationImageHeight)* (maxAlpha - minAlpha); // 1f and 0.4f are maximum and min
// alpha
// this will return a number betn 0f and 0.6f
}
// System.out.println(alpha+" "+screenHeight +" "+locationImageInitialLocation+" "+position+" "+diff);
return alpha;
}
An example working sample at https://github.com/ramanadv/fadingActionBar , you can have a look at it.
I'm using a cover flow in my Android App with this tutorial link http://www.inter-fuser.com/2010/01/android-coverflow-widget.html and I already use it well. But my problem is when the Android version is 4.1 the cover flow semms not working well, because the images is not being centered or aligning well after choosing an image. But if the Android version is below 4.0 it works well like in the video of the link.
Did anyone have a thoughts regards this issue?
UPDATE
A fix for this issue is to make the following change to getChildStaticTransformation(View child, Transformation t)
protected boolean getChildStaticTransformation(View child, Transformation t) {
child.invalidate(); // add this line
final int childCenter = getCenterOfView(child);
final int childWidth = child.getWidth();
int rotationAngle = 0;
t.clear();
t.setTransformationType(Transformation.TYPE_MATRIX);
if (childCenter == mCoveflowCenter) {
transformImageBitmap((ImageView) child, t, 0);
} else {
rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
if (Math.abs(rotationAngle) > mMaxRotationAngle) {
rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle
: mMaxRotationAngle;
}
transformImageBitmap((ImageView) child, t, rotationAngle);
}
return true;
}
--
I had this same problem recently. This has to do with the Gallery having been deprecated. As an alternative, I implemented something similar to this using a HorizontalScrollView and centering using .scrollTo(). The problem with this solution is that scrollTo() aligns with the left side of the View and so you have to compute the middle y0urself. If the layout fills the screen you're going to have to apply padding to the left and right side of the view to force the selected element to the center.
A word of caution. Horizontal scroll views don't have animatible scrolling so it's going to be a snap-to behavior. You can get around this by scrolling using a timer but it's not a terribly elegant solution.
When I enlarge the size of the content of a scrollview, the scrollview takes a while to get to "know" this size change of it's child. How can I order the ScrollView to check it's child immediately?
I have an ImageView in a LinearLayout in a ScrollView.
In my ScaleListener.onScale, I change the size of my LinearLayout. I then try to order a scroll on the scrollview. In the ScaleListener.onScale:
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) imageView.getLayoutParams();
params.width = (int) (startX * scaleFactor);
params.height = (int) (startY * scaleFactor);
imageView.setLayoutParams(params);
(...)
scrollView.scrollBy(scrollX, scrollY);
However, no scrolling occurs when in the situation before the scaling scrolling was not possible because the view was too small to scroll. After the setLayoutParams, the view should be larger, but no scrolling occurs because the scrollview thinks the child is still small.
When a fes ms later the onScroll is called again, it does scroll fine, it somehow found out that the child is larger and scrollable.
How can I notify the scrollview immediately, that the child's size has changed? So that scrollBy will work right after setLayoutParams on it's child?
I found a solution after trying just about every onXXX() method. onLayout can be used. You can plan the scroll and do it later in onLayout().
Extend your scrollview, and add:
private int onLayoutScrollByX = 0;
private int onLayoutScrollByY = 0;
public void planScrollBy(int x, int y) {
onLayoutScrollByX += x;
onLayoutScrollByY += y;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
doPlannedScroll();
}
public void doPlannedScroll() {
if (onLayoutScrollByX != 0 || onLayoutScrollByY != 0) {
scrollBy(onLayoutScrollByX, onLayoutScrollByY);
onLayoutScrollByX = 0;
onLayoutScrollByY = 0;
}
}
Now, to use this in your code, instead of scrollBy(x,y) use planScrollBy(x,y). It will do the scroll at a time when the new size of the child is "known", but not displayed on screen yet.
When you use a horizontal or vertical scrollview, of course you can only scroll one way, so you will have to change this code it a bit (or not, but it will ignore the scroll on the other axis). I used a TwoDScrollView, you can find it on the web.
You can call:
scrollView.updateViewLayout(childView, childLayout)
it's my first question.
I have built a custom component: a RelativeLayout with a TextView on the bottom and two ImageView above that, acting as a 2-columns clickable element of an histogram. To set the height of a bar, i get the "available height" in onLayout(), as container's height minus label's one:
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mAvailHeight = getHeight()-findViewById(R.id.label).getHeight(); // it works
and then assign it (multiplied by a 0.-1. value) as a layout parameter to the ImageView:
View bar = findViewById(R.id.bigBar);
RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) bar.getLayoutParams();
rlp.height = Math.round((float)mAvailHeight * mBigBarHeight);
}
The mBigBarHeight variable (0.-1.) can be set via this function:
public void setBigBarHeight(float value, float max) {
mBigBarHeight = value / max;
requestLayout(); //
invalidate(); // do these help? i find no difference
}
Now. When i add one of these "HistogramBar" in onCreate() and set the heights and label everything works as I expect. If i try to modify them later, say onClickSomething:
bar.setBigBarHeight(25, 100);
bar.setSmallBarHeight(50, 100);
bar.setLabel("jjk");
only the label changes. I checked with Hierarchy Viewer and actually the LayoutParams did change. If i click again changes appear.
The funny thing is that even if i do "Load View Hierarchy" from the tool changes get displayed (on the emulator)!! What happens? Is it strange? I want to do that in my code so that it works!
I couldn't find any similar question. Thanks.
When you load a hierarchy from the tool, a relayout/redraw happens to measure performance. You are probably not calling requestLayout() when you should.