That title was sort of a mouthful. Basically, I have these CardViews within a RecyclerView. I have a faux animation to expand and shrink the CardViews when they're clicked. I do this by setting various elements inside them to View.GONE or View.VISIBLE depending on if the card is expanded or not.
Here is the code for expanding/collapsing the cards:
// Expand the CardView
private boolean expand(View cardView) {
// Make the shortened ("intro") text invisible and make the full text visible
mIntroTextView.setVisibility(View.GONE);
mExpandableIndicator.setVisibility(View.GONE);
mCollapseIndicator.setVisibility(View.VISIBLE);
mInfoTextView.setVisibility(View.VISIBLE);
return true;
}
// Collapse the CardView
private boolean collapse(View cardView) {
// Make the shortened ("intro") text visible and make the full text invisible
mInfoTextView.setVisibility(View.GONE);
mCollapseIndicator.setVisibility(View.GONE);
mExpandableIndicator.setVisibility(View.VISIBLE);
mIntroTextView.setVisibility(View.VISIBLE);
return false;
}
It works fine except if I tap a card while scrolling, the card will move out of place, overlapping with other cards as shown in these pictures:
https://imgur.com/a/XJ901
I can provide other code if needed.
Any ideas? Thank you!
Related
Creating a really basic Memory game using Java Swing. I created my GUI with a list of blank buttons where I set the icon property to none.
My code for some of the buttons is:
private void tbtnCard3ActionPerformed(java.awt.event.ActionEvent evt) {
tbtnCard3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Card3Logo.png")));
if(tbtnCard5.isSelected()){
score++;
lblScore.setText(""+score);
}
}
private void tbtnCard4ActionPerformed(java.awt.event.ActionEvent evt) {
tbtnCard4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Card7EWaste.png")));
if(tbtnCard7.isSelected()){
score++;
lblScore.setText(""+score);
}
}
private void tbtnCard5ActionPerformed(java.awt.event.ActionEvent evt) {
tbtnCard5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Card3Logo.png")));
if(tbtnCard3.isSelected()){
score++;
lblScore.setText(""+score);
}
}
I have about 20 toggle buttons and for example the code above works and the scores go up by 1 when a match is found. So for tbtnCard3, if tbtnCard5 is selected the score goes up by 1. Now my question is how would I make it so that if tbtnCard3 is selected but tbtnCard 5 is not selected, display "Wrong Match". Since im using if Selected I'm not too sure how to display "wrong match" when the case is false. It doesn't make sense to say else ifSelected as no parameters can be put either....
In my opinion, the OPs suggestion is not a good approach. You do not want the listener of one button to be "aware" of some other component unnecessarily. Suppose you have an 8-by-8 grid with toggle buttons. You don't want each toggle button listener to be aware of the other 63 toggle buttons.
I believe there is a much simpler (and cleaner) approach. What you want is for the toggle button listener to register and deregister the toggle when the state of the button changes. Let say, you add the toggle button to or remove from a list (most likely a custom class) where you can trigger some logic when the list size reaches two. Then, depending on the outcome of the comparison, it will count a match (and disable these two toggle buttons in the current state), or will display some message like "Try again" and then toggle the buttons to hide the image.
In pseudocode, this will look something like this:
public class ToggleListener implements ItemListener {
public void actionPerformed (ItemEvent event) {
JToggleButton button = (JToggleButton) event.getSource();
if (event.getStateChange()==ItemEvent.SELECTED) {
// TODO Add the button to your list..
} else {
// remove button
}
}
}
In your Swing application, you can create a single instance of the above listener and add it to every single toggle button. And, as you can see, this listener is only responsible to register and unregister the component associated with the triggered event.
The "List Listener" on the other hand, is responsible to trigger the comparison logic when the size of the list reaches two. So, if you click on the same toggle button over and over again, the only thing the button listener will do is add or remove the button from the list depending on the button's current state. However, once a second button is toggled to reveal its image, the list listener will trigger the comparison logic. I am not 100% sure, but I think you could use JavaFX ObservableList interface or one of its implementing classes to do this. If the ListChangeListener.Change class is not suitable to figure out the size of the list to trigger the logic, you will have to implement this on your own. Regardless, in pseudocode, you need to do something like this:
public void onListChange(Event event) {
if (list.size() == 2 && btn1.getIconName().equals(btn2.getIconName())) {
displayMatchMessage();
btn1.setEnabled(false);
btn2.setEnabled(false);
list.clear(); // you should remove matched items from list manually
} else {
displayMismatchMessage();
btn1.setSelected(false); // flip the card
btn2.setSelected(false); // flip the card
// list.clear(); // you should not need this because the setSelected should trigger the Item Listener which should remove item from list.
}
}
Doing something like this is a much cleaner implementation where the button listener have a single job to do and the "list listener" has another job to do. Neither one encroaches on the other's job.
I my app I am fetch some text data from the server and showing this text data in the TextView. Here is something works fine. I am add an little arrow ImageView right to the TextView and this TextView is expandable so when TextView is more then 2 lines and if anyone click this TextView it expand and again click to shrink and I am also add an little arrow image right to the TextView (so user understant that it is an expandable text), here is everything is fine all code are works perfectly but now I want to remove this litter arrow image when the TextView is under 2 lines and when TextView is more then 2 lines it show. I want to tell you one more thing that I am also add a rotation in the arrow image so when the user click the text the little arrow image rotate the 180 degree and also text is expand and when user click the text second time arrow image again rotate to his previous position and text is shrink in 2 lines.
I want to remove this little arrow when the text is under 2 lies I do not want to remove the arrow image when text line more then 2, I'm guessing you understand.
I am new to the Java Code and I am learning is language so now I want to learn how to do this implementation in my app, I have add my code below so that you can understand batter.
textViewMyVideoTitle.setText(videoLists.get(0).getVideo_title());
my_title_layout_expand.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (isTextViewClicked) {
//This will shrink textview to 2 lines if it is expanded.
textViewMyVideoTitle.setText(videoLists.get(0).getVideo_title());
myTitleImageView.setRotation(imageView.getRotation() + 0);
myTitleImageView.setVisibility(View.VISIBLE);
textViewMyVideoTitle.setMaxLines(2);
isTextViewClicked = false;
} else {
//This will expand the textview if it is of 2 lines
textViewMyVideoTitle.setText(videoLists.get(0).getVideo_title());
myTitleImageView.setRotation(imageView.getRotation() - 180);
myTitleImageView.setVisibility(View.VISIBLE);
textViewMyVideoTitle.setMaxLines(Integer.MAX_VALUE);
isTextViewClicked = true;
}
}
});
So anybody can help me to achieve this code
As you say, your text doesnt have more than 2 lines, so your function wont work until the text has more than 2 lines.
You may try to use TextView's getLineCount() method to get this info and decide.
So I mean outside your onClickListener do something like this:
if (textViewMyVideoTitle.getLineCount() <= 2) {
my_title_layout_expand.setVisibility(View.VISIBLE);
} else {
my_title_layout_expand.setVisibility(View.GONE);
}
Or since it gives you the right number only after layout been 'rendered' you might need the following:
textViewMyVideoTitle.post(new Runnable() {
#Override
public void run() {
// Get the line count and put the if-else statement here
}});
FIXED: I was incorrectly updating my ListView adapter. see: How to refresh Android listview?
I have been struggling with an incredibly weird bug for too long of a time, and I wonder if any of you have had similar problems.
A detailed explanation of the bug will be less clear than for me to just show you, so I have attached a gif that displays exactly what goes wrong below.
http://giphy.com/gifs/xT9DPGixQnDIEHlVU4
Question 5 is included to show you how things are supposed to wrong. Then, when the CardView and the ListView inside it resize because the amount of options changes at question 6, the following goes wrong:
- The colors of the listview items do not get updated according to their correctness. (should be either green or a light shade of red)
- The checked RadioButton weirdly gets unchecked, right before I click the button.
Note: this bug only appears once upon resizing of the Listview. Everything proceeds to work fine once a similar size optionlist is supplied at the next question
These actions take place upon the second click of the button, which calls the following code
/*
FOR EACH LISTITEM:
> Make button unclickable
> Animate background change according to correctness of answer
*/
for (int i = 0; i < currentQuestion.getOptionList().size(); i++) {
ListView optionList = (ListView) rootView.findViewById(R.id.optionList);
View item = (View) optionList.getChildAt(i);
item.findViewById(R.id.optionRadioButton).setClickable(false);
final LinearLayout llayout = (LinearLayout) item.findViewById(R.id.itemLinearLayout);
int colorTo = getResources().getColor(R.color.lightPrimary);
if (currentQuestion.getOptionList().get(i).equals(currentQuestion.getAnswer())) {
colorTo = getResources().getColor(R.color.correct);
}
int colorFrom = getResources().getColor(R.color.white);
ValueAnimator colorAnimation = backgroundColorAnimator(
colorFrom,
colorTo,
llayout,
i);
colorAnimation.start();
}
// Bottom part of list view is animated SEPERATELY.
// please note that THIS DOES GET UPDATED ACCORDINGLY.
int colorFrom = getResources().getColor(R.color.white);
int colorTo = getResources().getColor(R.color.lightPrimary);
// Also increments question correct counter (important
if (correctAnswerSelected) {
colorTo = getResources().getColor(R.color.correct);
currentExercise.questionCorrectlyAnswered();
}
ValueAnimator anim = backgroundColorAnimator(
colorFrom,
colorTo,
fabContainer,currentQuestion.getOptionList().size()+1);
anim.start();
My hypothesis: Somehow, upon resizing the CardView / RelativeLayout / ListView, the ListView gets reinitiated and I call a different version of it. I suspect this is the cause because the lower part of the CardView (a FAB within a FrameLayout) does change color accordingly.
Any and all help is appreciated, I am at a complete loss with this question
Thanks in advance.
I'm trying to implement an animation which crossfades between 2 layout, with a layover between them. The first layout is the main layout, the second is a simple linear layout with textView and red background (your classic "Wrong!" screen if you will...). My goal is to animate a quick transition between the mainLayout and wrongLayout, have the program wait for a short period of time while displaying the wrongLayout and then automatically return to mainLayout. This turns out to be extremelly hard, I've tried using monitors, Thread.sleep() etc. but what I get is that the program waits before starting the animation and THEN performs it without any layover.
My code is as follows:
In the main method-
LinearLayout wrongLayout = (LinearLayout) findViewById(R.id.wrong_layout);
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_layout);
int animationDuration = getResources().getInteger(
android.R.integer.config_longAnimTime);
crossfade(wrongLayout, mainLayout, animationDuration);
/* This is where I want it to wait for 1 second */
crossfade(mainLayout, wrongLayout, animationDuration);
and the crossfade method-
private void crossfade(View fadeInLayout, final View fadeOutLayout,
int animationDuration) {
// Set the content view to 0% opacity but visible, so that it is visible
// (but fully transparent) during the animation.
fadeInLayout.setAlpha(0f);
fadeInLayout.setVisibility(View.VISIBLE);
// Animate the content view to 100% opacity, and clear any animation
// listener set on the view.
fadeInLayout.animate()
.alpha(1f)
.setDuration(animationDuration)
.setListener(null);
// Animate the loading view to 0% opacity. After the animation ends,
// set its visibility to GONE as an optimization step (it won't
// participate in layout passes, etc.)
fadeOutLayout.animate()
.alpha(0f)
.setDuration(animationDuration)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fadeOutLayout.setVisibility(View.GONE);
}
});
}
Thanks a lot...
Ok, so I've found this post which deals with just about the same problem-
Why the Sleep executes first and than the code above it in android?
I've changed the appropriate execution function and now it seems to work properly, though I'm still puzzled by the fact that I cannot cause the code to stop at a designated location for a specific amount of time. Oh well...
Here is my scenario.
I have an image which is made as per resolution 320*480 (assuming i am using mdpi mobile). I am adding this image as a background to a relative layout.
Now my screen has three main things.
1- Title bar (The standard title bar of android)
2- My relative layout and its sub view image relative layout which is matched parent.
3- My menu bar at the bottom.
Now since my image is getting stretched in between menu bar and title bar. I want to make it fit the screen. Below is the code I am using.
mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout()
{
if (notCreated == true)
{
notCreated = false;
}
else
{
mnHeight = mainLayout.getHeight();
Rect rect = getRawCoordinatesRect(mainLayout);
h = getWindowManager().getDefaultDisplay().getHeight() -
- rect.top - mainLayout.getHeight();
// rect.top to remove android standard title bar
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(image.getWidth(),LayoutParams.MATCH_PARENT);
params.topMargin = -1 * rect.top;
params.bottomMargin = -1 * h;
image.setLayoutParams(params);
}
}
});
Now this is not working. A little help would be appreciated.
Note: Actually I just want to stretch my image relative layout to 320*480. Right now it is sandwitched between title bar and my menu bar. E.g right now its dimensions are 320*400
Not sure if it will help, but try to play with setScaleType() trying different options.
image.setScaleType(ScaleType.FIT_CENTER);
Here are listed all the constans the ScaleType class has.
I must be honest and say i'm not completely sure what you want to do here. But i'm going to assume that you want to make the image function as a background..
If that's what you want, you can do this simply by setting the android:background="#drawable/your_image" attribute on the main layout in your layout file.
If what you want is remove the titlebar, this is done pretty simple by adding this line to your onCreate method in your activity class:
//Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
If what you want to do is remove the notificationbar, this is also done in the onCreate method in your activity class:
//Remove notification bar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
I hope this can help you :-) If it's not what you're looking for, then dont hesitate from trying to reformulate what you want.