I am facing problem while reading Animation scale duration flag in Marshmallow. Same code is working in earlier version of Marshmallow (6.0.0).
I am using android.app.Fragment.setCustomTransition() method for fragment animation. When Animation scale duration is 0 in developer option settings, fragments do not get displayed. So i had to disable animation over this condition.
My code snippet:
public static boolean isAnimationOff()
{
final float animatorSpeed;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
{
animatorSpeed = Settings.Global.getFloat(
context.getContentResolver(),
Settings.Global.ANIMATOR_DURATION_SCALE,
0);
}
else
{
animatorSpeed = Settings.System.getFloat(
context.getContentResolver(),
Settings.System.ANIMATOR_DURATION_SCALE,
0);
}
return animatorSpeed == 0;
}
The problem is :this code is returning true on each invoke even if animation scale duration is not 0.
Has anyone faced this issue?
Edit1
Following is the code snippet where I use isAnimationOff() method to load a fragment:
private void loadFragment(Fragment fragment)
{
FragmentTransaction transaction = getFragmentManager().beginTransaction();
if (!Constants.isAnimationOff())
transaction.setCustomAnimations(animSlideIn, animSlideOut);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).replace(R.id.frameTopContainer, fragment)
.commitAllowingStateLoss();
}
Edit2
Here is the custom LinearLayout that has custom property:
public class FractionLinearLayout extends LinearLayout
{
DisplayMetrics matrics = getContext().getResources().getDisplayMetrics();
public FractionLinearLayout(Context context, AttributeSet attrs,
int defStyleAttr)
{
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
public FractionLinearLayout(Context context)
{
super(context);
// TODO Auto-generated constructor stub
}
public FractionLinearLayout(Context context, AttributeSet attrs)
{
super(context, attrs);
// TODO Auto-generated constructor stub
}
public float getFractionTranslationX()
{
return getWidth() > 0 ? super.getTranslationX() / getWidth() : Float.MAX_VALUE;
}
public void setFractionTranslationX(float translationX)
{
int width = getWidth();
super.setTranslationX(width > 0 ? width * translationX : Float.MAX_VALUE);
}
public float getFractionTranslationY()
{
return getHeight() > 0 ? super.getTranslationX() / getHeight() : Float.MAX_VALUE;
}
public void setFractionTranslationY(float translationY)
{
int height = getHeight();
super.setTranslationY(height > 0 ? height * translationY : Float.MAX_VALUE);
}
public float getAnimWidth()
{
return getLayoutParams().width;
}
public void setAnimWidth(int animWidth)
{
getLayoutParams().width = animWidth;
requestLayout();
}
}
I had an issue in my FractionLinearLayout class. In set setFractionTranslationX() method, getWidth() was returning 0 at the very first call. That led my code to prevent Fragment to appear when animation is off. Now i have replaced getWidth() line with getResources().getDisplayMetrics().widthPixels and everything is working fine.
Updated Code:
public class FractionLinearLayout extends LinearLayout
{
DisplayMetrics matrics = getContext().getResources().getDisplayMetrics();
public FractionLinearLayout(Context context, AttributeSet attrs,
int defStyleAttr)
{
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
public FractionLinearLayout(Context context)
{
super(context);
// TODO Auto-generated constructor stub
}
public FractionLinearLayout(Context context, AttributeSet attrs)
{
super(context, attrs);
// TODO Auto-generated constructor stub
}
public float getFractionTranslationX()
{
return getWidth() > 0 ? super.getTranslationX() / getWidth() : 0;
}
public void setFractionTranslationX(float translationX)
{
int width = getResources().getDisplayMetrics().widthPixels;
super.setTranslationX(width > 0 ? width * translationX : 0);
}
public float getFractionTranslationY()
{
return getHeight() > 0 ? super.getTranslationY() / getHeight() : 0;
}
public void setFractionTranslationY(float translationY)
{
int height = getResources().getDisplayMetrics().heightPixels;
super.setTranslationY(height > 0 ? height * translationY : 0);
}
public float getAnimWidth()
{
return getLayoutParams().width;
}
public void setAnimWidth(int animWidth)
{
getLayoutParams().width = animWidth;
requestLayout();
}
}
But Still I don't knowl, why is ANIMATOR_DURATION_SCALE flag not working in Marshmallow.
Related
How can I determine the direction of a vertical ScrollView?
I need to hide and display another linear layout accoding to scrollview scroll
You can use the onScrollChanged(int l, int t, int oldl, int oldt) method for that. As there isn't a setter for a listener, but just that method, you will have to create your own ScrollView class and override that method and do your thing in your implementation.
public class ObservableScrollView extends ScrollView {
private static final int DEFAULT_THRESHOLD_DP = 4;
private ScrollDirectionListener scrollDirectionListener;
private int scrollThreshold;
public ObservableScrollView(Context context) {
this(context, null);
}
public ObservableScrollView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ObservableScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
scrollThreshold = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_THRESHOLD_DP, context.getResources().getDisplayMetrics());
}
#Override
protected void onScrollChanged(int x, int y, int oldX, int oldY) {
super.onScrollChanged(x, y, oldX, oldY);
if (Math.abs(y - oldY) > scrollThreshold && scrollDirectionListener != null) {
if (y > oldY) {
scrollDirectionListener.onScrollUp(Math.abs(y - oldY));
} else {
scrollDirectionListener.onScrollDown(Math.abs(y - oldY));
}
}
}
public void setScrollThresholdInPx(int px) {
scrollThreshold = px;
}
public void setScrollThresholdInDp(Context context, float dp) {
scrollThreshold = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}
public void setOnScrollDirectionListener(ScrollDirectionListener listener) {
scrollDirectionListener = listener;
}
public interface ScrollDirectionListener {
void onScrollDown(int pixels);
void onScrollUp(int pixels);
}}
got answer :) use this custom scrollview
ScrollView.setOnScrollDirectionListener(new ObservableScrollView.ScrollDirectionListener() {
#Override
public void onScrollDown(int pixels) {
contenttool.setVisibility(View.INVISIBLE);
}
#Override
public void onScrollUp(int pixels) {
contenttool.setVisibility(View.VISIBLE);
}
});
I need to create the following layout to my viewpager:
I'm using PageContainer:
public class PagerContainer extends FrameLayout implements ViewPager.OnPageChangeListener{
private ViewPager mPager;
boolean mNeedsRedraw = false;
public PagerContainer(Context context)
{
super(context);
init();
}
public PagerContainer(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public PagerContainer(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
private void init()
{
// Disable clipping of children so non-selected pages are visible
setClipChildren(false);
// Child clipping doesn't work with hardware acceleration in Android
// 3.x/4.x
// You need to set this value here if using hardware acceleration in an
// application targeted at these releases.
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
#Override
protected void onFinishInflate()
{
try
{
mPager = (ViewPager) getChildAt(0);
mPager.setOnPageChangeListener(this);
} catch (Exception e)
{
throw new IllegalStateException("The root child of PagerContainer must be a ViewPager");
}
}
public ViewPager getViewPager()
{
return mPager;
}
private Point mCenter = new Point();
private Point mInitialTouch = new Point();
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
mCenter.x = w / 2;
mCenter.y = h / 2;
}
#Override
public boolean onTouchEvent(MotionEvent ev)
{
// We capture any touches not already handled by the ViewPager
// to implement scrolling from a touch outside the pager bounds.
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mInitialTouch.x = (int) ev.getX();
mInitialTouch.y = (int) ev.getY();
default:
ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y);
break;
}
return mPager.dispatchTouchEvent(ev);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
// Force the container to redraw on scrolling.
// Without this the outer pages render initially and then stay static
if (mNeedsRedraw)
invalidate();
}
#Override
public void onPageSelected(int position)
{}
#Override
public void onPageScrollStateChanged(int state)
{
mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE);
}
`
And seting like this:
PagerContainer mContainer = (PagerContainer) mainView.findViewById(R.id.pagerContainer);
pager = mContainer.getViewPager();
pager.setOffscreenPageLimit(pagerAdapter.getCount());
pager.setPageMargin(getPx(20));
pager.setClipChildren(false);
But the side pages has the same size of the active page.
I've tried to use pager.setPageMargin but only sets margim between pages.
Can someone help me?
you need a PageTransfomer for that the changes the scale of the page on the left and on the right of the central one. When you implement the interface you'll be forced to implement the
public void transformPage (View page, float position) {
}
page is the current ViewPager's page, while float position is the position of page relative to the current center position of the pager. What you probably want is to change the scaleX and scaleY of page, when position is grater then 1 or less then -1. E.g.
public void transformPage (View page, float position) {
if (position > 1 || position < -1) {
ViewCompat.scaleX(page, 0.75f * paget.getWidth());
ViewCompat.scaleY(page, 0.75f * paget.getHeight());
} else if (position == 0) {
ViewCompat.scaleX(page, 1f);
ViewCompat.scaleY(page, 1f);
}
}
I have not the possibility to try it out so, please check for typo/cast.
In a project of mine, I have a custom HorizontalScrollView class that displays a line chart. It gets rid of all of the elements and then it adds a single ImageView as a child element. It works fine the first time, but if I were to change to other fragment and switch back to the fragment containing the line chart, the ImageView is not present, although the object is recreated exactly the same way as the first time. If I inspect it with the DDMS the ImageView is really not in the UI graph. Any ideas why?? I really need some help on that.
That is my code (from which I have omitted some irrelevant parts):
public class LineChartView extends HorizontalScrollView {
// Private Constants ...
// Private Fields...
public LineChartView(Context context) {
super(context);
init();
}
public LineChartView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LineChartView(Context context, float[] lineValues) {
super(context);
mLineValues = lineValues;
init();
}
public LineChartView(Context context, AttributeSet attrs, float[] lineValues) {
super(context, attrs);
mLineValues = lineValues;
init();
}
private void init() {
// Setting densityMultiplier
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
int pixelDensity = displayMetrics.densityDpi;
mDensityMultiplier = pixelDensity / DisplayMetrics.DENSITY_DEFAULT;
// Initalising Paints...
initChildElements();
}
private void initChildElements() {
removeAllViews();
// Adding the image view to the visual graph
mChartImage = new ImageView(getContext());
ViewGroup.LayoutParams chartLayoutParams = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mChartImage.setLayoutParams(chartLayoutParams);
addViewInLayout(mChartImage, 0, mChartImage.getLayoutParams(), true);
}
public void setLineValuesList(float[] lineValuesList) {
if (lineValuesList == null) {
mLineValues = new float[]{};
} else {
mLineValues = lineValuesList;
}
requestLayout();
invalidate();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mChartImage.setImageDrawable(renderLineChart(h, 1.5f)); // Calculate the bitmap with the same height
super.onSizeChanged(w, h, oldw, oldh);
}
private BitmapDrawable renderLineChart(int height, float scale) {
if (height <= 0 || mLineValues.length == 0)
return null;
// Drawing logic... (not really relevant)
return new BitmapDrawable(getContext().getResources(), resultBitmap);
}
private float calculateWidth(float distanceBetween) {
int strokeCount = mLineValues.length - 1;
return strokeCount * distanceBetween;
}
private float calculateDistanceToNextValue(float scale) {
return BASE_DISTANCE_BETWEEN_POINTS * mDensityMultiplier * scale;
}
}
I'm trying to make the following effect:
I have a custom ScrollView (in oder to get the onScrollChanged listener) and a custom View inside it. In the custom View I succeed to place the item as I want.
Here my customView:
public class CustomView extends FrameLayout {
private TextView nameView;
private TextView emailView;
private ImageView addressView;
private Tracks track ;
private double scrollProgress = 0.0;
private double topViewScaleFactor = 2.0;
private double collapsedViewHeight = 200.0;
private double expandedViewHeight = 700.0;
private double scrollProgressPerView = expandedViewHeight;
View v;
View firstItem;
View secondView;
int itemMinHeight = 200;
int itemMaxHeight = 700;
public CustomView(MyScrollView paramEventListView, Context paramContext){
super(paramContext);
}
public CustomView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
int m = getMeasuredWidth();
int itemWidth = (r-l)/getChildCount();
// int itemHeight = (b-t)/getChildCount();
firstItem = getChildAt(0);
//firstItem.layout(0, 0, r-l, itemMaxHeight);
firstItem.measure(View.MeasureSpec.makeMeasureSpec(m, MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(itemMaxHeight, MeasureSpec.EXACTLY));
firstItem.layout(0, 0, r-l, itemMaxHeight);
secondView = getChildAt(1);
secondView.measure(View.MeasureSpec.makeMeasureSpec(m, MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(itemMinHeight, MeasureSpec.EXACTLY));
secondView.layout(0, itemMaxHeight, r-l, itemMinHeight+itemMaxHeight);
int FirstAndSEcondItemHeight = firstItem.getHeight() + secondView.getHeight();
for(int i=2; i< this.getChildCount(); i++){
v = getChildAt(i);
// v.layout(itemWidth*i, 0, (i+1)*itemWidth, b-t);
v.layout(0, FirstAndSEcondItemHeight + (itemMinHeight*(i-2)), r-l, FirstAndSEcondItemHeight + ((i-1)*itemMinHeight));
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int heightMeasured = 0;
/*for each child get height and
heightMeasured += childHeight;*/
for(int i=0; i< this.getChildCount(); i++){
heightMeasured += getChildAt(i).getHeight();
}
//If I am in a scrollview i got heightmeasurespec == 0, so
if(heightMeasureSpec == 0){
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightMeasured, MeasureSpec.EXACTLY);
}
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(this.getSuggestedMinimumHeight(), heightMeasureSpec));
}
Here my Custom ScrollView:
public class MyScrollView extends ScrollView{
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
add(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
#Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
// How can I acces to each child in the customView class, and change their height depending on the scrollChanged
}
But now I need to change the item height when I scroll the scrollview. I don't know what to put in the onScrollChanged...
If someone has an idea?
Thanks
Perhaps you want to force the view to redraw by calling invalidate()?
From comment: I think you need to move your code in the onMeasure method to replace the "TODO" stub, so that super.onMeasure() is called after your manipulations. And make sure you're passing the new width/height calculations to it.
By default scrollview's fading edge is visible only if it is possible to scroll in that direction. How can I make it visible at all times?
I don't want to put any drawables on top or something like that. I want to accomplish it using the builtin fading edge, probably by overriding some scrollview functions.
Yes, extend ScrollView and override these methods (based on Donut-release2):
#Override
protected float getTopFadingEdgeStrength() {
if (getChildCount() == 0) {
return 0.0f;
}
return 1.0f;
}
#Override
protected float getBottomFadingEdgeStrength() {
if (getChildCount() == 0) {
return 0.0f;
}
return 1.0f;
}
For comparison's sake, this is the original code, which shortens the fading edge as you get close to the end of the list:
#Override
protected float getTopFadingEdgeStrength() {
if (getChildCount() == 0) {
return 0.0f;
}
final int length = getVerticalFadingEdgeLength();
if (mScrollY < length) {
return mScrollY / (float) length;
}
return 1.0f;
}
#Override
protected float getBottomFadingEdgeStrength() {
if (getChildCount() == 0) {
return 0.0f;
}
final int length = getVerticalFadingEdgeLength();
final int bottomEdge = getHeight() - mPaddingBottom;
final int span = getChildAt(0).getBottom() - mScrollY - bottomEdge;
if (span < length) {
return span / (float) length;
}
return 1.0f;
}
You can also use the following code:
public class TopFadeEdgeScrollView extends ScrollView {
public TopFadeEdgeScrollView(Context context) {
super(context);
}
public TopFadeEdgeScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TopFadeEdgeScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected float getBottomFadingEdgeStrength() {
return 0.0f;
}
}