I added a SwitchCompat to my Drawernavigation in Android.
First I set the item's actionlayout to my switchlayout.xml:
<android.support.v7.widget.SwitchCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="right|center_vertical"
app:buttonTint="#color/colorPrimary"
app:switchPadding="16dp" />
Now I'm trying to change the Buttons checkedstate in my Code, I'm trying switchCopmatObj.toggle() and also tried switchCompatObj.setChecked(!switchCompatObj.isChecked())
But it only changes the Color of the Switch, but doesn't play the animation where the Switch moves from one side to the other. How do I play this animation from my code?
I faced the same issue. It seems that SwitchCompat is broken on this point. setChecked() calls the animator that should update the thumb drawable but the onAnimationEnd is never called.
Meanwhile after many tries faking the touch events send to the SwitchCompat, I found an ugly workaround : instead of calling setChecked(), I remove the item from the menu and add it again :
// Update toggle state
mDrawerView.getMenu().removeItem(R.id.drawer_menu_availability);
final SwitchCompat toggle = (SwitchCompat) LayoutInflater.from(this).inflate(R.layout.drawer_menu_item_availability, null);
toggle.setChecked(mAvailable);
toggle.setOnCheckedChangeListener((buttonView, isChecked) -> toggleAvailability());
final MenuItem added = mDrawerView.getMenu().add(R.id.drawer_menu_group_actions, R.id.drawer_menu_availability, Menu.FIRST, text);
added.setActionView(toggle);
This however forces you to :
have an id for the menu group where your menu item is located
use android:orderInCategory to order your menu items so that your item goes back to the same place when adding it back.
Hope this helps.
EDIT : This does not play the animation but at least the thumb is in the right place.
Related
I got a view and in xml it is visible
<LinearLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
Then I do some manipulation with the data and I make it to invisible
container.visibility = INVISIBLE
But I have reset button that suppose to set the container back to visible after click
resetBtn.setOnClickListener {
this.runOnUiThread { // tried this from stack overflow answers
container.visibility = VISIBLE
container.invalidate()} // tried this from stack overflow answers
}
But after click I still do not see that container appears. What might be the issue?
first of all, be sure that resetBtn is referred to exactly your desired XML file. it's better to use view binding instead of kotlin synthetic.
then try one of these lines in your click listener:
container.visibility = View.VISIBLE
or
container.isVisible = true
Try to put log inside setOnClickLitener to check whether click works or not.If log message does not appear, it means you have problem with button
Actually, I use a ListView and when I use setClickable(false) I have the animation as if I clicked on a button you see? The animation that shows you click. Which is not normal, I think, basic.
And when I use setClickable(true) I no longer have the animation, as well as if I use
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
And i would like to use the OnClickListener but I think it would be better for the user to see that he can click, so to have the animation when you click.
So, I'd like to see when the user clicks on an item in the list, it does the action I want (I'll add that later) but let's imagine a Toast but it displays the effect as if you click on a button. The effect i got if i use setClickable(false) (the default setting).
That's the ripple effect !
In the row's layout of the ListView just add:
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
This will add the Ripple effect. If you want to show it on top of the other views, use the forground attribute:
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
add this foreground:?attr/selectableItemBackground to your view attribute, it should work
I have a list with elements that use a custom layout which consists of a text view and an image view. For this, I follow ViewHolder pattern like explained here. The image views display one of two icons and I want to change the icon of the clicked image view.
So my first approach was to define the on click listener of the ImageViews in the overridden getView function of my adapter class. The problem is that when the icon of the first ImageView changes and I scroll down to the last its icon changed as well. This question here was not helpful.
Here I found that it's not the best way to handle the click in the getView function but it's better to do it in the listView.setOnItemClickListener. I tried it but I am not able to find out whether an ImageView was clicked or not as the parent object holds the list item and the view parameter the LinearLayout in which the ImageView is contained (even when I click directly in the ImageView). Setting android:focusable="false" of the outer LinearLayout as it is suggested here did not help.
I'm sure someone must have had this issue / use case but I'm not able to find a solution. So, what's the best way to handle the click of the ImageView in my custon list item view?
Try adding the following attributes to the clickable ImageView instead of its ViewGroup, your LinearLayout:
android:focusable="false"
android:focusableInTouchMode="false"
... and as far as updating UI in a AdapterView/ListView/RecyclerView goes, you should make good use of an int flag that tracks the position of the list item that was clicked, and then set it as a conditional statement in getView() before invoking notifyDataSetChanged(), since "every other" row will be updated, especially in lists of say, 100 rows.
I actually answered this in a similar question here and here.
If you have two icons, you can simply put a custom checkbox instead of an imageview :
<CheckBox
android:id="#+id/customchechecbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/checkbox_selector"
android:button="#android:color/transparent" />
checkbox_selector :
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#drawable/checkbox"
android:state_checked="false"/>
<item android:drawable="#drawable/checkboxselected"
android:state_checked="true"/>
<item android:drawable="#drawable/checkbox"/>
</selector>
I have a dialog containing a list of notes, and I want to make the user scroll to the end of the list to find the "OK" button to close the dialog.
The dialog contains a ListView and I add the button to the list using the footer row.
View footerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).
inflate(R.layout.list_footer_button, null, false);
listView.addFooterView(footerView);
When i turn on talk back and open this dialog, it reads the wrong count for the ListView as it is including the footer row. For example if my list has 3 items, talkback reads "Item 1 of 4".
ISSUE
How can i get talkBack to read the correct number of items ignoring the footer row?
OR
If i can't change this, how else do i create a dialog where the user has to scroll to the end of the list before seeing the button to dismiss the dialog.
I have resolved this issue by adding the button to the View for the last row rather than adding a footer.
My layout for each row contains a textView and a button, and the button is set to be "invisible".
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout android:id="#+id/notes_details"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- other views here but removed for this post -->
<TextView
android:id="#+id/notes_text"
style="#style/notes_text_style"/>
</LinearLayout>
<Button
android:id="#+id/notes_button"
style="#style/notes_button"
android:layout_below="#id/notes_details"
android:layout_centerHorizontal="true"
android:visibility="invisible" />
</RelativeLayout>
In the adapter for the list, I show/hide the button based on whether the row is the last row
boolean isLastRow = iPosition == getCount()-1;
okButton.setVisibility(isLastRow ? View.VISIBLE : View.GONE);
Accessibility changes needed
There was additional work to make this all work for Accessibility purposes. If no changes were made to support accessibility, only the rows are navigatable. Therefore the last row will select the notes text and OK button as one selectable item and you would not be able to navigate to the button using a keyboard/trackerball.
Firstly you have to set the list so that items in a row are focusable
listView.setItemsCanFocus(true);
Secondly, in code in the adapter, i set the focusable/nextFocusXXX on the notes textView and button accordingly
// when in accessibility mode, we want to set the navigation order for
// the list item's text and the OK button
boolean isLastRow = iPosition == getCount()-1;
if (isAccessibilityEnabled) {
notesTextView.setFocusable(true);
okButton.setFocusable(true);
rowView.setNextFocusForwardId(isLastRow ? R.id.notes_button: R.id.notes_text);
rowView.setNextFocusDownId(isLastRow ? R.id.notes_button: R.id.notes_text);
okButton.setNextFocusUpId(R.id.notes_text);
}
I had another usecase with this issue.
Requirements
I have a screen containing a list of items and I have a Floating Action Button (FAB) on the bottom right of the screen allowing the user to add items to the list. On the right hand side of each row is a button presenting options for that row item.
I need the FAB to not overlay the last row in the list, otherwise I am never able to click on the right hand button of the last row as it will be under the FAB.
Solutions and their issues
I tried several solutions. One was adding an extra count to the list items and when getting the view for this last row I return an empty view, the height of the FAB. I also tried adding this empty padding row as the list footer. In both cases TalkBack reads one too many for the number of items in the list.
I can not use the solution I have posted for this question for my list of notes. I need the FAB to always be in the bottom right hand side of the screen (not just after the last row) even if there are only 1 or 2 items in the list or over a screen-full of items.
Working Solution
Adding the last 4 attributes in the code below to my list definition in the xml layout seems to solve the issue. There are no additional items added to the list so TalkBack reads the list count correctly and the following ensures the FAB in the bottom left of the screen never overlaps the last row.
<!-- Instead of adding a footer row to stay clear of the FAB,
add a padding to the listView and set clipToPadding to false
android:overScrollFooter is set to transparent to avoid having a divider
for the last item so there is just white space below the last item -->
<ListView
style="#style/my_list_style"
android:layout_alignParentTop="true"
android:paddingBottom="82dp"
android:clipToPadding="false"
android:footerDividersEnabled="false"
android:overScrollFooter="#android:color/transparent"/>
I would like to do the same thing than the GMail application on Honeycomb tablets.
When you click on the Refresh button, the icon is replaced by a ProgressBar.
How can I do this?
Thanks
Ok, I tried what Cailean suggested but it didn't work for me. Every time I want to revert indeterminate progress to the original button it becomes unclickable, I used this layout for the progress
(actionbar_refresh_progress.xml)
<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"/>
and this one to revert to the button
(actionbar_refresh_button.xml)
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/ic_menu_refresh_holo_light"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
my code was:
private void setRefreshing(boolean refreshing) {
this.refreshing = refreshing;
if(refreshMenuItem == null) return;
View refreshView;
LayoutInflater inflater = (LayoutInflater)getActionBar().getThemedContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(refreshing)
refreshView = inflater.inflate(R.layout.actionbar_refresh_progress, null);
else
refreshView = inflater.inflate(R.layout.actionbar_refresh_button, null);
refreshMenuItem.setActionView(refreshView);
}
After browsing the source of the Google IO app, especially this file: http://code.google.com/p/iosched/source/browse/android/src/com/google/android/apps/iosched/ui/HomeActivity.java i found another easier way.
Now I need only the first layout with progress and the working method looks like this:
private void setRefreshing(boolean refreshing) {
this.refreshing = refreshing;
if(refreshMenuItem == null) return;
if(refreshing)
refreshMenuItem.setActionView(R.layout.actionbar_refresh_progress);
else
refreshMenuItem.setActionView(null);
}
Menu item definition:
<item android:id="#+id/mail_refresh"
android:title="Refresh"
android:icon="#drawable/ic_menu_refresh_holo_light"
android:showAsAction="always"/>
I hope someone finds this useful.
Gmail does this using an action view for its "refresh in progress" state. Invoking a refresh is done using the standard action button/onMenuItemSelected path.
When you enter your refreshing state, set the action view of the refresh MenuItem to a ProgressBar. (Create it programmatically, inflate it from a layout, use actionLayout in the menu xml as CommonsWare suggests, whatever you prefer.) When you exit your refreshing state, set the action view back to null while keeping a reference to it so you can set it back again the next time you refresh. You can hang onto a reference to the MenuItem after you inflate the menu and changes to it later will be reflected in the action bar.
This approach has some advantages over using a full-time action view and managing other details of the state change yourself. An action view completely replaces the generated action button for a menu item, effectively blocking the user from being able to send the usual onMenuItemSelected events for refresh while a refresh is already in progress. One less thing to handle and the action view can stay completely non-interactive.
You could probably do something clever with an ActionProvider in API 14+ to encapsulate the whole process a bit more but the above ends up being pretty simple.
Assuming that you already have your menu item setup, you'll need to start by creating two new layouts. One that contains the layout for the normal refresh button, and another that contains the progressbar.
Once you have them, call the following piece of code to switch between the two layouts. It'll be up to you to decide exactly when it needs to be called a second time in order to switch it back to the refresh icon.
private void doRefresh(Boolean refreshing, MenuItem menuItem)
{
View refreshView;
LayoutInflater inflater = (LayoutInflater) getActionBar().getThemedContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(refreshing)
refreshView = inflater.inflate(R.layout.actionbar_indeterminate_progress, null);
else
refreshView = inflater.inflate(R.layout.refresh_icon, null);
menuItem.setActionView(refreshView);
}
Use the following layout as the action view for the action bar menu item.
actionbar_refresh_progress.xml
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="#dimen/abc_action_button_min_width"
android:minWidth="#dimen/abc_action_button_min_width">
<ProgressBar
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
style="?indeterminateProgressStyle" />
</FrameLayout>
Then
menuItem.setActionView(R.layout.actionbar_refresh_progress);
Works across Gingerbread and the rest like a charm. Note that I have used dimension from support action bar for compatibility. You can use #dimen/action_button_min_width instead for ICS and up.
Source: https://code.google.com/p/iosched/source/browse/android/res/layout/actionbar_indeterminate_progress.xml?r=f4fd7504d43b25a75cc23b58d6f844f3553b48c3