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.
Related
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?
I have an horizontal recycler view snapping to center position. I want to set a bottom margin to centered items gradually. It's like os x dock grow effect, but i don't want to scale up, i want to push up.
I've done it with animations but it's not a good result and they are fired on recycler view scroll state changes.
Someone can indicate a solution to me?
Thanks in advance
After a lot of time I'm here to share my solution, more simple than I believed. I have extended RecyclerView and overriden onDraw method to set margin to RecyclerView's children based on their distance from center. It's not much clear, but now I have no time to make it better, and if someone need it, he can take a look to take inspiration
#Override
public void onDraw(Canvas c) {
super.onDraw(c);
int size = getChildCount();
for (int i = 0; i < size; i++) {
View v = getChildAt(i);
int x = DisplayHelper.pxToDp(act, (int) v.getX());
topMargin = x - startXCenter;
if (topMargin < -100 || topMargin > 100) {
topMargin = MAX_MARGIN;
} else if (topMargin < 0) {
topMargin *= -1;
}
topMargin = topMargin - MAX_MARGIN;
if (null != v) {
v.setY(topMargin);
}
}
}
Actually I don't know how it properly called - overlay, parallax or slideUP, whatever, I have an Activity called "cafe details" which presents a Container(LinearLayout) with header information (name, min price, delivery time min e.t.c) and other container (ViewPager) which contains a ExpandableListView with something information (menus&dishes) and all I want to do is slide up my Viewpager when scrolls listview to scpecific Y position to cover(or overlay) header information.
A similar effect (but with parallax that I don't need to use) looks like this
I can detect when user scrolling listview down or up but how I can move container with ViewPager to overlay other container? Please give me ideas, regards.
UPD
I have tried a huge number of ways how to implement it and all of them unfortunately are not suitable. So now I have come to next variant - add scroll listener to ListView, calculate scrollY position of view and then based on that move the viewpager on y axis by calling setTranslationY();
Here is some code
1) ViewPager's fragment
mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView absListView, int i) {
}
#Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
if (getActivity() != null) {
((MainActivity) getActivity()).resizePagerContainer(absListView);
}
}
});
2) MainActivity
//object fields
int previousPos;
private float minTranslation;
private float minHeight;
<--------somewhere in onCreate
minTranslation = - (llVendorDescHeaders.getMeasuredHeight()+llVendorDescNote.getMeasuredHeight());
//llVendorDescHeaders is linearLayout with headers that should be hidden
//lVendorDescNote is a textView on green background;
minHeight = llVendorDescriptionPagerContainer.getMeasuredHeight();
//llVendorDescriptionPagerContainer is a container which contains ViewPager
--------->
public void resizePagerContainer(AbsListView absListView){
final int scrollY = getScrollY(absListView);
if (scrollY != previousPos) {
final float translationY = Math.max(-scrollY, minTranslation);
llVendorDescriptionPagerContainer.setTranslationY(translationY);
previousPos = scrollY;
}
}
private int getScrollY(AbsListView view) {
View child = view.getChildAt(0);
if (child == null) {
return 0;
}
int firstVisiblePosition = view.getFirstVisiblePosition();
int top = child.getTop();
return -top + firstVisiblePosition * child.getHeight() ;
}
This simple solution unfortunately has a problem - it is blinking and twitching (I don't know how to call it right) when scrolls slowly. So instead setTranslationY() I've used an objectAnimator:
public void resizePagerContainer(AbsListView absListView){
.............
ObjectAnimator moveAnim = ObjectAnimator.ofFloat(llVendorDescriptionPagerContainer, "translationY", translationY);
moveAnim.start();
..............
}
I don't like this solution because 1) anyway it does resize viewpager with delay, not instantly 2) I don't think that is good idea to create many ObjectAnimator's objects every time when I scroll my listView.
Need your help and fresh ideas. Regards.
I'm assuming that you are scrolling the top header (the ImageView is a child of the header) based on the scrollY of the ListView/ScrollView, as shown below:
float translationY = Math.max(-scrollY, mMinHeaderTranslation);
mHeader.setTranslationY(translationY);
mTopImage.setTranslationY(-translationY / 3); // For parallax effect
If you want to stick the header/image to a certain dimension and continue the scrolling without moving it anymore, then you can change the value of mMinHeaderTranslation to achieve that effect.
//change this value to increase the dimension of header stuck on the top
int tabHeight = getResources().getDimensionPixelSize(R.dimen.tab_height);
mHeaderHeight = getResources().getDimensionPixelSize(R.dimen.header_height);
mMinHeaderTranslation = -mHeaderHeight + tabHeight;
The code snippets above are in reference to my demo but I think it's still general enough for you.
If you're interested you can check out my demo
https://github.com/boxme/ParallaxHeaderViewPager
Have you tried CoordinatorLayout from this new android's design support library? It looks like it's what you need. Check this video from 3:40 or this blog post.
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.
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)