Android - Motion Layout or animation item to cart - java

I'm planning to create an animation like all those apps that have a RecyclerView and when click Add to cart does like a screenshot of the item and with animations goes through the screen and ends in the cart icon.
And I'm wondering if the Motion Layout is something I need to use no matter what, I know you can control the scenes and everything but perhaps there's another way to do this.
The scenario is :
I have a horizontal scroll view and in one item I have a button that says Add to cart, when I press to it then it animates to another view adding alpha until alpha is 0.
The naming of this animation is seen as Fly to cart animation.
Any hint?
This is my custom view and what I want is when I press the button of an item of my RecyclerView this exact item make it smaller and "fly" with a parabola or something or even a straight line to the number 2 making the item smaller and reducing alpha until it arrives to number 2 and it dissapear, and then animate this 2. When the item arrives to the item 2 it should move the second to the first item like the item was removed.
The idea is something like this : https://www.youtube.com/watch?v=YOsz8_vkfiM&ab_channel=AravindrajPalani but instead of doing a "screenshoot" moving the item it self or perhaps I have to hide the item and then create a copy of it... I don't know

Do you mean somthing like this?
Here is How I do it
view_card.xml
Just a typical layout there is no important code here
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardBackgroundColor="#E6EFF1"
app:cardCornerRadius="12dp"
app:cardUseCompatPadding="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:text="Add To Cart"
android:textSize="11sp"
app:layout_constraintBottom_toBottomOf="#+id/imageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/imageView"
app:layout_constraintTop_toBottomOf="#+id/textView"
app:layout_constraintVertical_bias="1.0" />
<ImageView
android:id="#+id/imageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:src="#drawable/a2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AIMAN"
android:textAlignment="center"
android:textColor="#color/black"
android:textSize="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="#+id/button"
app:layout_constraintTop_toTopOf="#+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
activity_main.xml
Just a typical layout there is no important code here
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<RelativeLayout
android:id="#+id/card"
android:layout_width="130dp"
android:layout_height="100dp"
android:layout_marginTop="#dimen/cardMargin"
app:cardBackgroundColor="#EDEAF1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.943"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:src="#drawable/ic_cart" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:clipToPadding="false"
android:orientation="horizontal"
android:padding="16dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/card"
tools:listitem="#layout/view_card" />
</androidx.constraintlayout.widget.ConstraintLayout>
CustomAdapter.java
Focus here on the remove(..) function, here when you notify by the function notifyItemRemoved(position) the animation after the card removes going to be applied, you don't need to do anything else.
List<Drawable> list;
CustomViewListener listener;
public CustomAdapter() {
list = new ArrayList<>();
}
public void setListener(CustomViewListener listener) {
this.listener = listener;
}
public void add(Drawable drawable) {
list.add(drawable);
notifyDataSetChanged();
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_card, parent, false);
return new CustomViewHolder(inflate, listener);
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
holder.bind(list.get(position));
}
#Override
public int getItemCount() {
return list.size();
}
public void remove(Drawable drawable) {
int position = list.indexOf(drawable);
list.remove(drawable);
notifyItemRemoved(position);
}
public interface CustomViewListener {
void onFly(View view, Drawable drawable, int x, int y, int width, int hight);
}
}
CustomViewHolder.java
Foucse here at the following
initSize() to get the CardView size witch we need later to pass it for the temporary ImageView in the MainActivity
at the binding.button.setOnClickListener we going to get the CardView location and after that we call the function onFly to pass the information we need to the MainActivity
class CustomViewHolder extends RecyclerView.ViewHolder {
int width = 0, height = 0;
Drawable drawable;
CustomAdapter.CustomViewListener listener;
ViewCardBinding binding;
public CustomViewHolder(#NonNull View itemView, CustomAdapter.CustomViewListener listener) {
super(itemView);
binding = ViewCardBinding.bind(itemView);
this.listener = listener;
initSize();
initEvent();
}
private void initSize() {
ViewTreeObserver treeObserver = binding.card.getViewTreeObserver();
treeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
binding.card.getViewTreeObserver().removeOnGlobalLayoutListener(this);
width = binding.card.getMeasuredWidth();
height = binding.card.getMeasuredHeight();
}
});
}
public void bind(Drawable drawable) {
this.drawable = drawable;
binding.imageView.setImageDrawable(drawable);
binding.card.setVisibility(View.VISIBLE);
}
private void initEvent() {
binding.button.setOnClickListener(view -> {
int[] location = new int[2];
binding.card.getLocationInWindow(location);
int x = location[0];
int y = location[1];
listener.onFly(binding.card, drawable, x, y, width, height);
binding.card.setVisibility(View.INVISIBLE);
});
}
}
MainActivity.java
Foucse here at the following
Inside the function handleAnimateTheCard(..)
1- getTemporaryImageView(..) create temporary ImageView with the width and hight of CardView from the RecyclerView
2- loadBitmapFromView(..) draw inside a BitMap to look like the CardView of the RecyclerView
Inside the function startAnime(..) going to create animations you request by the coordinates of the CardView inside the RecyclerView ,and the RelativeLayout inside the MainActivty, here we have three animation pop up then moving the card with fading
after the second animation finish going to remove the card from the RecyclerView
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
CustomAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
adapter = new CustomAdapter();
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true);
binding.recyclerView.setLayoutManager(layoutManager);
binding.recyclerView.setAdapter(adapter);
adapter.setListener(this::handleAnimateTheCard);
addSomeData();
}
void handleAnimateTheCard(View view, Drawable drawable, int x, int y, int width, int hight) {
ImageView tempImage = getTemporaryImageView(width, hight);
Bitmap viewBitmap = loadBitmapFromView(view);
tempImage.setImageBitmap(viewBitmap);
// here because the y value not include the toolbar and actionbar hight
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int topOffset = dm.heightPixels - binding.getRoot().getMeasuredHeight();
y -= topOffset;
int[] location = new int[2];
binding.card.getLocationInWindow(location);
int cartX = location[0] - 100;
int cartY = location[1] - topOffset;
tempImage.setAlpha(1f);
startAnime(tempImage, drawable, x, y, cartX, cartY);
}
private ImageView getTemporaryImageView(int width, int hight) {
ImageView tempImage = new ImageView(MainActivity.this);
binding.getRoot().addView(tempImage);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(width, hight);
tempImage.setLayoutParams(params);
return tempImage;
}
private void startAnime(ImageView tempImage, Drawable drawable, int x, int y, int cartX, int cartY) {
ObjectAnimator popAnime = ObjectAnimator.ofFloat(tempImage, "translationX", x, x);
ObjectAnimator popAnime2 = ObjectAnimator.ofFloat(tempImage, "translationY", y, y);
ObjectAnimator popAnime3 = ObjectAnimator.ofFloat(tempImage, "scaleY", 1f, 0.9f, 1.2f);
ObjectAnimator popAnime4 = ObjectAnimator.ofFloat(tempImage, "scaleX", 1f, 0.9f, 1.2f);
AnimatorSet popAnimeSet = new AnimatorSet();
popAnimeSet.setDuration(200).playTogether(popAnime, popAnime2, popAnime3, popAnime4);
ObjectAnimator moveAnime = ObjectAnimator.ofFloat(tempImage, "translationX", x, cartX);
ObjectAnimator moveAnime2 = ObjectAnimator.ofFloat(tempImage, "translationY", y, cartY);
ObjectAnimator moveAnime3 = ObjectAnimator.ofFloat(tempImage, "scaleY", 1.2f, 0.5f);
ObjectAnimator moveAnime4 = ObjectAnimator.ofFloat(tempImage, "scaleX", 1.2f, 0.5f);
AnimatorSet moveAnimeSet = new AnimatorSet();
moveAnimeSet.setDuration(500).playTogether(moveAnime, moveAnime2, moveAnime3, moveAnime4);
moveAnimeSet.setStartDelay(50);
moveAnimeSet.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
tempImage.animate().alpha(0f).setDuration(600);
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(popAnimeSet, moveAnimeSet);
animatorSet.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
adapter.remove(drawable);
}
});
animatorSet.start();
}
public Bitmap loadBitmapFromView(View view) {
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
Drawable bgDrawable = view.getBackground();
if (bgDrawable != null)
bgDrawable.draw(canvas);
else
canvas.drawColor(Color.WHITE);
view.draw(canvas);
return returnedBitmap;
}
private void addSomeData() {
adapter.add(ContextCompat.getDrawable(this, R.drawable.a1));
adapter.add(ContextCompat.getDrawable(this, R.drawable.a2));
adapter.add(ContextCompat.getDrawable(this, R.drawable.a3));
}
}

Related

Swipe left to show view at top of cardview in recycler view item

On Swipe left from child item of recycler view to show an custom view
result_what_i_get
needed_result
I used the following code :
ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
final int position = viewHolder.getAdapterPosition();
if (direction == ItemTouchHelper.LEFT) {
Toast.makeText(getApplicationContext(), "Left swipe at position :"+(position+1), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
try {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
View itemView = viewHolder.itemView;
Paint paint = new Paint();
paint.setColor(Color.parseColor("#D32F2F"));
RectF background = new RectF((float) itemView.getRight() + dX / 5, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom());
c.drawRect(background, paint);
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
But i get the below result : result_what_i_get
But i need that result : needed_result
item xml file
the custom item file that i use in above code :
<android.support.v7.widget.CardView
android:id="#+id/cardV"
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="wrap_content"
app:cardBackgroundColor="#android:color/white"
app:cardCornerRadius="3dp"
app:cardElevation="4dp"
android:layout_marginTop="4dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
app:cardUseCompatPadding="true"
app:contentPadding="10dp">
<LinearLayout
android:id="#+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/card_view_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:textColor="#android:color/black"
android:textSize="15sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="Swipe"
android:textColor="#android:color/darker_gray"
android:textSize="12sp" />
</LinearLayout>
</android.support.v7.widget.CardView>
On swipe left to show a view just like i mention in screenshot

Cells not taking desired height, when using GridLayoutManager with RecyclerView

I have created a RecyclerView (in a fragment) in which I am adding items dynamically using GridLayoutManager. In each of the cell of RecyclerView I am loading images from the server using Picasso.
Now the problem is that, when the images are loading for the first time, the RecyclerView cells take weird height as shown here:
But when I change tab and come to the home tab again, everything is the way I want, as shown here:
What I need is, to make cells take the desired width and height at the time they are getting added to the recycler view. To achieve this I have tried:
Get the width of the screen and set cells' height and width = screen size /2.
Take the width of RecyclerView and make cells' width and height equals to half of it.
I am assigning dimensions to the cell in onCreateViewHolder method of the adapter.
But in any case, I need to change tab (load fragment again) to give the cells the desired height.
I have specified the width and height of cell in its layout file as wrap content because I want them to get set according to screen size. I don't wanna hard code any value.
What am I doing wrong? Did I miss anything?
For detailed explanation, the code is given as follows:
Cell layout file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/category_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#android:color/darker_gray"
android:orientation="vertical"
android:weightSum="1">
<ImageView
android:id="#+id/categoryImage"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:layout_marginTop="0dp"
android:layout_weight="0.8"
android:src="#drawable/icon" />
<TextView
android:id="#+id/categoryName"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="5dp"
android:layout_marginTop="0dp"
android:layout_weight="0.2"
android:text="ORAL CARE"
android:textAlignment="center"
android:textColor="#android:color/black"
android:textSize="15dp" />
</LinearLayout>
RecyclerView in fragment's layout file:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerViewCategories"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView11" />
RecyclerView adapter:
public class CategoryRecyclerViewAdapter extends RecyclerView.Adapter<CategoryRecyclerViewAdapter.ViewHolder> {
private List<MedicineCategoryDataModel> categoryData = new ArrayList<MedicineCategoryDataModel>();
private LayoutInflater layoutInflater;
private ItemClickListener itemClickListener;
private Context context;
private int itemWidth;
public CategoryRecyclerViewAdapter(Context context, List<MedicineCategoryDataModel> data, int width) {
this.layoutInflater = LayoutInflater.from(context);
this.categoryData = data;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.layout_category_item, parent, false);
// this is the point where I was trying to set cell's width and height.
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String categoryName = categoryData.get(position).categoryName;
holder.textViewCategoryName.setText(categoryName);
String iconUrl = categoryData.get(position).iconUrl;
EPClientLayer.getInstance().getImageHandler().loadImage(context,iconUrl, holder.imageViewCategoryIcon);
}
#Override
public int getItemCount() {
return categoryData.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView textViewCategoryName;
ImageView imageViewCategoryIcon;
ViewHolder(View itemView) {
super(itemView);
textViewCategoryName = (TextView) itemView.findViewById(R.id.categoryName);
imageViewCategoryIcon = (ImageView) itemView.findViewById(R.id.categoryImage);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (itemClickListener != null) itemClickListener.onItemClick(view, getAdapterPosition());
}
}
public String getItem(int id) {
return categoryData.get(id).categoryName;
}
public void setClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
I think you need to set the height of the ImageView of your cell item to wrap_content instead of providing the height 0dp as you are taking the weightSum. I would like to recommend to implement your cell items like this.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/category_item"
android:layout_width="match_parent"
android:layout_height="260dp"
android:background="#android:color/darker_gray">
<ImageView
android:id="#+id/categoryImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/icon" />
<TextView
android:id="#+id/categoryName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/categoryImage"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"
android:text="ORAL CARE"
android:textColor="#android:color/black"
android:textSize="15sp" />
</RelativeLayout>
And the RecyclerView to have the height and width set to match_parent.
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerViewCategories"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView11" />
You do not want to hard code any height, which is fine. However, I think you might consider hard-coding the optimized height of the cell item's root RelativeLayout to get the desired behaviour in all screen sizes.
make an SquareImageView as:
public class SquareImageView extends AppCompatImageView {
public SquareImageView(Context context) {
super(context);
}
public SquareImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);//replace heightMeasureSpec with widthMeasureSpec in this line
}
}
use above imageView in recyclerView Item to load image using Piccasa.
use recyclerView in xml as:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:spanCount="2"
tools:listitem="#layout/recycler_view_item"
app:layoutManager="GridLayoutManager">
</android.support.v7.widget.RecyclerView>
let me know if this solve your problem

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.CardView.setVisibility(int)' on a null object reference

I am trying to animate a Cardview when FAB is pressed. I want to get circular animation. Initially Cardview is set to Invisible. But, it is trowing null object reference on CardView.setVisibility.
public class FeedFragment extends Fragment {
private FloatingActionButton floatingBtn;
private CardView cardView;
boolean flag = true;
public FeedFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_feed, container, false);
floatingBtn = view.findViewById(R.id.floatBtn);
cardView = view.findViewById(R.id.cardView);
floatingBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(flag) {
// Check if the runtime version is at least Lollipop
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
// get the center for the clipping circle
int cx = cardView.getWidth() / 2;
int cy = cardView.getHeight() / 2;
// get the final radius for the clipping circle
float finalRadius = (float) Math.hypot(cx, cy);
// create the animator for this view (the start radius is zero)
Animator anim =
ViewAnimationUtils.createCircularReveal(cardView, cx, cy, 0, finalRadius);
// make the view visible and start the animation
cardView.setVisibility(View.VISIBLE);
anim.start();
} else {
// set the view to visible without a circular reveal animation below Lollipop
cardView.setVisibility(View.VISIBLE);
}
flag = false;
} else {
// Check if the runtime version is at least Lollipop
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
// get the center for the clipping circle
int cx = cardView.getWidth() / 2;
int cy = cardView.getHeight() / 2;
// get the initial radius for the clipping circle
float initialRadius = (float) Math.hypot(cx, cy);
// create the animation (the final radius is zero)
Animator anim =
ViewAnimationUtils.createCircularReveal(cardView, cx, cy, initialRadius, 0);
// make the view invisible when the animation is done
anim.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
cardView.setVisibility(View.INVISIBLE);
}
});
// start the animation
anim.start();
} else {
// set the view to visible without a circular reveal animation below Lollipop
cardView.setVisibility(View.VISIBLE);
}
flag = true;
}
}
});
return view;
}
}
Here is the XML code
<FrameLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.authent.authentication.FeedFragment">
<!-- TODO: Update blank fragment layout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="bottom">
<android.support.v7.widget.CardView
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="208dp"
android:layout_gravity="bottom"
android:layout_marginBottom="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
app:cardCornerRadius="20dp"
android:visibility="gone">
<LinearLayout
android:id="#+id/linearReveal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone">
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/white"
android:text="Ask a Query"
android:textSize="24dp"
android:textAllCaps="false"
android:textColor="#00ccff"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#android:color/darker_gray"/>
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/white"
android:text="Share Something"
android:textSize="24dp"
android:textAllCaps="false"
android:textColor="#ff3300"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#android:color/darker_gray"/>
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/white"
android:text="Post an MCQ"
android:textSize="24dp"
android:textAllCaps="false"
android:textColor="#cc9900"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.design.widget.FloatingActionButton
android:id="#+id/floatBtn"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="end"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:layout_marginRight="16dp"
android:src="#drawable/edit_nick_name" />
</LinearLayout>
Somebody help how to achieve circular animation. I am new to programming.
I also tried making LinearLayout INVISIBLE, it is also throwing NullPointerException on LinearLayout.setVisibility on a null object reference.
Thanks in advance.
Your CardView is null. Based on your code, you are trying to get the CardView from the View that received the onClick which is the FloatingButton.
Try calling the initialization outside just before the listener. Ideally on the same level as where you initialized the FloatingButton.
Intilaize cardview outside of the "clickListener".
You just need to remove this line cardView = view.findViewById(R.id.cardView);
and paste it before
floatingBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
return view;
}

How can I anchor an image to the center within an Imageview in a scrollview, in Android?

When I scroll within my Android scrollview, it scrolls down as it should.
But I'd like the image within the imageview to anchor to the centre. So you always see the face of the person in the image as you scrolling up.
So far I have not been able to accomplish this
A similar effect is created in the image below:
Stockguy image:
My code so far (which so far doesn't accomplish this):
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fillViewport="true"
android:scrollbars="none"
android:background="#FAFAFA"
android:id="#+id/cScrollview"
>
<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="1100dp"
tools:context=".MainActivity"
android:id="#+id/CRLayout">
<ImageView
android:layout_gravity="center"
android:adjustViewBounds="true"
android:layout_width="601dp"
android:layout_height="250dp"
android:paddingTop="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:scaleType="centerCrop"
android:id="#+id/contactPic"
android:src="#drawable/stockguy"/>
....
</RelativeLayout>
</ScrollView>
To achieve parallax effect like on image you posted try following code. It is a very simple way.
Layout:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/rlWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/ivContactPhoto"
android:layout_width="match_parent"
android:layout_height="#dimen/contact_photo_height"
android:scaleType="centerCrop"
android:src="#drawable/stockguy" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="#dimen/contact_photo_height"
android:layout_marginTop="250dp">
<!-- Other Views -->
</LinearLayout>
</RelativeLayout>
</ScrollView>
LinearLayout's top margin is equal to the ImageViews's height.
Listening scroll position of the ScrollView and changing position of ImageView:
#Override
protected void onCreate(Bundle savedInstanceState) {
<...>
mScrollView = (ScrollView) findViewById(R.id.scrollView);
mPhotoIV = (ImageView) findViewById(R.id.ivContactPhoto);
mWrapperRL = (RelativeLayout) findViewById(R.id.rlWrapper);
mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ScrollPositionObserver());
<...>
}
private class ScrollPositionObserver implements ViewTreeObserver.OnScrollChangedListener {
private int mImageViewHeight;
public ScrollPositionObserver() {
mImageViewHeight = getResources().getDimensionPixelSize(R.dimen.contact_photo_height);
}
#Override
public void onScrollChanged() {
int scrollY = Math.min(Math.max(mScrollView.getScrollY(), 0), mImageViewHeight);
// changing position of ImageView
mPhotoIV.setTranslationY(scrollY / 2);
// alpha you can set to ActionBar background
float alpha = scrollY / (float) mImageViewHeight;
}
}
Hope it will help.
I'd take a different approach with that.
Try building your layout based on the following snippet:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:background="#00FF00"
android:scaleType="centerCrop"
android:layout_height="200dp"/>
<FrameLayout
android:id="#+id/content"
android:layout_below="#+id/image"
android:background="#FF0000"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
Using the GestureDetector.SimpleOnGestureListeneryou can detect when the user scrolls on the content layout and update the image size and alpha accordingly to get the effect you describe.
I would implement this using a scroll callback on the ScrollView, this doesn't exist by default but is easy to create yourself by extending ScrollView:
public class UpdatingScrollView extends ScrollView {
private OnScrollChangedListener mScrollChangedListener;
public interface OnScrollChangedListener {
public void onScrollChanged(int x, int y, int oldx, int oldy);
}
public UpdatingScrollView(Context context) {
super(context);
}
public UpdatingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public UpdatingScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setOnScrollChangedListener(OnScrollChangedListener listener) {
mScrollChangedListener = listener;
}
#Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (mScrollChangedListener != null) mScrollChangedListener.onScrollChanged(x, y, oldx, oldy);
}
}
So replace ScrollView in your layout with com.your.package.UpdatingScrollView.
In your Fragment/Activity where the UpdatingScrollView is defined you set the scroll listener and update the bottom margin of the image based on the scroll offset. For every 2 pixels the ScrollView has scrolled you'll want to update the bottom margin by -1 pixel which will make the image move up the screen at half the rate of the rest of the content.
So something like this:
scrollView.setOnScrollChangedListener(new OnScrollChangedListener() {
#Override
public void onScrollChanged(int x, int y, int oldx, int oldy) {
// I think y will be negative when scrolled
if(y >= -image.getHeight()) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) image.getLayoutParams();
lp.setMargins(0, 0, 0, y / 2);
image.setLayoutParams(lp);
}
}
});

split up a linear layout background into different colored parts

For a ListView, I want to give the individual ListView elements some kind of progress indicator - so to speak, I need a list of progress bars.
However, each of the listview elements have some text overlay in the form of a TextView that should not be affected by the progress bar at all.
I think pictures can tell more than words in this case, so here is pretty much what I want:
I know I can add "sublayouts" to the individual LinearLayouts and change the weight programmatically, which looks somewhat like this:
<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="match_parent"
android:orientation="horizontal">
<LinearLayout
android:id="#leftSide"
android:background="#color/green"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8" >
</LinearLayout>
<LinearLayout
android:id="#rightSide"
android:background="#color/red"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.2" >
</LinearLayout>
</LinearLayout>
and then programmatically change the weight for both sides (completed and uncompleted):
float weightLeft = 0.8f;
float weightRight = 1f-weightLeft;
android.widget.LinearLayout.LayoutParams paramsLeft = new android.widget.LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, weightLeft);
LinearLayout left = (LinearLayout) findViewById(R.id.leftside);
left.setLayoutParams(paramsLeft);
android.widget.LinearLayout.LayoutParams paramsRight = new android.widget.LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, weightRight);
LinearLayout right = (LinearLayout) findViewById(R.id.rightside);
left.setLayoutParams(paramsRight);
But - the question now is, how do I make the textviews sit on the parent linear layout and ignore the children LinearLayouts ?
I can also imagine there is a way to just split up the distribution of the background parts using drawables, but I have no clue how to do that, especially not programmatically.
Any help is appreciated!
try this custom Drawable, mFraction is [0..1]:
public class FractionDrawable extends Drawable {
private Paint mPaint;
private float mFraction;
public FractionDrawable(float fraction) {
mPaint = new Paint();
setFraction(fraction);
}
public void setFraction(float fraction) {
mFraction = fraction;
invalidateSelf();
}
#Override
public void draw(Canvas canvas) {
Rect b = getBounds();
mPaint.setColor(0xff00aa00);
float x = b.width() * mFraction;
canvas.drawRect(0, 0, x, b.height(), mPaint);
mPaint.setColor(0xffaa0000);
canvas.drawRect(x, 0, b.width(), b.height(), mPaint);
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}

Categories