I need to animate the following scenario:
I have a ListView, each cell have 3 Layouts in it:
A preview_layout (blue): contains a preview of the contents of the contents_layout.
A contents_layout (green): contains a long text with some buttons.
A wrapper_layout (red): contains preview_layout and contents_layout.
The contents_layout is set with visibility to "gone", so only the preview_layout are visible in the list.
When a cell of the ListView is pressed I need to show the contents_layout with a slide down animation.
Until now I used the following solution:
In the getView of the ListView:
// Preview_layouts height
int hPreview = 70;
// Views
final View previewView = rowView.findViewById(R.id.preview);
final View contentsView = rowView.findViewById(R.id.contents);
// On previewView click
previewView.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (!contentsView.isShown()) {
// Close all the contents_layout of the ListView (menuListView)
for (int i=0; i < menuListView.getChildCount(); i++) {
View v = menuListView.getChildAt(i).findViewById(R.id.contents);
if (v.isShown()) { v.startAnimation(new SlideUpAnimation(v, hPreview)); }
}
// Slide down the selected contents_layout (contentsView)
contentsView.startAnimation(new SlideDownAnimation(contentsView, hPreview));
}
}
});
The SlideDownAnimation class:
public class SlideDownAnimation extends Animation {
private View target;
private LayoutParams targetResize;
private int mFromHeight, mToHeight;
public SlideDownAnimation( View targetToSlideDown, int fromHeight ) {
// Show the contents_layout target
target = targetToSlideDown;
target.setVisibility(View.VISIBLE);
// Animation property
setDuration(500);
setInterpolator(new DecelerateInterpolator());
// Target
targetResize = targetToSlideDown.getLayoutParams();
mFromHeight = fromHeight;
mToHeight = targetResize.height - fromHeight;
targetResize.height = 1;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
// Set the Alpha to fade in the contents_layout target
t.setAlpha(interpolatedTime);
// Set the height to slide down the contents_layout target
targetResize.height = (int) (mToHeight * interpolatedTime) + mFromHeight;
target.requestLayout();
}
}
The big problem with this solution is that I cannot get the height of the contents_layout if it is set to android:layout_height="wrap_content" and the visibility is GONE, it just return "0".
Do you have any other solutions to perform the animation that I need?
Related
I created a recyclerview with a list of 'events'.This works fine for a list of events that is below 5. but as soon as i get 6 or more events in the list the last event will not expand when clicked, instead it dissapears. the closing animation also stops working with more than 6 events in the list.
how it should behave:
User taps event > view expands to full screen
User taps an expanded event > view collapses back to it's original size
User taps an event while another event is expanded > expanded event is set to original height en tapped event expands to fullscreen
current behavior:
User taps event > all views expand correctly except for the last item in the list
User taps expanded event > view collapses but does not animate
User taps an event while another event is expanded > expanded event collapses and tapped event expands correctly
User taps the last event in the list > the event dissapears (probably decreased it's size to below 0)
I know it probably has something to do with the way the recyclerview reuses its views when they are out of the screen. To fix this i check the position of the tapped event by the eventId instead of the position in the list, but this still leaves the issues that i talked about above.
public class EventRecyclerAdapter extends RecyclerView.Adapter<EventRecyclerAdapter.ViewHolder> {
private Context c;
private List<Event> items = new ArrayList<>();
private RelativeLayout container;
private int screenheight;
private EventListFragment eventListFragment;
private int expandedPosition = -1;
private static final String TAG = "EventRecyclerAdapter";
public interface ItemClickedListener {
void itemClicked(int position);
}
private ItemClickedListener itemClickedListener;
public EventRecyclerAdapter(List<Event> itemlist, Context c, EventListFragment eventListFragment, ItemClickedListener listener) {
this.items = itemlist;
this.c = c;
this.eventListFragment = eventListFragment;
this.itemClickedListener = listener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, null);
WindowManager wm = (WindowManager) c.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screenheight = size.y;
// Get the screen height from the device
Resources r = c.getResources();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80, r.getDisplayMetrics());
screenheight -= px;
ViewHolder viewHolder = new ViewHolder(itemLayoutView);
return viewHolder;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
Event event = items.get(position);
// - get data from your itemsData at this position
// - replace the contents of the view with that itemsData
viewHolder.tvName.setText(event.getName());
viewHolder.tvLocation.setText(event.getLocation().getName());
viewHolder.tvDate.setText(Helper.dateDoubleToString(event.getStartDate()));
viewHolder.tvTicketCount.setText(String.valueOf(event.getNumberOfTickets()));
viewHolder.background.setBackgroundColor(Color.GRAY);
viewHolder.eventId = event.getId();
// Load the background image
if (event.getEventImageId() != null) {
Picasso.with(c).load(Helper.imageUrlString(event.getEventImageId())).into(viewHolder.background);
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
viewHolder.background.setColorFilter(filter);
}
// Check if the view needs to be expanded, collapsed or just drawn normally.
if (expandedPosition == event.getId()) {
if (event.expanded) {
collapseView(viewHolder, event);
} else if (!event.expanded) {
expandView(viewHolder, position, event);
}
} else {
setContainerHeight(viewHolder, event);
}
}
private void expandView(final EventRecyclerAdapter.ViewHolder viewHolder, final int pos, Event event) {
ResizeAnimation resizeAnimation = new ResizeAnimation(
viewHolder.container,
viewHolder.container.getHeight(),
screenheight
);
resizeAnimation.setDuration(Constants.ANIMATION_SPEED);
resizeAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
viewHolder.infoContainer.setVisibility(View.VISIBLE);
viewHolder.closeIcon.setVisibility(View.VISIBLE);
itemClickedListener.itemClicked(pos);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
viewHolder.itemView.startAnimation(resizeAnimation);
viewHolder.expanded = true;
event.expanded = true;
}
private void collapseView(final EventRecyclerAdapter.ViewHolder viewHolder, Event event) {
ResizeAnimation resizeAnimation = new ResizeAnimation(
viewHolder.container,
viewHolder.container.getHeight(),
getContainerCollapsedHeight()
);
resizeAnimation.setDuration(Constants.ANIMATION_SPEED);
viewHolder.infoContainer.setVisibility(View.INVISIBLE);
viewHolder.closeIcon.setVisibility(View.INVISIBLE);
viewHolder.itemView.startAnimation(resizeAnimation);
viewHolder.expanded = false;
event.expanded = false;
}
private void setContainerHeight(EventRecyclerAdapter.ViewHolder viewHolder, Event event) {
viewHolder.container.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getContainerCollapsedHeight()));
viewHolder.infoContainer.setVisibility(View.INVISIBLE);
viewHolder.closeIcon.setVisibility(View.INVISIBLE);
event.expanded = false;
viewHolder.expanded = false;
}
private int getContainerCollapsedHeight() {
int containerHeight;
// Define the item containers height
if (items.size() <= 3) {
containerHeight = screenheight / items.size();
} else {
containerHeight = screenheight / 3;
}
return containerHeight;
}
/**
* Clear all current data and swap add the new data list.
* The expanded position also gets reset
* #param events
*/
public void swap(List<Event> events) {
this.items.clear();
this.items.addAll(events);
this.expandedPosition = -1;
Log.v(TAG,"SWAP SIZE : " + items.size());
notifyDataSetChanged();
}
// inner class to hold a reference to each item of RecyclerView
class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvLocation, tvDate, tvTicketCount;
public TextView tvName;
public ImageView background;
public View container;
public View infoContainer;
public TextView closeIcon;
public int eventId;
public boolean expanded = false;
public ViewHolder(final View itemLayoutView) {
super(itemLayoutView);
tvName = (TextView) itemLayoutView.findViewById(R.id.tvName);
tvLocation = (TextView) itemLayoutView.findViewById(R.id.tvLocation);
tvDate = (TextView) itemLayoutView.findViewById(R.id.tvDate);
background = (ImageView) itemLayoutView.findViewById(R.id.background);
tvTicketCount = (TextView) itemLayoutView.findViewById(R.id.ticket_count);
container = itemLayoutView.findViewById(R.id.list_item_container);
infoContainer = itemLayoutView.findViewById(R.id.info_container);
closeIcon = (TextView) itemLayoutView.findViewById(R.id.close_icon);
infoContainer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Activity mainActivity = (Activity) c;
FragmentManager fm = mainActivity.getFragmentManager();
//add
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.animator.slide_to_top, R.animator.slide_from_bottom);
ft.addToBackStack(ft.toString());
ft.add(R.id.content_frame, EventFragment.newInstance(items.get(getAdapterPosition())), Constants.EVENT_FRAGMENT_TAG);
//commit change
ft.commit();
}
});
container.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
expandedPosition = eventId;
notifyDataSetChanged();
}
});
}
}
// Return the size of your itemsData (invoked by the layout manager)
#Override
public int getItemCount() {
return items.size();
}
}
i think it's somehow running the collapseView method when i tap the last item in the list, causing its height to become below 0. But i'm unable to figure out why this is happening.
I hope someone is able to spot what's wrong here.
you can try this in OnClilck of recycleview Item
#Override
public void onClick(View view)
{
LayoutParams params = view.getLayoutParams();
if (!large)
{
params.height = 2 * view.getHeight();
} else {
params.height = view.getHeight()/2;
}
large = !large;
view.setLayoutParams(params);
}
How can I add a slide in animation on my recycler view items one after the other. Like as the activity starts, the list items of the recycler view slides in one by one. I am using LinearLayoutManager
Not all at the same time should slide in. And not even while scrolling. Just at the time of activity creation.
I searched but didn't find anything.
I want to achieve something like this : https://youtu.be/Q8TXgCzxEnw?t=30s
I put together a sample app a couple of months ago that has a sequential slide in-slide out animation during reshuffles. A demo video is available here. It should give you some ideas.
A link to the most relevant class file is here, and I'll copy the code below.
public class AllNotesFragmentRecyclerView extends RecyclerView {
private static final int BASE_ANIMATION_TIME = 50;
private static final int MAX_ANIMATION_TIME_INCREMENT = 100;
private int screenWidth;
private int startX, finalX;
private int[] interpolatedAnimationTimes;
public AllNotesFragmentRecyclerView(Context context) {
super(context);
init(context);
}
public AllNotesFragmentRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AllNotesFragmentRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
calculateScreenWidth(context);
startX = 0;
finalX = -(screenWidth);
}
private void calculateScreenWidth(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
screenWidth = metrics.widthPixels;
}
private int calculateInterpolatedAnimationTime(int currentIndex, int maxIndex) {
float percentage = ((float)currentIndex/(float)maxIndex);
float increment = (float) MAX_ANIMATION_TIME_INCREMENT * percentage;
return (int) (BASE_ANIMATION_TIME + increment);
}
public void updateListOrder() {
createAnimatorSet();
}
private void createAnimatorSet() {
AnimatorSet set = new AnimatorSet();
ArrayList<Animator> animArrayList = new ArrayList<>();
for (int i = 0; i < getChildCount(); i++) {
ObjectAnimator anim = ObjectAnimator
.ofFloat(getChildAt(i), "translationX", finalX);
int duration = calculateInterpolatedAnimationTime(i, getChildCount());
anim.setDuration(duration);
anim.addListener(new RowAnimationListener(i, duration, startX));
animArrayList.add(anim);
}
set.setInterpolator(new AccelerateInterpolator());
set.playSequentially(animArrayList);
set.start();
}
private void animateOn(int childPosition, int duration, int targetValue) {
ObjectAnimator animator = ObjectAnimator
.ofFloat(getChildAt(childPosition), "translationX", targetValue);
animator.setInterpolator(new DecelerateInterpolator());
animator.setDuration(duration);
animator.start();
}
//...
private class RowAnimationListener implements Animator.AnimatorListener {
private int position, duration, targetX;
public RowAnimationListener(int position, int duration, int targetX) {
this.position = position;
this.duration = duration;
this.targetX = targetX;
}
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
int currentItem = getLinearLayoutManager().findFirstVisibleItemPosition() + position;
getAdapter().notifyItemChanged(currentItem);
notifyRowsPeripheralToVisibleItemsDataChanged(position);
animateOn(position, duration, targetX);
}
#Override
public void onAnimationCancel(Animator animation) { }
#Override
public void onAnimationRepeat(Animator animation) { }
}
}
Finally I found a solution. In below snippet I will explain how to implement. It is simple and can be done on any existing working RecyclerView. I have explained everything in comments.
Here is the onCreate/onCreateView method (I have used this inside Fragment, You can change accordingly if needed):
RecyclerView recList = (RecyclerView) rootView.findViewById(R.id.event_list);
recList.setHasFixedSize(true);
LinearLayoutmanager llm = new LinearLayoutManager(getActivity().getApplicationContext());
llm.setOrientation(LinearLayoutManager.VERTICAL);
recList.setLayoutManager(llm);
// This is important. Setting recyclerView's alpha to zero.
// Basically this is just to hide recyclerview at start before binding data
// As setVisibility is not working on recycler view object.
recList.setAlpha(0);
// Create the EventAdapter with the result we got
// EventAdapter is my custom adapter class.
// you should set your adapter class
EventAdapter ea = new EventAdapter(eventResultList);
// Binding the Adapter to RecyclerView list to show the data
recList.setAdapter(ea);
// ********************* Animate at start ********************************
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// This will give me the initial first and last visible element's position.
// This is required as only this elements needs to be animated
// Start will be always zero in this case as we are calling in onCreate
int start = llm.findFirstVisibleItemPosition();
int end = llm.findLastVisibleItemPosition();
Log.i("Start: ", start + "");
Log.i("End: ", end + "");
// Multiplication factor
int DELAY = 50;
// Loop through all visible element
for (int i = start; i <= end; i++) {
Log.i("Animatining: ", i + "");
// Get View
View v = recList.findViewHolderForAdapterPosition(i).itemView;
// Hide that view initially
v.setAlpha(0);
// Setting animations: slide and alpha 0 to 1
PropertyValuesHolder slide = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 150, 0);
PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat(View.ALPHA, 0, 1);
ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(v, slide, alpha);
a.setDuration(300);
// It will set delay. As loop progress it will increment
// And it will look like items are appearing one by one.
// Not all at a time
a.setStartDelay(i * DELAY);
a.setInterpolator(new DecelerateInterpolator());
a.start();
}
// Set Recycler View visible as all visible are now hidden
// Animation will start, so set it visible
recList.setAlpha(1);
}
}, 50);
This is quite a small code without comments.
Some things needs an explanation:
Why hiding RecyclerView initially?
If RecyclerView is not hidden initially you will notice a blink initially before the animation starts. The reason for it is when you set a data adapter it will position it on its default positions and after the loop it starts animating. So in between while loop is running you will notice sudden blink in the RecyclerView that at first all are at its initial position and than suddenly animating.
So hiding it at first and than after loop completes and all visible positions animations are set with delays and started, we can show the RecyclerView. It makes sliding looks smooth.
The reason for hiding it with setAlpha(0) is as setVisibility() function is not working on the RecyclerView object.
How only visible elements will animate?
There are functions in the LayoutManager class to get the visible elements position. In LinearLayoutManager used findFirstVisibleItemPosition() to get the position of the first visible view from the recycler view data which is visible on screen. And the last visible view's position can be retried with findLastVisibleItemPosition(). So we can loop from the first view to last view and animate the initial views which are going to be on screen at start.
How delay Works?
As loop will progress from 0(start) to end it will set delay from 0,50,100,150,.. if DELAY variable is set to 50. So this will make first element start animating, second after 50ms delay, third after 100ms delay and so on. So it will look like they are coming in one by one. Not all together.
Create animation in anim/slide_in.xml file like below
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="#android:anim/decelerate_interpolator">
<translate
android:fromXDelta="100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="2000"/>
</set>
And then apply this animation on each view of RecyclerView in onBindViewHolder method.
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ViewHolder vh = (ViewHolder) holder;
vh1.tv_header.setText(mList.get(position));
Animation animation = AnimationUtils.loadAnimation(mContext,R.anim.rec_anim);
animation.setStartOffset(30 * position);//Provide delay here
holder.itemView.startAnimation(animation);
}
I just want to make the background image to look blur(like defocus),I used alpha but it was not only setting alpha to my background image but also to the whole content...Is there any way that I can set blur effect only to my background image!!!..
need help thanks in advance!!..
Please use below tutorial for blur background
NavigationDrawer :
https://github.com/charbgr/BlurNavigationDrawer
Fragment:
https://github.com/tvbarthel/BlurDialogFragment
Image : If you want to blur an image in layout :
https://github.com/kikoso/android-stackblur
Layout:
https://github.com/PomepuyN/BlurEffectForAndroidDesign
public class MainActivity extends Activity {
private static final String BLURRED_IMG_PATH = "blurred_image.png";
private static final int TOP_HEIGHT = 700;
private ListView mList;
private ImageView mBlurredImage;
private View headerView;
private ImageView mNormalImage;
private ScrollableImageView mBlurredImageHeader;
private Switch mSwitch;
private float alpha;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_main);
// Get the screen width
final int screenWidth = ImageUtils.getScreenWidth(this);
// Find the view
mBlurredImage = (ImageView) findViewById(R.id.blurred_image);
mNormalImage = (ImageView) findViewById(R.id.normal_image);
mBlurredImageHeader = (ScrollableImageView) findViewById(R.id.blurred_image_header);
mSwitch = (Switch) findViewById(R.id.background_switch);
mList = (ListView) findViewById(R.id.list);
// prepare the header ScrollableImageView
mBlurredImageHeader.setScreenWidth(screenWidth);
// Action for the switch
mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
mBlurredImage.setAlpha(alpha);
} else {
mBlurredImage.setAlpha(0f);
}
}
});
// Try to find the blurred image
final File blurredImage = new File(getFilesDir() + BLURRED_IMG_PATH);
if (!blurredImage.exists()) {
// launch the progressbar in ActionBar
setProgressBarIndeterminateVisibility(true);
new Thread(new Runnable() {
#Override
public void run() {
// No image found => let's generate it!
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.image, options);
Bitmap newImg = Blur.fastblur(MainActivity.this, image, 12);
ImageUtils.storeImage(newImg, blurredImage);
runOnUiThread(new Runnable() {
#Override
public void run() {
updateView(screenWidth);
// And finally stop the progressbar
setProgressBarIndeterminateVisibility(false);
}
});
}
}).start();
} else {
// The image has been found. Let's update the view
updateView(screenWidth);
}
String[] strings = getResources().getStringArray(R.array.list_content);
// Prepare the header view for our list
headerView = new View(this);
headerView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, TOP_HEIGHT));
mList.addHeaderView(headerView);
mList.setAdapter(new ArrayAdapter<String>(this, R.layout.list_item, strings));
mList.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/**
* Listen to the list scroll. This is where magic happens ;)
*/
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// Calculate the ratio between the scroll amount and the list
// header weight to determinate the top picture alpha
alpha = (float) -headerView.getTop() / (float) TOP_HEIGHT;
// Apply a ceil
if (alpha > 1) {
alpha = 1;
}
// Apply on the ImageView if needed
if (mSwitch.isChecked()) {
mBlurredImage.setAlpha(alpha);
}
// Parallax effect : we apply half the scroll amount to our
// three views
mBlurredImage.setTop(headerView.getTop() / 2);
mNormalImage.setTop(headerView.getTop() / 2);
mBlurredImageHeader.handleScroll(headerView.getTop() / 2);
}
});
}
private void updateView(final int screenWidth) {
Bitmap bmpBlurred = BitmapFactory.decodeFile(getFilesDir() + BLURRED_IMG_PATH);
bmpBlurred = Bitmap.createScaledBitmap(bmpBlurred, screenWidth, (int) (bmpBlurred.getHeight()
* ((float) screenWidth) / (float) bmpBlurred.getWidth()), false);
mBlurredImage.setImageBitmap(bmpBlurred);
mBlurredImageHeader.setoriginalImage(bmpBlurred);
}
}
Kotlin code, use view effect Library :
1- Add library in build.gradle:
implementation 'com.github.mirrajabi:view-effects:e355a1bac4'
2- Blure the background of root view or view, here Constraint Layout blured by 20%
ViewFilter.getInstance(this)
.setRenderer( BlurRenderer(20))
.applyFilterOnView( root_constraintLayout,
root_constraintLayout )
my github repository for blur background : link
public class Game_collecting_view extends View
{
Button image_boy;
private static final int BOY_DIAMETER = 200; // initial spot size
int boy_width =0;
int boy_height =0;
public void setGame_collecting(Game_collecting mGame_collecting)
{
this.mGame_collecting = mGame_collecting;
}
// constructs a new View
public Game_collecting_view(Context context, RelativeLayout parentLayout)
{
super(context);
resources = context.getResources(); // save Resources for loading external values
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// get references to various GUI components
relativeLayout = parentLayout;
spotHandler = new Handler(); // used to add spots when game starts
}
#Override
protected void onSizeChanged(int width, int height, int oldw, int oldh)
{
viewWidth = width; // save the new width
viewHeight = height; // save the new height
}
public void set_boy()
{
final Button boy = (Button) layoutInflater.inflate(R.layout.untouched, null);
boy.setX(viewWidth /2);
boy.setY(viewHeight - BOY_DIAMETER);
boy.setPadding(0,0,0,0);
boy.setBackgroundResource(R.drawable.blue);
boy.setLayoutParams(new RelativeLayout.LayoutParams(BOY_DIAMETER, BOY_DIAMETER));
relativeLayout.addView(boy); // add spot to the screen
Toast.makeText(getContext(), "set_boy\nviewWidth=" +viewHeight +"\nviewHeight=" +viewHeight, Toast.LENGTH_SHORT).show();
boy.setOnClickListener
(
new OnClickListener()
{
public void onClick(View v)
{
touchedSpot(boy);
}
}
);
}
public void resume(Context context)
{
resetGame();
}
public void resetGame()
{
for (int i = 1; i <= INITIAL_SPOTS; ++i)
{
spotHandler.postDelayed(addSpotRunnable, i * SPOT_DELAY);
generate_text();
}
set_boy();
}
private Runnable addSpotRunnable = new Runnable()
{
public void run()
{
addNewSpot(); // add a new spot to the game
}
};
Objective:
I would like to set the boy icon at the bottom middle of the screen.
The boy icon is set at this way for later dynamic interface (swipe the screen to the right the boy icon will move to the right, vice versa)
Observation:
The toast reports both the viewWidth and viewHeight =0, and the boy icon appears at 0,0 (left upper corner). If I set the setY(viewHeight + BOY_DIAMETER), the boy icon will be located at (0, 200).
Question:
I would like to ask why the viewWidth and viewHeight both report 0. How could the onSizeChanged be called immediately such that the boy icone could be set at the bottom center of the screen?
Thanks!!
The location is null until Android has calculated their positions. You can retrieve the height and width like this:
image_boy.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int height = image_boy.getHeight();
int width = image_boy.getWidth();
//these values won't be null
}
});
set layout param for setting the view position
I want to animate a rectangle filled with one opaque color. The attributes I will be animating is the translation, and the width of the active menu item.
I know how to animate things, but in this case, I want it to do no layouts on the view, since my animation will occur inside a LinearLayout, and it will not exceed it's size.
The Blue line on top of my layout is what I will be animating. It will go horizontally to the left and right, while changing it's width, so that it fits on the selected menu item.
I usually work with animations on the margin, but it consumes a lot of processing to re-calculate bounds on the layout process.
Any suggestions on how to do that?
That depends entirely on what API level you're targetting, if you're only targeting >3.0 then ObjectAnimator and ValueAnimator or the nicer ViewPropertyAnimator are your best friend, they let you do simple things like "move the X value of this 100dp while increasing the width by a factor of two, in 300ms".
If you're targeting a lower API level check out NineOldAndroids which brings that functionality over to all versions of Android.
To do what you want to do it'd be something along the lines of:
myImageView.scaleXBy(FACTOR_NEEDED_FOR_NEW_WIDTH);
and that's all to it.
As a sidenote: It looks like you might be attempting to replicate a ViewPager's indicator, in which case you should be using an actual indicator.
I had to animate the Margin and the Width of the view, because there was no way out, since I'm using android version >=8.
Here is my two classes that can do this:
MarginAnimation class:
public class MarginAnimation extends Animation{// implements AnimationListener{
public static String TAG = "MarginAnimation";
protected View animatingView;
protected int fromMarginLeft = 0;
protected int fromMarginTop = 0;
protected int toMarginLeft = 0;
protected int toMarginTop = 0;
protected LayoutParams layoutParam;
public MarginAnimation(View v, int toMarginLeft, int toMarginTop) {
this.toMarginLeft = toMarginLeft;
this.toMarginTop = toMarginTop;
this.animatingView = v;
// Save layout param
layoutParam = (LayoutParams) animatingView.getLayoutParams();
// Save current margins as initial state
saveCurrent();
// Set the listner to be self object
// setAnimationListener(this);
}
public MarginAnimation(View v, int fromMarginLeft, int toMarginLeft, int fromMarginTop, int toMarginTop) {
this.fromMarginLeft = fromMarginLeft;
this.toMarginLeft = toMarginLeft;
this.fromMarginTop = fromMarginTop;
this.toMarginTop = toMarginTop;
this.animatingView = v;
// Save layout param
layoutParam = (LayoutParams) animatingView.getLayoutParams();
// Set the listner to be self object
// setAnimationListener(this);
}
protected void saveCurrent(){
fromMarginLeft = layoutParam.leftMargin;
fromMarginTop = layoutParam.topMargin;
}
long lastTime = 0;
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
// long thisTime = System.nanoTime();
// if(lastTime != 0)
// Log.e(TAG, ((thisTime - lastTime) / 1000) + "delta Anim.");
// lastTime = thisTime;
layoutParam.leftMargin = (int)(fromMarginLeft + (toMarginLeft - fromMarginLeft) * interpolatedTime);
layoutParam.topMargin = (int)(fromMarginTop + (toMarginTop- fromMarginTop) * interpolatedTime);
animatingView.setLayoutParams(layoutParam);
}
#Override
public boolean willChangeBounds() {
return false;
}
}
MarginAndWidthAnimation class:
public class MarginAndWidthAnimation extends MarginAnimation{
public static String TAG = "MarginAndWidthAnimation";
int toWidth;
int fromWidth;
public MarginAndWidthAnimation(View v, int toMarginLeft, int toMarginTop, int toWidth) {
super(v, toMarginLeft,toMarginTop);
this.toWidth = toWidth;
// Log.i(TAG, "++F: "+this.fromWidth+" T: "+this.toWidth);
}
protected void saveCurrent(){
super.saveCurrent();
// fromWidth = animatingView.getWidth();
fromWidth = layoutParam.width;
// Log.i(TAG, "F: "+fromWidth+" T: "+toWidth);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
layoutParam.width = (int)(fromWidth + (toWidth - fromWidth) * interpolatedTime);
// Log.i(TAG, "F: "+fromWidth+" T: "+toWidth+" S: "+layoutParam.width);
super.applyTransformation(interpolatedTime, t);
}
}