Android - Toolbar goes above Statusbar on Listview scroll - android

I am trying to hide the toolbar when a listview is scrolled, using Coordinator Layout. I've used app:layout_scrollFlags="scroll|enterAlways" on my toolbar, and android:nestedScrollingEnabled="true" in my listview.
The toolbar hides correctly when I scroll down my listview, but it goes 'above' the statusbar. In web development terminology, it looks like the 'Z-Index' of the toolbar is higher than the statusbar. This is how it looks -
Here is my activity_main.xml
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" android:id="#+id/main_content"
android:layout_width="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" tools:context=".MainActivity"
android:background="#FFFFFF" >
<android.support.design.widget.AppBarLayout android:id="#+id/appbar"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar android:id="#+id/toolbar"
android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" app:popupTheme="#style/AppTheme.PopupOverlay"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager android:id="#+id/container"
android:layout_width="match_parent" android:layout_height="match_parent"
android:background="#FFFFFF"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
Here is my fragment_main.xml code
<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:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity$PlaceholderFragment">
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollingCache="false"
android:nestedScrollingEnabled="true" />
</RelativeLayout>
How do I fix this problem? Thanks in advance!
UPDATE: I've posted my answer below! Check for the accepted answer.

I finally fixed this. If anyone else if stuck here, this is how I fixed it. No need to change your layouts to Recyclerview and all! Here are the steps.
1) Set the fitsSystemWindows to false for the CoordinatorLayout.
android:fitsSystemWindows="false"
2) Now, my status bar turned white. To fix this, add the following lines to your onCreate method in MainActivity.java
Window window = getWindow();
// clear FLAG_TRANSLUCENT_STATUS flag:
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
// finally change the color
window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
Voila! Now everything works perfect.
Here is my activity_main.xml contents, in case I missed something.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay"
app:contentScrim="#color/colorPrimaryDark"
app:layout_scrollFlags="scroll|enterAlways">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="#style/AppTheme.PopupOverlay"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout android:id="#+id/tabs"
android:layout_width="match_parent" android:layout_height="wrap_content"
app:tabIndicatorColor="#android:color/white"
app:tabIndicatorHeight="3dp"
android:textStyle="bold"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />

Why do you have AppBarlayout and toolbar layout if you do not want a toolbar that expands and contracts? basically that AppBarlayout is used when one wants it to be expanding and contracting and it used with a android.support.v4.widget.NestedScrollView so chances are the issue is coming up from there, they are not compatible, you could use a android.support.v7.widget.RecyclerViewin place of the listview and the viewpager has the attribute appbar_scrolling_view_behavior which triggers the appbarlayout to start listening for scroll inputs, I archieve having a normal behaving toolbar by not having AppBarlayout but only toolbar so you could remove the AppBarlayout, looking at things it is not really needed, since you happen to want it to expand and contract below is a sample of how your code should look like
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/scrollableview"
android:layout_width="match_parent"
android:visibility="gone"
android:background="#FFFFFF"
android:paddingTop="?attr/actionBarSize"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<!-- Your content, maybe a ListView? -->
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/fab_margin"
android:clickable="true"
android:id="#+id/fabAddItem"
android:src="#drawable/ic_action_add"
app:backgroundTint="#color/google_lightblue"
app:layout_anchor="#+id/toolbar"
app:layout_anchorGravity="bottom|right|end" />
<aubry.chromio.com.dressup.view.CollapsingTitleLayout
android:id="#+id/backdrop_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="#style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
app:expandedTextSize="40dp"
app:expandedMargin="16dp">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent" />
</aubry.chromio.com.dressup.view.CollapsingTitleLayout>
</FrameLayout>
and here is my CollapingsTitleLayout
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.Toolbar;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import aubry.chromio.com.dressup.R;
public class CollapsingTitleLayout extends FrameLayout {
// Pre-JB-MR2 doesn't support HW accelerated canvas scaled text so we will workaround it
// by using our own texture
private static final boolean USE_SCALING_TEXTURE = Build.VERSION.SDK_INT < 18;
private static final boolean DEBUG_DRAW = false;
private static final Paint DEBUG_DRAW_PAINT;
static {
DEBUG_DRAW_PAINT = DEBUG_DRAW ? new Paint() : null;
if (DEBUG_DRAW_PAINT != null) {
DEBUG_DRAW_PAINT.setAntiAlias(true);
DEBUG_DRAW_PAINT.setColor(Color.MAGENTA);
}
}
private Toolbar mToolbar;
private View mDummyView;
private float mScrollOffset;
private final Rect mToolbarContentBounds;
private float mExpandedMarginLeft;
private float mExpandedMarginRight;
private float mExpandedMarginBottom;
private int mRequestedExpandedTitleTextSize;
private int mExpandedTitleTextSize;
private int mCollapsedTitleTextSize;
private float mExpandedTop;
private float mCollapsedTop;
private String mTitle;
private String mTitleToDraw;
private boolean mUseTexture;
private Bitmap mExpandedTitleTexture;
private float mTextLeft;
private float mTextRight;
private float mTextTop;
private float mScale;
private final TextPaint mTextPaint;
private Paint mTexturePaint;
private Interpolator mTextSizeInterpolator;
public CollapsingTitleLayout(Context context) {
this(context, null);
}
public CollapsingTitleLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CollapsingTitleLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CollapsingTitleLayout);
mExpandedMarginLeft = mExpandedMarginRight = mExpandedMarginBottom =
a.getDimensionPixelSize(R.styleable.CollapsingTitleLayout_expandedMargin, 0);
final boolean isRtl = ViewCompat.getLayoutDirection(this)
== ViewCompat.LAYOUT_DIRECTION_RTL;
if (a.hasValue(R.styleable.CollapsingTitleLayout_expandedMarginStart)) {
final int marginStart = a.getDimensionPixelSize(
R.styleable.CollapsingTitleLayout_expandedMarginStart, 0);
if (isRtl) {
mExpandedMarginRight = marginStart;
} else {
mExpandedMarginLeft = marginStart;
}
}
if (a.hasValue(R.styleable.CollapsingTitleLayout_expandedMarginEnd)) {
final int marginEnd = a.getDimensionPixelSize(
R.styleable.CollapsingTitleLayout_expandedMarginEnd, 0);
if (isRtl) {
mExpandedMarginLeft = marginEnd;
} else {
mExpandedMarginRight = marginEnd;
}
}
if (a.hasValue(R.styleable.CollapsingTitleLayout_expandedMarginBottom)) {
mExpandedMarginBottom = a.getDimensionPixelSize(
R.styleable.CollapsingTitleLayout_expandedMarginBottom, 0);
}
final int tp = a.getResourceId(R.styleable.CollapsingTitleLayout_android_textAppearance,
android.R.style.TextAppearance);
setTextAppearance(tp);
if (a.hasValue(R.styleable.CollapsingTitleLayout_collapsedTextSize)) {
mCollapsedTitleTextSize = a.getDimensionPixelSize(
R.styleable.CollapsingTitleLayout_collapsedTextSize, 0);
}
mRequestedExpandedTitleTextSize = a.getDimensionPixelSize(
R.styleable.CollapsingTitleLayout_expandedTextSize, mCollapsedTitleTextSize);
final int interpolatorId = a
.getResourceId(R.styleable.CollapsingTitleLayout_textSizeInterpolator,
android.R.anim.accelerate_interpolator);
mTextSizeInterpolator = AnimationUtils.loadInterpolator(context, interpolatorId);
a.recycle();
mToolbarContentBounds = new Rect();
setWillNotDraw(false);
}
public void setTextAppearance(int resId) {
TypedArray atp = getContext().obtainStyledAttributes(resId,
R.styleable.CollapsingTextAppearance);
mTextPaint.setColor(atp.getColor(
R.styleable.CollapsingTextAppearance_android_textColor, Color.WHITE));
mCollapsedTitleTextSize = atp.getDimensionPixelSize(
R.styleable.CollapsingTextAppearance_android_textSize, 0);
atp.recycle();
recalculate();
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
if (child instanceof Toolbar) {
mToolbar = (Toolbar) child;
mDummyView = new View(getContext());
mToolbar.addView(mDummyView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
}
/**
* Set the value indicating the current scroll value. This decides how much of the
* background will be displayed, as well as the title metrics/positioning.
*
* A value of {#code 0.0} indicates that the layout is fully expanded.
* A value of {#code 1.0} indicates that the layout is fully collapsed.
*/
public void setScrollOffset(float offset) {
if (offset != mScrollOffset) {
mScrollOffset = offset;
calculateOffsets();
}
}
private void calculateOffsets() {
final float offset = mScrollOffset;
final float textSizeOffset = mTextSizeInterpolator != null
? mTextSizeInterpolator.getInterpolation(mScrollOffset)
: offset;
mTextLeft = interpolate(mExpandedMarginLeft, mToolbarContentBounds.left, offset);
mTextTop = interpolate(mExpandedTop, mCollapsedTop, offset);
mTextRight = interpolate(getWidth() - mExpandedMarginRight, mToolbarContentBounds.right, offset);
setInterpolatedTextSize(
interpolate(mExpandedTitleTextSize, mCollapsedTitleTextSize, textSizeOffset));
ViewCompat.postInvalidateOnAnimation(this);
}
private void calculateTextBounds() {
final DisplayMetrics metrics = getResources().getDisplayMetrics();
// We then calculate the collapsed text size, using the same logic
mTextPaint.setTextSize(mCollapsedTitleTextSize);
float textHeight = mTextPaint.descent() - mTextPaint.ascent();
float textOffset = (textHeight / 2) - mTextPaint.descent();
mCollapsedTop = mToolbarContentBounds.centerY() + textOffset;
// First, let's calculate the expanded text size so that it fit within the bounds
// We make sure this value is at least our minimum text size
mExpandedTitleTextSize = (int) Math.max(mCollapsedTitleTextSize,
getSingleLineTextSize(mTitle, mTextPaint,
getWidth() - mExpandedMarginLeft -mExpandedMarginRight, 0f,
mRequestedExpandedTitleTextSize, 0.5f, metrics));
mExpandedTop = getHeight() - mExpandedMarginBottom;
// The bounds have changed so we need to clear the texture
clearTexture();
}
#Override
public void draw(Canvas canvas) {
final int saveCount = canvas.save();
final int toolbarHeight = mToolbar.getHeight();
canvas.clipRect(0, 0, canvas.getWidth(),
interpolate(canvas.getHeight(), toolbarHeight, mScrollOffset));
// Now call super and let it draw the background, etc
super.draw(canvas);
if (mTitleToDraw != null) {
float x = mTextLeft;
float y = mTextTop;
final float ascent = mTextPaint.ascent() * mScale;
final float descent = mTextPaint.descent() * mScale;
final float h = descent - ascent;
if (DEBUG_DRAW) {
// Just a debug tool, which drawn a Magneta rect in the text bounds
canvas.drawRect(mTextLeft,
y - h + descent,
mTextRight,
y + descent,
DEBUG_DRAW_PAINT);
}
if (mUseTexture) {
y = y - h + descent;
}
if (mScale != 1f) {
canvas.scale(mScale, mScale, x, y);
}
if (mUseTexture && mExpandedTitleTexture != null) {
// If we should use a texture, draw it instead of text
canvas.drawBitmap(mExpandedTitleTexture, x, y, mTexturePaint);
} else {
canvas.drawText(mTitleToDraw, x, y, mTextPaint);
}
}
canvas.restoreToCount(saveCount);
}
private void setInterpolatedTextSize(final float textSize) {
if (mTitle == null) return;
if (isClose(textSize, mCollapsedTitleTextSize) || isClose(textSize, mExpandedTitleTextSize)
|| mTitleToDraw == null) {
// If the text size is 'close' to being a decimal, then we use this as a sync-point.
// We disable our manual scaling and set the paint's text size.
mTextPaint.setTextSize(textSize);
mScale = 1f;
// We also use this as an opportunity to ellipsize the string
final CharSequence title = TextUtils.ellipsize(mTitle, mTextPaint,
mTextRight - mTextLeft,
TextUtils.TruncateAt.END);
if (title != mTitleToDraw) {
// If the title has changed, turn it into a string
mTitleToDraw = title.toString();
}
if (USE_SCALING_TEXTURE && isClose(textSize, mExpandedTitleTextSize)) {
ensureExpandedTexture();
}
mUseTexture = false;
} else {
// We're not close to a decimal so use our canvas scaling method
if (mExpandedTitleTexture != null) {
mScale = textSize / mExpandedTitleTextSize;
} else {
mScale = textSize / mTextPaint.getTextSize();
}
mUseTexture = USE_SCALING_TEXTURE;
}
ViewCompat.postInvalidateOnAnimation(this);
}
private void ensureExpandedTexture() {
if (mExpandedTitleTexture != null) return;
int w = (int) (getWidth() - mExpandedMarginLeft - mExpandedMarginRight);
int h = (int) (mTextPaint.descent() - mTextPaint.ascent());
mExpandedTitleTexture = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(mExpandedTitleTexture);
c.drawText(mTitleToDraw, 0, h - mTextPaint.descent(), mTextPaint);
if (mTexturePaint == null) {
// Make sure we have a paint
mTexturePaint = new Paint();
mTexturePaint.setAntiAlias(true);
mTexturePaint.setFilterBitmap(true);
}
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mToolbarContentBounds.left = mDummyView.getLeft();
mToolbarContentBounds.top = mDummyView.getTop();
mToolbarContentBounds.right = mDummyView.getRight();
mToolbarContentBounds.bottom = mDummyView.getBottom();
if (changed && mTitle != null) {
// If we've changed and we have a title, re-calculate everything!
recalculate();
}
}
private void recalculate() {
if (getHeight() > 0) {
calculateTextBounds();
calculateOffsets();
}
}
/**
* Set the title to display
*
* #param title
*/
public void setTitle(String title) {
if (title == null || !title.equals(mTitle)) {
mTitle = title;
clearTexture();
if (getHeight() > 0) {
// If we've already been laid out, calculate everything now otherwise we'll wait
// until a layout
recalculate();
}
}
}
private void clearTexture() {
if (mExpandedTitleTexture != null) {
mExpandedTitleTexture.recycle();
mExpandedTitleTexture = null;
}
}
/**
* Recursive binary search to find the best size for the text
*
* Adapted from https://github.com/grantland/android-autofittextview
*/
private static float getSingleLineTextSize(String text, TextPaint paint, float targetWidth,
float low, float high, float precision, DisplayMetrics metrics) {
final float mid = (low + high) / 2.0f;
paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, mid, metrics));
final float maxLineWidth = paint.measureText(text);
if ((high - low) < precision) {
return low;
} else if (maxLineWidth > targetWidth) {
return getSingleLineTextSize(text, paint, targetWidth, low, mid, precision, metrics);
} else if (maxLineWidth < targetWidth) {
return getSingleLineTextSize(text, paint, targetWidth, mid, high, precision, metrics);
} else {
return mid;
}
}
/**
* Returns true if {#code value} is 'close' to it's closest decimal value. Close is currently
* defined as it's difference being < 0.01.
*/
private static boolean isClose(float value, float targetValue) {
return Math.abs(value - targetValue) < 0.01f;
}
/**
* Interpolate between {#code startValue} and {#code endValue}, using {#code progress}.
*/
private static float interpolate(float startValue, float endValue, float progress) {
return startValue + ((endValue - startValue) * progress);
}
}

Related

Bottom sheet scrollable content in middle in Android

I am facing 1 issue with BottomSheet in Android. What I am trying to achieve :
BottomSheet Google Direction
But I am not able to implement ListView with header and footer like google.
The main issue is ListView shows all the items and my bottom sheet not displaying footer view. I want to always visible the bottom view of my bottom sheet.
If the footer is your main problem here's a simple solution:
Add the footer View as a direct child of your BottomSheet
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#EECCCCCC"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<TextView
android:id="#+id/pinned_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#500000FF"
android:padding="16dp"
android:text="Bottom" />
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Add a BottomSheetCallback and adjust the footer's translationY in onSlide()
BottomSheetBehavior.from(bottom_sheet).addBottomSheetCallback(
object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val bottomSheetVisibleHeight = bottomSheet.height - bottomSheet.top
pinned_bottom.translationY =
(bottomSheetVisibleHeight - pinned_bottom.height).toFloat()
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
}
})
It runs smoothly because you're simply changing the translationY.
You can also use this technique to pin a View in the center of the BottomSheet:
pinned_center.translationY = (bottomSheetVisibleHeight - pinned_center.height) / 2f
I've made a sample project on GitHub to reproduce both use cases (pinned to center and bottom): https://github.com/dadouf/BottomSheetGravity
I have created sample example to achieve bottom sheet as google direction that will floating
on any ui and working will be same as google direction swipable view. I achieved it using
"ViewDragHelper" class(https://developer.android.com/reference/android/support/v4/widget/ViewDragHelper)
Here is the sample what i achieved with "ViewDragHelper" same as google direction swipable view:
Note: In below example, there is hard coded strings as well a single
adapter taken only in swipable view class and also taken static list.
Anyone can customize it with proper code format as well
getter/setters. This is for example only to taught how
"ViewDragHelper" works.
First create "GoogleBottomSheet" class as below:
import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
public class GoogleBottomSheet extends ViewGroup {
private final ViewDragHelper mDragHelper;
GoogleRoutesAdapter googleRoutesAdapter;
private View mHeaderView;
private RecyclerView rvList;
private float mInitialMotionX;
private float mInitialMotionY;
private int mDragRange;
private int mTop;
private float mDragOffset;
public GoogleBottomSheet(Context context) {
this(context, null);
}
public GoogleBottomSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mHeaderView = findViewById(R.id.viewHeader);
rvList = findViewById(R.id.rvList);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
rvList.setLayoutManager(linearLayoutManager);
ArrayList<String> allRoutesList = new ArrayList<>();
allRoutesList.add("47 Bourbon Li");
allRoutesList.add("Head South");
allRoutesList.add("Princess Street");
allRoutesList.add("A 3-lane partially one-way street heading out of Manchester city centre");
allRoutesList.add("Manchester Jewish Museum, \n" +
"Peninsula Building");
allRoutesList.add("Portland Street");
allRoutesList.add("Quay Street");
allRoutesList.add("Forms part of the city's historic Northern Quarter district");
allRoutesList.add("Sackville Street Building, University of Manchester including the Godlee Observatory");
allRoutesList.add("Turn Left on S Naper");
allRoutesList.add("150 W-Stall");
allRoutesList.add("Former National Westminster Bank");
allRoutesList.add("Bradshaw, L. D.");
allRoutesList.add("House of Commons Transport Committee");
allRoutesList.add("A street only for Metrolink trams and previously buses which joined the street at Lower Mosley Street.");
googleRoutesAdapter = new GoogleRoutesAdapter(getContext(), allRoutesList);
rvList.setAdapter(googleRoutesAdapter);
}
public GoogleBottomSheet(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDragHelper = ViewDragHelper.create(this, 1f, new DragHelperCallback());
}
public void maximize() {
smoothSlideTo(0f);
}
boolean smoothSlideTo(float slideOffset) {
final int topBound = getPaddingTop();
int y = (int) (topBound + slideOffset * mDragRange);
if (mDragHelper.smoothSlideViewTo(mHeaderView, mHeaderView.getLeft(), y)) {
ViewCompat.postInvalidateOnAnimation(this);
return true;
}
return false;
}
private class DragHelperCallback extends ViewDragHelper.Callback {
#Override
public boolean tryCaptureView(View child, int pointerId) {
return child == mHeaderView;
}
#Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
mTop = top;
mDragOffset = (float) top / mDragRange;
requestLayout();
}
#Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
int top = getPaddingTop();
if (yvel > 0 || (yvel == 0 && mDragOffset > 0.5f)) {
top += mDragRange;
}
mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top);
}
#Override
public int getViewVerticalDragRange(View child) {
return mDragRange;
}
#Override
public int clampViewPositionVertical(View child, int top, int dy) {
final int topBound = getPaddingTop();
final int bottomBound = getHeight() - mHeaderView.getHeight();
final int newTop = Math.min(Math.max(top, topBound), bottomBound);
return newTop;
}
}
#Override
public void computeScroll() {
if (mDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
if ((action != MotionEvent.ACTION_DOWN)) {
mDragHelper.cancel();
return super.onInterceptTouchEvent(ev);
}
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mDragHelper.cancel();
return false;
}
final float x = ev.getX();
final float y = ev.getY();
boolean interceptTap = false;
switch (action) {
case MotionEvent.ACTION_DOWN: {
mInitialMotionX = x;
mInitialMotionY = y;
interceptTap = mDragHelper.isViewUnder(mHeaderView, (int) x, (int) y);
break;
}
case MotionEvent.ACTION_MOVE: {
final float adx = Math.abs(x - mInitialMotionX);
final float ady = Math.abs(y - mInitialMotionY);
final int slop = mDragHelper.getTouchSlop();
if (ady > slop && adx > ady) {
mDragHelper.cancel();
return false;
}
}
}
return mDragHelper.shouldInterceptTouchEvent(ev) || interceptTap;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
mDragHelper.processTouchEvent(ev);
final int action = ev.getAction();
final float x = ev.getX();
final float y = ev.getY();
boolean isHeaderViewUnder = mDragHelper.isViewUnder(mHeaderView, (int) x, (int) y);
switch (action & MotionEventCompat.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
mInitialMotionX = x;
mInitialMotionY = y;
break;
}
case MotionEvent.ACTION_UP: {
final float dx = x - mInitialMotionX;
final float dy = y - mInitialMotionY;
final int slop = mDragHelper.getTouchSlop();
if (dx * dx + dy * dy < slop * slop && isHeaderViewUnder) {
if (mDragOffset == 0) {
smoothSlideTo(1f);
} else {
smoothSlideTo(0f);
}
}
break;
}
}
return isHeaderViewUnder && isViewHit(mHeaderView, (int) x, (int) y) ||
isViewHit(rvList, (int) x, (int) y);
}
private boolean isViewHit(View view, int x, int y) {
int[] viewLocation = new int[2];
view.getLocationOnScreen(viewLocation);
int[] parentLocation = new int[2];
this.getLocationOnScreen(parentLocation);
int screenX = parentLocation[0] + x;
int screenY = parentLocation[1] + y;
return screenX >= viewLocation[0] && screenX < viewLocation[0] + view.getWidth() &&
screenY >= viewLocation[1] && screenY < viewLocation[1] + view.getHeight();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0),
resolveSizeAndState(maxHeight, heightMeasureSpec, 0));
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mDragRange = getHeight() - mHeaderView.getHeight();
mHeaderView.layout(
0,
mTop,
r,
mTop + mHeaderView.getMeasuredHeight());
rvList.layout(
0,
mTop + mHeaderView.getMeasuredHeight(),
r,
mTop + b);
}
}
Create xml file named as "rawitem_mapdetails.xml" for recyclerview viewholder item as below:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/mTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimaryDark"
android:text="Route 1"
android:padding="#dimen/_10sdp"
android:textColor="#android:color/white"
android:textSize="#dimen/_15sdp" />
</RelativeLayout>
</LinearLayout>
Create simple adapter named "GoogleRoutesAdapter" for recyclerview as below:
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class GoogleRoutesAdapter extends RecyclerView.Adapter<GoogleRoutesAdapter.GoogleRouteViewHolder> {
private Context mContext;
private ArrayList<String> allRoutesList;
public GoogleRoutesAdapter(Context context, ArrayList<String> allRoutesList) {
this.mContext = context;
this.allRoutesList = allRoutesList;
}
#Override
public GoogleRouteViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.rawitem_mapdetails, null);
GoogleRouteViewHolder rcv = new GoogleRouteViewHolder(layoutView);
return rcv;
}
#Override
public void onBindViewHolder(final GoogleRouteViewHolder holder, final int position) {
holder.tvRoute.setText(allRoutesList.get(position));
}
#Override
public int getItemCount() {
return allRoutesList.size();
}
public class GoogleRouteViewHolder extends RecyclerView.ViewHolder {
private TextView tvRoute;
public GoogleRouteViewHolder(View view) {
super(view);
tvRoute = view.findViewById(R.id.mTextView);
tvRoute.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(mContext, allRoutesList.get(getAdapterPosition()), Toast.LENGTH_SHORT).show();
}
});
}
}
}
Create "activity_main.xml" as below for MainActivity as below:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.viewdraghelper.GoogleBottomSheet
android:id="#+id/my_googleBottomSheet"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/viewHeader"
android:layout_width="match_parent"
android:background="#color/colorAccent"
android:layout_height="#dimen/_80sdp"
android:textSize="#dimen/_25sdp"
android:padding="#dimen/_10sdp"
android:textColor="#android:color/white"
android:text="31 min (29 mi)"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/rvList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.viewdraghelper.GoogleBottomSheet>
</RelativeLayout>
Edited Answer based on requirements as below:
1. To get sliding panel at bottom/hidden as default state on view created first time
First take initOnce global boolean variable
private boolean initOnce = false;
Then change onLayout() method as below:
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if(!initOnce){
initOnce = true;
mDragRange = getHeight() - mHeaderView.getHeight();
mHeaderView.layout(
0,
b - mHeaderView.getMeasuredHeight(),
r,
b);
}else {
mDragRange = getHeight() - mHeaderView.getHeight();
mHeaderView.layout(
0,
mTop,
r,
mTop + mHeaderView.getMeasuredHeight());
rvList.layout(
0,
mTop + mHeaderView.getMeasuredHeight(),
r,
mTop + b);
}
}
Now all done! As i stated above that this is to only taught how "ViewDragHelper" works thats why we don't
have to do anything in MainActivity right now because all adapter logic resides in "GoogleBottomSheet" class.
I have also take one simple recyclerview item click so anyone can have better idea that other ui will work same
as its own behaviour. We can also customize by putting any ui in "GoogleBottomSheet".
Hope it helps! Happy Coding :)

CollapsingToolbarLayout Scrolling Bug -Sometimes it'll stuck when scrolled up

I'm creating a Scrolling Activity in my Android App. The Activity has a CollapsingToolbarLayout with parallax effect.
When I scroll the layout below the appbarlayout up, it'll go up smoothly and the appbarlayout will be collapsed up to the title.The ImageView and the TextView will go up to the title. And when I scroll the layout back down, they'll all go back down to the beginning.
The bug is here:
when I running the activity on some devices, sometimes when I scroll it up, the layout will be stucked there up and down for seconds and then, back go to the top.
And when I running the activity on some other devices, it'll be OK, nothing wrong happened.
The demo of this bug: https://share.weiyun.com/1d797a4a92580e1595eacb226f9a92a3
Here is the layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="nczz.cn.helloworld.ScrollingActivity"
>
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="#dimen/app_bar_height"
android:background="#FA7199"
app:layout_scrollFlags="scroll|enterAlways"
android:theme="#style/AppTheme.AppBarOverlay">
<nczz.cn.widget.CollapsingImageTextLayout
android:id="#+id/imageTextLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:title_id="#+id/test_title"
app:text_id="#+id/test_text"
app:img_scale="0.6"
app:text_scale="0.6"
app:text_margin_left="110dp"
app:img_id="#+id/test_img"
app:img_margin_left="55dp"
>
<LinearLayout
android:id="#+id/test_title"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="#FA7199"
android:gravity="center_vertical"
android:orientation="horizontal"
>
<ImageView
android:id="#+id/return_btn"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginLeft="20dp"
android:layout_centerVertical="true"
android:src="#drawable/left" />
</LinearLayout>
<ImageView
android:id="#+id/test_img"
android:layout_width="80dp"
android:layout_height="80dp"
android:scaleType="fitXY"
android:src="#mipmap/ic_launcher"
android:layout_centerInParent="true"
android:layout_marginBottom="30dp"
/>
<TextView
android:id="#+id/test_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/test_img"
android:text="MoveText"
android:textSize="20sp"
android:textColor="#android:color/white"
android:layout_marginTop="-20dp"
android:layout_marginLeft="50dp"
android:layout_centerInParent="true"
/>
</nczz.cn.widget.CollapsingImageTextLayout>
</android.support.design.widget.AppBarLayout>
<include
android:id="#+id/includelayout"
layout="#layout/content_scrolling"/>
</android.support.design.widget.CoordinatorLayout>
Here is the CollapsingImageTextLayout:
package nczz.cn.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.NonNull;
import android.support.design.widget.AppBarLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.RelativeLayout;
import nczz.cn.helloworld.R;
/**
* Created by yahui.hu on 2017/4/21.
*/
public class CollapsingImageTextLayout extends RelativeLayout {
private AppBarLayout.OnOffsetChangedListener mOffsetChangedListener;
private int mTitleId, mTextId, mImageId;
private int mTitleMarginLeft, mTitleMarginTop, mImgMarginLeft, mImgMarginTop;
private float mTextScale, mImgScale;
private View mTitle, mImg, mText;
private boolean isGetView = true;
private int mTitleHeight = 0;
public CollapsingImageTextLayout(Context context) {
this(context, null);
}
public CollapsingImageTextLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CollapsingImageTextLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CollapsingImageLayout, defStyleAttr, 0);
mTitleId = a.getResourceId(R.styleable.CollapsingImageLayout_title_id, 0);
mTextId = a.getResourceId(R.styleable.CollapsingImageLayout_text_id, 0);
mImageId = a.getResourceId(R.styleable.CollapsingImageLayout_img_id, 0);
mTextScale = a.getFloat(R.styleable.CollapsingImageLayout_text_scale, 0.4f);
mImgScale = a.getFloat(R.styleable.CollapsingImageLayout_img_scale, 0.4f);
mTitleMarginLeft = a.getDimensionPixelSize(R.styleable.CollapsingImageLayout_text_margin_left, 0);
mTitleMarginTop = a.getDimensionPixelSize(R.styleable.CollapsingImageLayout_text_margin_top, 0);
mImgMarginLeft = a.getDimensionPixelSize(R.styleable.CollapsingImageLayout_img_margin_left, 0);
mImgMarginTop = a.getDimensionPixelSize(R.styleable.CollapsingImageLayout_img_margin_top, 0);
a.recycle();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
getView();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void getView() {
if (!isGetView) {
return;
}
if (mTitleId != 0) {
mTitle = findViewById(mTitleId);
}
if (mTextId != 0) {
mText = findViewById(mTextId);
}
if (mImageId != 0) {
mImg = findViewById(mImageId);
}
isGetView = false;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (mTitle != null) {
getViewOffsetHelper(mTitle).onViewLayout(0, 0);
setMinimumHeight(getHeightWithMargins(mTitle));
mTitleHeight = mTitle.getHeight();
this.bringChildToFront(mTitle);
}
if (mImg != null) {
getViewOffsetHelper(mImg).onViewLayout(mImgMarginLeft, mImgMarginTop);
this.bringChildToFront(mImg);
}
if (mText != null) {
getViewOffsetHelper(mText).onViewLayout(mTitleMarginLeft, mTitleMarginTop);
this.bringChildToFront(mText);
}
}
static ViewHelper getViewOffsetHelper(View view) {
ViewHelper offsetHelper = (ViewHelper) view.getTag(R.id.view_helper);
if (offsetHelper == null) {
offsetHelper = new ViewHelper(view);
view.setTag(R.id.view_helper, offsetHelper);
}
return offsetHelper;
}
private static int getHeightWithMargins(#NonNull final View view) {
final ViewGroup.LayoutParams lp = view.getLayoutParams();
if (lp instanceof MarginLayoutParams) {
final MarginLayoutParams mlp = (MarginLayoutParams) lp;
return view.getHeight() + mlp.topMargin + mlp.bottomMargin;
}
return view.getHeight();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
ViewParent viewParent = getParent();
if (viewParent instanceof AppBarLayout) {
if (mOffsetChangedListener == null) mOffsetChangedListener = new OffsetListenerImp();
((AppBarLayout) viewParent).addOnOffsetChangedListener(mOffsetChangedListener);
}
}
#Override
protected void onDetachedFromWindow() {
ViewParent viewParent = getParent();
if (viewParent instanceof AppBarLayout) {
((AppBarLayout) viewParent).removeOnOffsetChangedListener(mOffsetChangedListener);
}
super.onDetachedFromWindow();
}
final int getMaxOffsetForPinChild(View child) {
final ViewHelper offsetHelper = getViewOffsetHelper(child);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
return getHeight()
- offsetHelper.getLayoutTop()
- child.getHeight()
- lp.bottomMargin;
}
static int constrain(int amount, int low, int high) {
return amount < low ? low : (amount > high ? high : amount);
}
static int constrain(int amount, int low) {
return amount < low ? low : amount;
}
private void setTopAndBottomOffset(View child, int verticalOffset) {
ViewHelper viewHelper = (ViewHelper) child.getTag(R.id.view_helper);
viewHelper.setTopAndBottomOffset(
constrain(-verticalOffset, 0, getMaxOffsetForPinChild(child)));
Log.e("setTopAndBottomOffset",""+-verticalOffset);
}
private void setTopAndBottomOffset(View child, int verticalOffset, float scale) {
ViewHelper viewHelper = (ViewHelper) child.getTag(R.id.view_helper);
viewHelper.setTopAndBottomOffset(
constrain(-verticalOffset - getMaxOffset(viewHelper, scale),
0));
//Log.e("setTopAndBottomOffset",""+-verticalOffset);
}
private void setLeftAndRightOffset(View child, int verticalOffset, float scale) {
ViewHelper viewHelper = (ViewHelper) child.getTag(R.id.view_helper);
int maxOffsetDistance = getMaxOffset(viewHelper, scale);
int maxLeft = viewHelper.getLayoutLeft()
+ (viewHelper.getViewWidth() - viewHelper.getScaleViewWidth(scale))
- viewHelper.getMarginTitleLeft();
int realOffset = (int) (maxLeft * 1.0f / (maxOffsetDistance * 1.0f) * verticalOffset);
realOffset = constrain(realOffset, -maxLeft, maxLeft);
viewHelper.setLeftAndRightOffset(realOffset);
// Log.e("setLeftAndRightOffset",""+realOffset);
}
private void setViewScale(View child, int verticalOffset, float scale) {
ViewHelper viewHelper = (ViewHelper) child.getTag(R.id.view_helper);
int maxOffsetDistance = getMaxOffset(viewHelper, scale);
float realScale = -verticalOffset - maxOffsetDistance > 0 ? scale : verticalOffset == 0 ? 1f : 0f;
if (realScale == 0) {
realScale = (maxOffsetDistance + verticalOffset * (1 - scale)) / (maxOffsetDistance * 1f);
}
viewHelper.setViewOffsetScale(realScale);
}
private int getMaxOffset(ViewHelper viewHelper, float scale) {
int scaleViewHeight = (int) (scale * viewHelper.getViewHeight());
int offsetTitleDistance = scaleViewHeight >= mTitleHeight ? 0 : (mTitleHeight - scaleViewHeight) / 2;
int marginTop = viewHelper.getMarginTitleTop() >= offsetTitleDistance ? offsetTitleDistance : viewHelper.getMarginTitleTop();
return viewHelper.getLayoutBottom() - viewHelper.getScaleViewHeight(scale) - offsetTitleDistance - marginTop;
}
private class OffsetListenerImp implements AppBarLayout.OnOffsetChangedListener {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (mTitle != null) {
setTopAndBottomOffset(mTitle, verticalOffset);
}
if (mText != null) {
setTopAndBottomOffset(mText, verticalOffset, mTextScale);
setLeftAndRightOffset(mText, verticalOffset, mTextScale);
setViewScale(mText, verticalOffset, mTextScale);
}
if (mImg != null) {
setTopAndBottomOffset(mImg, verticalOffset, mImgScale);
setLeftAndRightOffset(mImg, verticalOffset, mImgScale);
setViewScale(mImg, verticalOffset, mImgScale);
}
}
}
public void setImgTitleMarginTop(int top) {
if (mImg != null) {
getViewOffsetHelper(mImg).setMarginTitleTop(top);
}
}
public void setImgTitleMarginLeft(int left) {
if (mImg != null) {
getViewOffsetHelper(mImg).setMarginTitleLeft(left);
}
}
public void setTextTitleMarginTop(int top) {
if (mText != null) {
getViewOffsetHelper(mText).setMarginTitleTop(top);
}
}
public void setImgTextMarginLeft(int left) {
if (mText != null) {
getViewOffsetHelper(mText).setMarginTitleLeft(left);
}
}
}
Here is the content_scolling.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="#cccccc"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="nczz.cn.helloworld.ScrollingActivity"
tools:showIn="#layout/activity_scrolling">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/large_text" />
</android.support.v4.widget.NestedScrollView>
Here is the java:
package nczz.cn.helloworld;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
public class ScrollingActivity extends Activity {
LinearLayout titleTxt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_scrolling);
initViews();
setTitleBarHeight();
}
private void initViews(){
titleTxt= (LinearLayout) findViewById(R.id.test_title);
}
private void setTitleBarHeight(){
WindowManager manager=getWindowManager();
int height=manager.getDefaultDisplay().getHeight();
ViewGroup.LayoutParams params=titleTxt.getLayoutParams();
params.height=height/12;
titleTxt.setLayoutParams(params);
}
}
i am not sure but u can use following code according to view inside nested scrollview
viewlayoutInsidescrollview.setNestedScrollingEnabled(false);
in java class

Parallel animation in Imageview

I want to implement animation like the below image.
I have already used ThreePhaseBottomLibrary and as per my experience animation should go parallel as per above image when I scroll it up!
Below is my Fragment class. It works fine except this Image parallel animation as per the screen:
Myfragment.java
public class MyFragment extends BottomSheetFragment {
private BottomSheetLayout mBottomSheetLayout;
private ImageView mBottomSheetBackgroundImageView;
private int mBottomSheetHeight;
private ImageView movingIconImageView;
private AppBarLayout mAppBarLayout;
private int mMStartMarginBottom;
private int mMStartMarginLeft;
private Toolbar mToolbar;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_my, container, false);
mBottomSheetHeight = getResources().getDimensionPixelSize(R.dimen.header_height);
mAppBarLayout = (AppBarLayout) view.findViewById(R.id.appbar);
view.setMinimumHeight(getResources().getDisplayMetrics().heightPixels);
CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) view.findViewById(R.id.collapsing_toolbar);
//collapsingToolbar.setTitle("Title");
collapsingToolbar.setTitleEnabled(false);
mToolbar = (Toolbar) view.findViewById(R.id.toolbar);
//final AppCompatActivity activity = (AppCompatActivity) getActivity();
//activity.setSupportActionBar(toolbar);
//final ActionBar actionBar = activity.getSupportActionBar();
//actionBar.setDisplayHomeAsUpEnabled(true);
//actionBar.setTitle(null);
mToolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mBottomSheetLayout.dismissSheet();
}
});
mToolbar.setAlpha(0);
mBottomSheetBackgroundImageView = (ImageView) view.findViewById(R.id.backdrop);
mBottomSheetBackgroundImageView.setAlpha(0.0f);
movingIconImageView = (ImageView) view.findViewById(R.id.movingIconImageView);
Glide.with(this).load(R.drawable.cheese_1).centerCrop().into(mBottomSheetBackgroundImageView);
if (mBottomSheetLayout != null)
mBottomSheetLayout.setAppBarLayout(mAppBarLayout);
final int actionBarHeight = getActionBarHeight(getActivity());
mMStartMarginBottom = getResources().getDimensionPixelSize(R.dimen.header_view_start_margin_bottom);
mMStartMarginLeft = getResources().getDimensionPixelSize(R.dimen.header_view_start_margin_left);
movingIconImageView.setPivotX(0);
final float actionBarIconPadding = getResources().getDimensionPixelSize(R.dimen.action_bar_icon_padding);
mAppBarLayout.addOnOffsetChangedListener(new OnOffsetChangedListener() {
float startY = 0;
float scaleDiff = 0;
#Override
public void onOffsetChanged(final AppBarLayout appBarLayout, final int verticalOffset) {
if (mBottomSheetLayout != null && mBottomSheetLayout.isSheetShowing() && mBottomSheetLayout.getState() == State.EXPANDED) {
float progress = (float) -verticalOffset / mAppBarLayout.getTotalScrollRange();
movingIconImageView.setX(mMStartMarginLeft + (progress * (actionBarHeight - mMStartMarginLeft)));
if (startY == 0)
startY = movingIconImageView.getY();
if (scaleDiff == 0) {
scaleDiff = 1 - (actionBarHeight - actionBarIconPadding) / movingIconImageView.getHeight();
movingIconImageView.setPivotY(movingIconImageView.getHeight());
}
movingIconImageView.setScaleX(1f - progress * scaleDiff);
movingIconImageView.setScaleY(1f - progress * scaleDiff);
movingIconImageView.setY(startY - progress * actionBarIconPadding / 2 + mMStartMarginBottom * progress);
}
}
});
return view;
}
/**
* returns the height of the action bar
*/
public static int getActionBarHeight(final Context context) {
// based on http://stackoverflow.com/questions/12301510/how-to-get-the-actionbar-height
final TypedValue tv = new TypedValue();
int actionBarHeight = 0;
if (context.getTheme().resolveAttribute(R.attr.actionBarSize, tv, true))
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources()
.getDisplayMetrics());
return actionBarHeight;
}
public void setBottomSheetLayout(final BottomSheetLayout bottomSheetLayout) {
mBottomSheetLayout = bottomSheetLayout;
if (mBottomSheetLayout != null && mAppBarLayout != null)
mBottomSheetLayout.setAppBarLayout(mAppBarLayout);
mBottomSheetLayout.addOnSheetStateChangeListener(new OnSheetStateChangeListener() {
private ViewPropertyAnimator mToolbarAnimation;
State lastState;
#Override
public void onSheetStateChanged(final State state) {
if (lastState == state)
return;
lastState = state;
if (state != State.EXPANDED) {
if (mToolbarAnimation != null)
mToolbarAnimation.cancel();
mToolbarAnimation = null;
mToolbar.setAlpha(0);
mToolbar.setVisibility(View.INVISIBLE);
} else if (mToolbarAnimation == null) {
mToolbar.setVisibility(View.VISIBLE);
mToolbar.setTranslationY(-mToolbar.getHeight() / 3);
mToolbarAnimation = mToolbar.animate().setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
mToolbarAnimation.alpha(1).translationY(0).start();
}
}
});
}
#Override
public ViewTransformer getViewTransformer() {
return new BaseViewTransformer() {
private ViewPropertyAnimator mBottomSheetBackgroundImageViewFadeInAnimation, mBottomSheetBackgroundImageViewFadeOutAnimation;
private Float mOriginalContactPhotoXCoordinate = null;
private final float mOriginalBottomSheetBackgroundImageViewTranslationY = mBottomSheetBackgroundImageView.getTranslationY();
#Override
public void transformView(final float translation, final float maxTranslation, final float peekedTranslation, final BottomSheetLayout parent, final View view) {
if (mOriginalContactPhotoXCoordinate == null)
mOriginalContactPhotoXCoordinate = movingIconImageView.getX();
if (translation < mBottomSheetHeight)
return;
if (translation == mBottomSheetHeight) {
if (mBottomSheetBackgroundImageViewFadeInAnimation != null)
mBottomSheetBackgroundImageViewFadeInAnimation.cancel();
mBottomSheetBackgroundImageViewFadeInAnimation = null;
if (mBottomSheetBackgroundImageViewFadeOutAnimation == null)
mBottomSheetBackgroundImageViewFadeOutAnimation = mBottomSheetBackgroundImageView.animate().alpha(0);
} else {
if (mBottomSheetBackgroundImageViewFadeOutAnimation != null)
mBottomSheetBackgroundImageViewFadeOutAnimation.cancel();
mBottomSheetBackgroundImageViewFadeOutAnimation = null;
if (mBottomSheetBackgroundImageViewFadeInAnimation == null) {
mBottomSheetBackgroundImageViewFadeInAnimation = mBottomSheetBackgroundImageView.animate().alpha(1);
}
}
float progress = (translation - mBottomSheetHeight) / (maxTranslation - mBottomSheetHeight);
//Log.d("AppLog", "translation:" + translation + " maxTranslation:" + maxTranslation + " progress:" + progress);
//movingIconImageView.setY(progress * (mBottomSheetHeight - movingIconImageView.getHeight()));
movingIconImageView.setY(progress * (mBottomSheetHeight - movingIconImageView.getHeight() - mMStartMarginBottom));
movingIconImageView.setX(mOriginalContactPhotoXCoordinate - progress * (mOriginalContactPhotoXCoordinate - mMStartMarginLeft));
//mBottomSheetBackgroundImageView.setAlpha(progress);
mBottomSheetBackgroundImageView.setTranslationY(mOriginalBottomSheetBackgroundImageViewTranslationY - progress * mOriginalBottomSheetBackgroundImageViewTranslationY);
}
};
}
}
Here is my xml:-
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="#+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="#dimen/header_height"
android:background="#null">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="168dp"
android:layout_marginTop="40dp"
android:background="#eee">
</FrameLayout>
<ImageView
android:id="#+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:translationY="40dp"
app:layout_collapseMode="parallax"/>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:theme="#style/ToolbarColoredBackArrow"/>
<ImageView
android:id="#+id/movingIconImageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center_horizontal" android:background="#f00"
android:src="#drawable/test"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/window_color"
android:orientation="vertical"
android:paddingTop="24dp">
<include layout="#layout/junk_cardview"/>
<include layout="#layout/junk_cardview"/>
<include layout="#layout/junk_cardview"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<!--<android.support.design.widget.FloatingActionButton-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_margin="#dimen/fab_margin"-->
<!--android:clickable="true"-->
<!--android:src="#android:drawable/ic_menu_send"-->
<!--app:layout_anchor="#id/appbar"-->
<!--app:layout_anchorGravity="bottom|right|end"/>-->
I want my backdrop image to slide up which only fading out with slide!
Note: In the library sample I am getting ImageView alpha from 0 to 1 but I want to slide my imageUp not just animate as like alpha animation!
The image you posted is originally from a post about the design of the Google I/O app in 2014. A corresponding image showed what this motion would actually look like in practice [on the right]:
As stated in the article, the source for this app was made public on GitHub. I suggest you take a look at that code in order to get your answer. Though the source currently available is the 2015 version of the app, not the 2014 version mentioned in the article.

How to make first item height bigger in Listview when user scrolls in android [duplicate]

I am creating images in which when scrolled up, the image should get enlarged and remaining images should get smaller. Similarly when second image pushed up, it should enlarge and show. I used accordion type but nothing works. I searched but couldn't find.
In IPhone, it has features but I couldn't find how to create for android. This is for
same effect to be implemented in android.
I used ScaleAnimation with hide and show of layouts to open where image been placed inside the layout. But that also didn't work.
if(openLayout == panel1){
panel1.startAnimation(new ScaleAnimToHide(1.0f, 1.0f, 1.0f, 0.0f, 200, panel1, true));
}
Can someone help me to solve this issue?
Thanks in advance!!
I have created a basic custom view which replicates this behaviour, it's not completely the same but I think it's close enough for now, if it needs to be exactly the same this can be quickly achieved by modifying the updateChildViews() method. I wrote this class in 20 minutes so it's far from perfect, for a production ready solution some additional work has to be done. Generally this solution works with all kinds of child views, but to replicate the exact behaviour use an ImageView as background for your child views and set this property on the ImageViews:
android:scaleType="centerCrop"
Problems I see with my solution in it's current state:
Only works in vertical orientation
No view recycling.
Should be derived from AdapterView and not LinearLayout.
Anyway that's how it looks so far:
Here is the source code:
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
public class Accordion extends LinearLayout {
private static final String LOG_TAG = Accordion.class.getSimpleName();
private double scrollProgress = 0.0;
private double topViewScaleFactor = 2.0;
private double collapsedViewHeight = 200.0;
private double expandedViewHeight = 700.0;
private double scrollProgressPerView = expandedViewHeight;
private final ScrollTouchListener touchListener = new ScrollTouchListener() {
#Override
protected void onScroll(float x, float y) {
scrollProgress += y;
if(scrollProgress < 0.0) {
scrollProgress = 0.0;
}
int viewCount = getChildCount();
double maxScrollProgress = (viewCount - 1) * scrollProgressPerView + 1;
if(scrollProgress > maxScrollProgress) {
scrollProgress = maxScrollProgress;
}
Log.i(LOG_TAG, String.format("Scroll Progress: %f", scrollProgress));
updateChildViews();
}
};
public Accordion(Context context) {
super(context);
this.setOnTouchListener(this.touchListener);
}
public Accordion(Context context, AttributeSet attrs) {
super(context, attrs);
this.setOnTouchListener(this.touchListener);
}
public Accordion(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setOnTouchListener(this.touchListener);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
updateChildViews();
}
private void updateChildViews() {
int viewCount = getChildCount();
double progress = scrollProgress;
double overflow = 0;
for(int i = 0; i < viewCount; i++) {
View child = getChildAt(i);
if(child != null) {
if(progress >= scrollProgressPerView) {
progress -= scrollProgressPerView;
child.setVisibility(View.GONE);
setChildHeight(child, 0);
} else if (progress > 0) {
setChildHeight(child, expandedViewHeight - progress);
overflow = progress;
child.setVisibility(View.VISIBLE);
progress = 0;
} else {
if(overflow > 0) {
double height = collapsedViewHeight + overflow;
if(height > expandedViewHeight) {
height = expandedViewHeight;
}
setChildHeight(child, height);
overflow = 0;
} else {
setChildHeight(child, i > 0 ? collapsedViewHeight : expandedViewHeight);
}
child.setVisibility(View.VISIBLE);
}
}
}
}
private void setChildHeight(View child, double height) {
child.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)height));
}
private static abstract class ScrollTouchListener implements OnTouchListener {
private static final String LOG_TAG = ScrollTouchListener.class.getSimpleName();
private boolean scrolling = false;
private float x = 0;
private float y = 0;
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = event.getX();
y = event.getY();
scrolling = true;
return true;
case MotionEvent.ACTION_UP:
scrolling = false;
return true;
case MotionEvent.ACTION_MOVE:
if (scrolling) {
float newX = event.getX();
float newY = event.getY();
float difX = x - newX;
float difY = y - newY;
onScroll(difX, difY);
x = newX;
y = newY;
}
return true;
default:
return false;
}
}
protected abstract void onScroll(float x, float y);
}
}
To use it just put it in a layout like this:
<at.test.app.Accordion xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="#drawable/alpen"/>
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="#drawable/alpen"/>
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="#drawable/alpen"/>
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="#drawable/alpen"/>
</at.test.app.Accordion>
If you have any additional questions feel free to ask!
I think if the container you are using is a ListView, then following must be useful.Just need to detect the center element of the list view, and apply the zooming effect to the image in that row.Following is the code that can be used to implement this strategy:
int visibleChildCount = (listView1.getLastVisiblePosition() - listView1.getFirstVisiblePosition()) + 1;
In your getView() method:
if(position==visibleChildCount/2)
{
//Center Element
//Apply the Transition Effect From the XML files to the Image to Grow.
}

Text scale up to fit a TextView and an EditText

I want to fit the text size of a TextView and an EditText to to match their bounds.
I searched a bit and found the code below. So I created a new class with the code below:
package com.example.test;
import android.content.Context;
import android.text.Layout.Alignment;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
public class AutoResizeTextView extends TextView {
// Minimum text size for this text view
public static final float MIN_TEXT_SIZE = 20;
// Interface for resize notifications
public interface OnTextResizeListener {
public void onTextResize(TextView textView, float oldSize, float newSize);
}
// Our ellipse string
private static final String mEllipsis = "...";
// Registered resize listener
private OnTextResizeListener mTextResizeListener;
// Flag for text and/or size changes to force a resize
private boolean mNeedsResize = false;
// Text size that is set from code. This acts as a starting point for resizing
private float mTextSize;
// Temporary upper bounds on the starting text size
private float mMaxTextSize = 0;
// Lower bounds for text size
private float mMinTextSize = MIN_TEXT_SIZE;
// Text view line spacing multiplier
private float mSpacingMult = 1.0f;
// Text view additional line spacing
private float mSpacingAdd = 0.0f;
// Add ellipsis to text that overflows at the smallest text size
private boolean mAddEllipsis = true;
// Default constructor override
public AutoResizeTextView(Context context) {
this(context, null);
}
// Default constructor when inflating from XML file
public AutoResizeTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
// Default constructor override
public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mTextSize = getTextSize();
}
/**
* When text changes, set the force resize flag to true and reset the text size.
*/
#Override
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
mNeedsResize = true;
// Since this view may be reused, it is good to reset the text size
resetTextSize();
}
/**
* If the text view size changed, set the force resize flag to true
*/
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != oldw || h != oldh) {
mNeedsResize = true;
}
}
/**
* Register listener to receive resize notifications
* #param listener
*/
public void setOnResizeListener(OnTextResizeListener listener) {
mTextResizeListener = listener;
}
/**
* Override the set text size to update our internal reference values
*/
#Override
public void setTextSize(float size) {
super.setTextSize(size);
mTextSize = getTextSize();
}
/**
* Override the set text size to update our internal reference values
*/
#Override
public void setTextSize(int unit, float size) {
super.setTextSize(unit, size);
mTextSize = getTextSize();
}
/**
* Override the set line spacing to update our internal reference values
*/
#Override
public void setLineSpacing(float add, float mult) {
super.setLineSpacing(add, mult);
mSpacingMult = mult;
mSpacingAdd = add;
}
/**
* Set the upper text size limit and invalidate the view
* #param maxTextSize
*/
public void setMaxTextSize(float maxTextSize) {
mMaxTextSize = maxTextSize;
requestLayout();
invalidate();
}
/**
* Return upper text size limit
* #return
*/
public float getMaxTextSize() {
return mMaxTextSize;
}
/**
* Set the lower text size limit and invalidate the view
* #param minTextSize
*/
public void setMinTextSize(float minTextSize) {
mMinTextSize = minTextSize;
requestLayout();
invalidate();
}
/**
* Return lower text size limit
* #return
*/
public float getMinTextSize() {
return mMinTextSize;
}
/**
* Set flag to add ellipsis to text that overflows at the smallest text size
* #param addEllipsis
*/
public void setAddEllipsis(boolean addEllipsis) {
mAddEllipsis = addEllipsis;
}
/**
* Return flag to add ellipsis to text that overflows at the smallest text size
* #return
*/
public boolean getAddEllipsis() {
return mAddEllipsis;
}
/**
* Reset the text to the original size
*/
public void resetTextSize() {
if(mTextSize > 0) {
super.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
mMaxTextSize = mTextSize;
}
}
/**
* Resize text after measuring
*/
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if(changed || mNeedsResize) {
int widthLimit = (right - left) - getCompoundPaddingLeft() - getCompoundPaddingRight();
int heightLimit = (bottom - top) - getCompoundPaddingBottom() - getCompoundPaddingTop();
resizeText(widthLimit, heightLimit);
}
super.onLayout(changed, left, top, right, bottom);
}
/**
* Resize the text size with default width and height
*/
public void resizeText() {
int heightLimit = getHeight() - getPaddingBottom() - getPaddingTop();
int widthLimit = getWidth() - getPaddingLeft() - getPaddingRight();
resizeText(widthLimit, heightLimit);
}
/**
* Resize the text size with specified width and height
* #param width
* #param height
*/
public void resizeText(int width, int height) {
CharSequence text = getText();
// Do not resize if the view does not have dimensions or there is no text
if(text == null || text.length() == 0 || height <= 0 || width <= 0 || mTextSize == 0) {
return;
}
// Get the text view's paint object
TextPaint textPaint = getPaint();
// Store the current text size
float oldTextSize = textPaint.getTextSize();
// If there is a max text size set, use the lesser of that and the default text size
float targetTextSize = mMaxTextSize > 0 ? Math.min(mTextSize, mMaxTextSize) : mTextSize;
// Get the required text height
int textHeight = getTextHeight(text, textPaint, width, targetTextSize);
// Until we either fit within our text view or we had reached our min text size, incrementally try smaller sizes
while(textHeight > height && targetTextSize > mMinTextSize) {
targetTextSize = Math.max(targetTextSize - 2, mMinTextSize);
textHeight = getTextHeight(text, textPaint, width, targetTextSize);
}
// If we had reached our minimum text size and still don't fit, append an ellipsis
if(mAddEllipsis && targetTextSize == mMinTextSize && textHeight > height) {
// Draw using a static layout
StaticLayout layout = new StaticLayout(text, textPaint, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, false);
// Check that we have a least one line of rendered text
if(layout.getLineCount() > 0) {
// Since the line at the specific vertical position would be cut off,
// we must trim up to the previous line
int lastLine = layout.getLineForVertical(height) - 1;
// If the text would not even fit on a single line, clear it
if(lastLine < 0) {
setText("");
}
// Otherwise, trim to the previous line and add an ellipsis
else {
int start = layout.getLineStart(lastLine);
int end = layout.getLineEnd(lastLine);
float lineWidth = layout.getLineWidth(lastLine);
float ellipseWidth = textPaint.measureText(mEllipsis);
// Trim characters off until we have enough room to draw the ellipsis
while(width < lineWidth + ellipseWidth) {
lineWidth = textPaint.measureText(text.subSequence(start, --end + 1).toString());
}
setText(text.subSequence(0, end) + mEllipsis);
}
}
}
// Some devices try to auto adjust line spacing, so force default line spacing
// and invalidate the layout as a side effect
textPaint.setTextSize(targetTextSize);
setLineSpacing(mSpacingAdd, mSpacingMult);
// Notify the listener if registered
if(mTextResizeListener != null) {
mTextResizeListener.onTextResize(this, oldTextSize, targetTextSize);
}
// Reset force resize flag
mNeedsResize = false;
}
// Set the text size of the text paint object and use a static layout to render text off screen before measuring
private int getTextHeight(CharSequence source, TextPaint paint, int width, float textSize) {
// Update the text paint object
paint.setTextSize(textSize);
// Measure using a static layout
StaticLayout layout = new StaticLayout(source, paint, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, true);
return layout.getHeight();
}
}
But what do I have to do from there in order for the code to work? This is my code and my XML file. What do I do wrong and what should I do?
Java:
package com.example.test;
import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.Bundle;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.VideoView;
import com.example.test.AutoResizeTextView;
public class MainActivity extends Activity {
public VideoView vv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, // Set Fullscreen mode, overiding title and BATTERY
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // SCREEN NEVER GOES TO SLEEP MODE
//*** BACKGROUND MOVIE, LOOPING AND SETTING LOCAL PATH ***
vv = (VideoView) findViewById(R.id.videoView);
vv.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.setLooping(true);
}
});
Uri url=Uri.parse("android.resource://" + getPackageName() +"/"+ R.raw.bubblessd );
vv.setVideoURI(url);
vv.start();
vv.requestFocus();
//*** BACKGROUND MOVIE, LOOPING AND SETTING LOCAL PATH ***
}
final EditText myet = (EditText) findViewById(R.id.editText1);
myet.resizeText();
}
and XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="#style/AppTheme"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fitsSystemWindows="true"
android:gravity="center"
android:soundEffectsEnabled="false"
tools:context=".MainActivity" >
<VideoView
android:id="#+id/videoView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true" />
<LinearLayout
android:id = "#+id/main_menu_wrapper"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical"
android:weightSum="100">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="20"
android:fitsSystemWindows="true"
android:gravity="center"
android:orientation="horizontal"
android:weightSum="100" >
<com.example.test.AutoResizeTextView
android:id="#+id/textView1"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="20"
android:background="#55000000"
android:text="TextView"
/>
<EditText
android:id="#+id/editText1"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="20"
android:background="#55000000"
android:inputType="text"
android:maxLength="10"
android:shadowColor="#000"
android:textColor="#FFFFFF"
android:textStyle="bold" >
</EditText>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
You are already using it correctly. By defining it in your XML, you tell the inflater to use that class.
If you want to access it in Java, treat it like any other view:
AutoResizeTextView textView = (AutoResizeTextView) findViewById(R.id.textView1);
textView.setText("Hello, user!");
It will behave just like any other text view, except it is supposed to automatically resize the text.

Categories

Resources