I have a space ship ImageView that I'm rotating with the help of the following AnimatorSet:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially" >
<objectAnimator
android:duration="5000"
android:propertyName="rotation"
android:repeatCount="infinite"
android:repeatMode="restart"
android:valueTo="-360"
android:valueType="floatType"
android:interpolator="#android:anim/linear_interpolator" />
In order to start and end the animation I'm using this OnTouchListener:
turnShipLeft_btn.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
if (arg1.getAction() == MotionEvent.ACTION_DOWN) {
spaceShip_setLeft.start();
} else if(arg1.getAction() == MotionEvent.ACTION_UP){
spaceShip_setLeft.cancel();
}
return true;
}
});
Once spaceShip_setLeft.cancel(); is executed, I want to do 2 things:
Store the exact rotation degree where it was stopped in a local variable.
Set my rotation degree variable on the next AnimatorSet's android:valueFrom="" so it will start the animation from the exact position where spaceShip_setLeft animation ended.
I'm breaking my head over this for too long now. Any help will be very much appreciated!
PS. If you can include you'r own code snippets, it would be totally awesome!
Don't use XML if you want to use dynamic values.
For simplicity, I wrote my own little demo inside of the default Android Application Project (the newest one that has the fragment). You should be able to adapt to your code as necessary.
public static class PlaceholderFragment extends Fragment {
Button btn_A;
Button btn_B;
TextView hello;
ObjectAnimator mAnimation;
AnimatorSet transSet;
Float valuefrom=0f;
Float valueto=-360f;
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
btn_A= (Button) rootView.findViewById(R.id.button1);
btn_B= (Button) rootView.findViewById(R.id.button2);
hello= (TextView) rootView.findViewById(R.id.textView1);
btn_A.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
if(!transSet.isRunning()){
transSet.start();
}
}
});
btn_B.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Float save = (Float) mAnimation.getAnimatedValue();
Log.d("TAG", "Value" +save);
valuefrom= save;
valueto= save-360;
transSet.cancel();
//re-init the animation
doObjectAnimator();
}
});
//init the animation
doObjectAnimator();
return rootView;
}
public void doObjectAnimator(){
mAnimation= ObjectAnimator.ofFloat(hello, "rotation", valuefrom, valueto);
mAnimation.setInterpolator(new LinearInterpolator());
mAnimation.setDuration(5000);
mAnimation.setRepeatCount(Animation.INFINITE);
mAnimation.setRepeatMode(Animation.RESTART);
//define your other animations here and add them to the set like: set.play(anim1).before(anim2);
transSet= new AnimatorSet();
transSet.play(mAnimation);
}
}
Related
I wanna make a reaction button like Facebook, so something like this
Now i manage to make something similar with a DialogFragment but I am having some trouble with the position of my dialog, this code sometimes works but some other time the dialog is placed in the wrong place. Can someone give me some advice or suggest me a better way to do this?
My Dialog Class
public class ReactionsFragment extends DialogFragment {
public static final String TAG = "ReactionsFragment";
private View paretnView;
public ReactionsFragment(View view, String reviewId,Reactionable reactedContent) {
this.paretnView = view;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_reactions, container, false);
initComponent(view);
setDialogPosition();
return view;
}
public void initComponent(View rootView) {...}
public void setDialogPosition() {
if (paretnView == null) {
return; // Leave the dialog in default position
}
int[] location = new int[2];
paretnView.getLocationOnScreen(location);
int sourceX = location[0];
int sourceY = location[1];
Window window = getDialog().getWindow();
window.setGravity(Gravity.TOP|Gravity.LEFT);
WindowManager.LayoutParams params = window.getAttributes();
params.x = sourceX - dpToPx(0);
params.y = sourceY - dpToPx(110);
window.setAttributes(params);
}
public int dpToPx(float valueInDp) {
DisplayMetrics metrics = getActivity().getResources().getDisplayMetrics();
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
}
Use PopupWindow. I think this is exactly what you are looking for:
https://developer.android.com/reference/android/widget/PopupWindow
You can set the exact position for the popup to appear using this method
I have encountered a weird bug in my fragment class: imageViews "disappear" if I rotate/reload the view. From my understanding, rotating/reloading destroys the View and re-creates it, so local variables and local view elements may not preserve. However, I have made a manual button that should manually render the images again after I click it, yet the ImageViews stay gone even if I manually reset their imageResource or imageBackground resource. Note that these imageviews are animated-drawables. Below is most of my code:
#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 rootView = inflater.inflate(R.layout.fragment_home, container, false);
mView = rootView; //mView is global
return rootView;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d("gnereed id", "id is "+R.id.generate_button);
final Button generate_button = getView().findViewById(R.id.generate_button);
if ( bottleMap == null ) bottleMap = new Hashtable();
// the code sets all images to invisible onCreate
// their visibility will be changed when a bottle is "created"
ImageView[] bottles = new ImageView[7];
for (int i = 0; i < bottleAry.length; i++){
bottles[i] = getView().findViewById(bottleAry[i]);
bottles[i].setVisibility(View.GONE);
}
// this is a button that generates a new bottle and manually refreshes all previous bottle
// If fragment has not been reloaded/rotated then everything works here
// after fragment reloads, new bottles can be generated but old bottles do not re-render.
generate_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Bottle bottle = new Bottle("123", bottleList.size());
bottle.setVisible();
bottleList.add(bottle);
Log.e(" mView : ", mView.toString());
// for all bottles created, re-render them
for (int i = 0; i < bottleList.size(); i ++) {
bottleList.get(i).reRender();
}
}
});
}
public class Bottle{
String message;
ImageView bottleLocation;
int imageSrc;
int avail_index;
int bottle_index;
int locationID;
AnimationDrawable bottleAnimation;
public Bottle(String msg, int bottle_index){
message = msg;
this.bottle_index = bottle_index;
locationID = getRandomBottleLocation();
bottleLocation = getView().findViewById(locationID);
Log.e(" old View : ", getView().toString());
// sets the image source and sets visible, lastly start animation
imageSrc = getRandomBottleImg();
bottleLocation.setBackgroundResource(imageSrc);
bottleMap.put(Integer.toString(locationID), imageSrc);
bottleAnimation = (AnimationDrawable) bottleLocation.getBackground();
bottleAnimation.start();
bottleLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(getActivity(), ViewBottleActivity.class));
availableLocation[avail_index] = false;
bottleMap.remove(Integer.toString(locationID));
bottleAnimation.stop();
bottleLocation.setVisibility(View.GONE);
bottleList.remove(bottle_index);
}
});
}
public int getRandomBottleImg(){
int bottle;
Random rand = new Random();
bottle = imgAry[rand.nextInt(imgAry.length)];
return bottle;
}
public int getRandomBottleLocation(){
int location;
Random rand = new Random();
avail_index = rand.nextInt(bottleAry.length);
while (availableLocation[avail_index]){
avail_index = rand.nextInt(bottleAry.length);
}
location = bottleAry[avail_index];
availableLocation[avail_index] = true;
return location;
}
public void reRender(){
Log.e("location ID is:" , Integer.toString(this.locationID));
bottleLocation = mView.findViewById(this.locationID);
Log.e("ImageView is:" , bottleLocation.toString());
imageSrc = getRandomBottleImg();
bottleLocation.setBackgroundResource(imageSrc);
bottleAnimation = (AnimationDrawable) bottleLocation.getBackground();
bottleAnimation.stop();
bottleAnimation.start();
this.setVisible();
}
public void setVisible(){
bottleLocation.setVisibility(View.VISIBLE);
}
I fixed the problem. What I learned is that you cannot use
View.findViewByID(viewID)
outside of onViewCreated(). Notice how I implemented reRender() function inside the onViewCreated() but it didn't work? The result is that mView.findViewByID(viewID) is actually executed OUTSIDE OF onViewCreated() although I call the function from WITHIN.
Yes, the line will be executed, but upon inspection, mView.findViewByID(viewID) will return TWO DIFFERENT objects when called from inside onViewCreated() and when called from a function that is called from onViewCreated().
This is very counterintuitive, especially for us who's taught to deploy the DRY(do not repeat urself) principle. The fix is just to simply not write outside functions for handling View.
I have a Horizontal Listview with a textview. When I click on a textview in the view, that particular textview gets a border.
public View getView(int position, View convertView, ViewGroup parent) {
View retval = LayoutInflater.from(parent.getContext()).inflate(R.layout.minute_listview, null);
Typeface afBold = Typeface.createFromAsset(getAssets(), "fonts/AftenScreen-Bold.ttf");
minuteText = (TextView) retval.findViewById(R.id.title);
Button button = (Button) retval.findViewById(R.id.clickbutton);
button.setOnClickListener(mOnButtonClicked);
minuteText.setText(dataObjects[position]);
minuteText.setTypeface(afBold);
//THIS IS WHERE THE BORDER GETS SET
minuteText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.setBackgroundResource(R.drawable.border);
}
});
return retval;
}
Now, how can I remove this border and set it on the next textview thats clicked?
Use this it will give you a white background or a translucent one, in other words it has been removed
WhatEverView.setBackground(new ColorDrawable(Color.TRANSPARENT));
okay full code
int pos -1;// default is -1, which means no one has altered it
// replicate this onclick listener logic
minuteText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(pos != -1){ // it is not -1 that means some1 has altered it
parentView.findViewById(pos).
setBackground(new ColorDrawable(Color.TRANSPARENT));
// the above line searched for the view and changed the background
}
pos = v.getId(); // the id of the new view, keep doing it
v.setBackgroundResource(R.drawable.border);
}
});
so use this for all onclick listeners you want that effect on
Does it fit your requirement?
add this
TextView ClicledTv ;//to save the clicked tv id
then
minuteText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(Clickedtv!=null)
clickedtv.setBackground(R.drawable.anotherOne);
v.setBackgroundResource(R.drawable.border);
clickedTv=minuteText;
}
});
I'm struggling with this topic on Android Listview since a few days and I don't seem to get it right. I just can't understand how to do it. I've learned the best I could about Adapters (BaseAdapter specially) but still couldn't think in a way to do this.
I've searched on the web for information but didn't quite get it.
What I wish to do is the following: I want to create a ListView of
contacts.
Each row has 3 horizontal sections: a photo that is constant, content x and content y (this last one is out of the screen and is invisible)
And I wish that when the user swipes a single item
from right to left, the content (with information x) fades out. The
other content (with information Y) slides in from out of the screen,
with right to left orientation, at the same time.
When the user
swipes back (from left to right) the content y swipes out again and
the initial content x fades in.
I just can't to this, so I'm asking your help please.
Thank you very much for your time and effort
Adding such animations to a ListView is no problem, I built this solution for a normal non-custom ListView in a few minutes, generally this sort of thing works on any ListView out of the box, it's all just in the adapter. The only thing missing in my answer is the swipe detection, unfortunately I don't have the time to test that right now. But swipe detection is not difficult and there are a ton of examples if you google it. Anyway if you have questions, feel free to ask.
Result:
I am using a simple BaseAdapter with ViewHolder pattern, nothing special, I will post the getView method anyway for clarification:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(getItemId(position) == TEST_VIEW_ID) {
TestViewModel viewModel = (TestViewModel) getItem(position);
TestRow row;
if(convertView == null) {
convertView = this.inflater.inflate(TestRow.LAYOUT, parent, false);
row = new TestRow(convertView); // Here the magic happens
convertView.setTag(row);
}
row = (TestRow) convertView.getTag();
row.bind(viewModel);
}
return convertView;
}
In my ViewHolder class, here called TestRow I created a few helper methods for the animations, I will explain them further below, but here first my code from TestRow:
public class TestRow {
public static final int LAYOUT = R.layout.list_item_test;
public ImageView ivLogo;
public TextView tvFadeOut;
public TextView tvSlideIn;
public TestRow(View view) {
this.ivLogo = (ImageView) view.findViewById(R.id.ivLogo);
this.tvFadeOut = (TextView) view.findViewById(R.id.tvFadeOut);
this.tvSlideIn = (TextView) view.findViewById(R.id.tvSlideIn);
this.ivLogo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// When the ImageView is clicked the animations are applied to the TextViews.
if(tvFadeOut.getVisibility() == View.VISIBLE) {
fadeOutView(tvFadeOut);
slideInView(tvSlideIn);
} else {
fadeInView(tvFadeOut);
slideOutView(tvSlideIn);
}
}
});
}
public void bind(TestViewModel viewModel) {
// Nothing to do here
}
}
And here are the helper methods i use for the animations:
private void fadeOutView(View view) {
Animation fadeOut = AnimationUtils.loadAnimation(view.getContext(), R.anim.fade_out);
if (fadeOut != null) {
fadeOut.setAnimationListener(new ViewAnimationListener(view) {
#Override
protected void onAnimationStart(View view, Animation animation) {
}
#Override
protected void onAnimationEnd(View view, Animation animation) {
view.setVisibility(View.GONE);
}
});
view.startAnimation(fadeOut);
}
}
private void fadeInView(View view) {
Animation fadeIn = AnimationUtils.loadAnimation(view.getContext(), R.anim.fade_in);
if (fadeIn != null) {
fadeIn.setAnimationListener(new ViewAnimationListener(view) {
#Override
protected void onAnimationStart(View view, Animation animation) {
view.setVisibility(View.VISIBLE);
}
#Override
protected void onAnimationEnd(View view, Animation animation) {
}
});
view.startAnimation(fadeIn);
}
}
private void slideInView(View view) {
Animation slideIn = AnimationUtils.loadAnimation(view.getContext(), R.anim.slide_in_right);
if (slideIn != null) {
slideIn.setAnimationListener(new ViewAnimationListener(view) {
#Override
protected void onAnimationStart(View view, Animation animation) {
view.setVisibility(View.VISIBLE);
}
#Override
protected void onAnimationEnd(View view, Animation animation) {
}
});
view.startAnimation(slideIn);
}
}
private void slideOutView(View view) {
Animation slideOut = AnimationUtils.loadAnimation(view.getContext(), R.anim.slide_out_right);
if (slideOut != null) {
slideOut.setAnimationListener(new ViewAnimationListener(view) {
#Override
protected void onAnimationStart(View view, Animation animation) {
}
#Override
protected void onAnimationEnd(View view, Animation animation) {
view.setVisibility(View.GONE);
}
});
view.startAnimation(slideOut);
}
}
private abstract class ViewAnimationListener implements Animation.AnimationListener {
private final View view;
protected ViewAnimationListener(View view) {
this.view = view;
}
#Override
public void onAnimationStart(Animation animation) {
onAnimationStart(this.view, animation);
}
#Override
public void onAnimationEnd(Animation animation) {
onAnimationEnd(this.view, animation);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
protected abstract void onAnimationStart(View view, Animation animation);
protected abstract void onAnimationEnd(View view, Animation animation);
}
These are the animation xml's I use:
fade in:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha
android:fromAlpha="0"
android:toAlpha="1"
android:duration="700"/>
</set>
fade out:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha
android:fromAlpha="1"
android:toAlpha="0"
android:duration="700"/>
</set>
slide in:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="100%" android:toXDelta="0%"
android:duration="700"/>
</set>
slide out:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="100%"
android:duration="700"/>
</set>
Use this xml in res/anim/ (FOR ANIMATION PURPOSE)
This is for left to right animation:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
This is for right to left animation:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700" />
</set>
In your coding use intent like for left to right:
this.overridePendingTransition(R.anim.animation_enter,
R.anim.animation_leave);
In your coding use intent like for right to left
this.overridePendingTransition(R.anim.animation_leave,
R.anim.animation_enter);
For Custom List View u can use this Code:
http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/
Just catch Gesture event and apply animation, and make one layout which will appear-disappear on gesture event.
If u are Using for normal purpose than working example of exactly what u want is here:
https://github.com/47deg/android-swipelistview
This is actually a memory training app, with matrix of squares wich flips to their other side and than back to first side. And user need to click on squares that flipped. You know what I mean?
Something like that.
What I need is that sizes of the matrix would change dynamically. If user have been passed one level of complexity (matrix size is 4x4 for example), then matrix size would grow (5x5 for example), and if not then matrix size would get smaller (3x3 for example). I hope that's clear, and if not - sorry, English is not my native language =)
So if I would do it from code this would not be a problem. I would use ViewFlipper with some transition animation and create TableView with sizes that I want with inflater or something like that (or directly from code without using xml at all). And then adding it to ViewFlipper from code.
But somehow I don't like that idea.
Then next idea come into my mind. To do ViewFlipper with all possible tableviews in it and then just showNext(); or showPrevious(); depending on what user have done. But in this case XML would be of very great size.
So maybe someone knows the another way to do it?
i suggest you to look view-pager-example,
using viewflipper showNext(); or showPrevious(); you had to download all data at the same time, but using fragmen, you can load only specific data assoiated with fragment.
you can change the view on every fragment like below
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new DetailFragment();
case 1:
return new ImageFragment(R.drawable.ic_launcher);
case 2:
return new ImageFragment(R.drawable.thumb);
default:
return null;
}
}
[EDIT - For checking view in listener]
public class LoginExampleImplements extends Activity implements OnClickListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
btn3.setOnClickListener(this);
btn4.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v==btn1) {
} else if(v==btn2) {
} else if(v==btn3) {
} else if(v==btn4) {
}
}
}
[EDIT 2]
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
LinearLayout1 = (LinearLayout) findViewById(R.id.LinearLayout1);
for (int i = 0; i < 30; i++) {
button = new Button(getApplicationContext());
button.setId(i);
button.setOnClickListener(this);
LinearLayout1.addView(button);
}
}
#Override
public void onClick(View v) {
Button b = (Button)v;
b.getId()
// check clikedId
}
[EDIT 3]
public class MainActivity extends Activity implements OnClickListener{
ImageView img;
LinearLayout LinearLayout1;
LinearLayout.LayoutParams layoutParams;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout1 = (LinearLayout) findViewById(R.id.ln1);
layoutParams = new LinearLayout.LayoutParams(100, 100);
for (int i = 0; i < 30; i++) {
img = new ImageView(getApplicationContext());
img.setId(i);
img.setTag(i);
layoutParams.setMargins(10, 10, 10, 10);
img.setLayoutParams(layoutParams);
img.setBackgroundColor(Color.RED);
img.setPadding(10, 10, 10, 10);
img.setOnClickListener(this);
LinearLayout1.addView(img);
}
}
#Override
public void onClick(View v) {
ImageView b = (ImageView)v;
b.setBackgroundColor(Color.BLUE);
b.setImageLevel(Integer.valueOf(String.valueOf(b.getTag())));
}
}