How to get Talkback's rectangle foucse on DrawerLayer? - android

In my application I use DrawerLayout to show same help information. So I put it over actuall activity. Now I want to add TalckBack function and I cannot make that the any of view in DrawerLayout get the yellow rectangle (which marks focus in talkback mode).
The Drawerlayout view is loaded on demand by inflantign it.
drawerLayout = (DrawerLayout) ((Activity) mContext).findViewById(R.id.drawer);
drawerHelp = (RelativeLayout) LayoutInflater.from(mContext).inflate(R.layout.help, drawerLayout, false);
What I try:
in xml add:
android:focusable="true"
android:focusableInTouchMode="true"
android:importantForAccessibility="yes"
In code:
requestChildFocus()
requestFocus()
requestChildFocusFromTouch()
but still no luck.
So how to force the rectangle mark in talkback mode for ImageButton?

I solve my problem by adding
android:importantForAccessibility="no"
to all element in drawer layout and to other not nedeed elements in help layout.

Related

Block scroll along with Expand/Collapse Collapsible Toolbar

I was using Collapsible Toolbar in my app. On activity launch Collapsible Toolbar is expanded state with scrolling enabled and its working well normally. But now I have a requirement to show a full screen error layout in case my API fails. In that case I have to collapsed toolbar with scrolling effect blocked.
Error Layout shows a Retry Button. On Retry I make API call again and if API gives success I have to again expand Toolbar and enable scrolling effect.
I was able to collapse toolbar with setExpanded(flag, animate) but in that case I am not able to block scrolling effect of Collapsible Toolbar while error layout is shown.
I need to provide a way to block as well as unblock scroll effect + Expand/Collapse Toolbar. Any help would be really appreciated.. !!!
Make your error layout such that it will overlap Collapsible Toolbar. Also set android:clickable="true" to your error layout.
When you set visibility to your error layout, set Toolbar scrolling accordingly.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f3f3f3"
android:orientation="vertical"
>
<!-- Add your other layout including Collapsible Toolbar here.-->
<RelativeLayout
android:id="#+id/errorLayout"
android:clickable="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
I created a library AppBarrr to lock the screen in expanded mode, based on my previous answer.
As I said, the height of the Toolbar is the key: the CollapsingToolbarLayout will collapse until the Toolbar's height and will expand until the AppBarLayout's height.
With this library, you must set two layouts as the Toolbar and your Expanded Layout (used to lock the screen and the scroll), it will create a CollapsingToolbarLayout and inflate these layouts inside.
You can declare the animations duration, the color of the inner CollapsingToolbarLayout, the collapsed/expanded title's style, even the height of the locked layout... You could also hide the Expanded Layout if you click outside it. It can support NestedScrollView and ScrollView inside the Expanded Layout. The documentation and a sample app are available on Github.
For those who don't want to use the library, my previous answer shows the way to do it. Here's the output of the previous answer:
Basically, this is the same concept, but no need to write a full class, with the lib you just need to have a simple widget in xml and that's it!
Feel free to use, fork or test. Hope it will be useful ;)
If you use AlertDialog to communicate the error and a ProgressDialog (spinner) to show you are doing stuff, you can block user input while your app is doing it's thing.
A simple solution that you can apply is just use the property
android:visibility="gone"
for the content that you don't want to show and just make your error layout visible by using property android:visibility="visible"
place the error layout at the bottom of your parent layout
once the contents are not visible on screen and error layout is just visible you will achieve the desired result that you want. Hope this helps you.
You can implement the interface and call its methods when to enable or disable the collapsing effect.
public interface AppbarRequestListener {
void unlockAppBarOpen();
void lockAppBarClosed();
}
#Override
public void unlockAppBarOpen() {
appBarLayout.setExpanded(true, false);
appBarLayout.setActivated(true);
setAppBarDragging(false);
}
#Override
public void lockAppBarClosed() {
appBarLayout.setExpanded(false, false);
appBarLayout.setActivated(false);
setAppBarDragging(false);
}
private void setAppBarDragging(final boolean isEnabled) {
CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
#Override
public boolean canDrag(AppBarLayout appBarLayout) {
return isEnabled;
}
});
params.setBehavior(behavior);
}

When to set Resource for ImageView in Android NavigationDrawer

I have trouble deciding where to set the image of an ImageView contained in the Android NavigationDrawer.
My Android app has a NavigationDrawer that contains an ImageView nested into a couple of other elements inside the NavigationDrawer header layout (app:headerLayout="#layout/navdrawer_header), and my navdrawer_header.xml has the following structure:
<LinearLayout android:id="#+id/navdrawer_header">
...
<ImageView android:id=#+id/image_view
android:layout_width="match_parent"
android:layout_height="match_parent"/>
...
</LinearLayout>
I am setting the image (img.jpg in my drawable folder) via
ImageView imageView = (ImageView) view.findViewById(R.id.image_view);
imageView.setImageResource(R.drawable.img);
If called from OnCreate inside my MainActivity, the imageView will be null and the app crashes. The same if I move the above lines to OnPostCreate or even OnStart.
My understanding is that the view is not initialized yet at that point in time and therefore findViewById returns null. As a workaround, I have overwritten the OnDrawerOpened method and moved my code from above to that method.
This works just fine, but I am pretty sure it is not the best way to go since the method is called every time the drawer is opened. Instead, I would need a method that is only called once upon the creation of the drawer.
What is the best practice here, i.e. where should I set the resource of an ImageView that is contained in the NavigationDrawer?
I have tried omitting view. and experimented with different values of view, for example by assigning to it the NavigationView or DrawerLayout associated with my drawer, but it does not solve the issue.
Try this:
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
View view = navigationView.getHeaderView(0);
ImageView imageView = (ImageView) view.findViewById(R.id.image_view);
imageView.setImageResource(R.drawable.img);

Android Toolbar "Up" Arrow in custom implementation

I am making a very custom Toolbar (don't freak, it's for good, not evil, I promise), and I want to put the "Up" arrow (the arrow that appears when there is a parent Activity set or for other reasons and has the nice ripple touch effect on Lollipop) in a custom location.
Is there a way to get this arrow as a View or asset to use somewhere else in the Toolbar?
I could not even find the image asset for the arrow. Any ideas?
For an example, I want top be able to do something like:
mToolbar.addView(arrowView, 0);
mToolbar.addView(titleView, 1);
Maybe this will help, looks like something that you want, or you want completely custom up button with different position and view?
If you don't want to place arrow icon as custom view in Toolbar, alternatively you can set content description to the navigation button and find view reference later. Every View or ViewGroup supports finding views with content description.
public static View getNavigationIcon(Toolbar toolbar){
//check if contentDescription previously was set
boolean hadContentDescription = TextUtils.isEmpty(toolbar.getNavigationContentDescription());
String contentDescription = !hadContentDescription ? toolbar.getNavigationContentDescription() : "navigationIcon";
toolbar.setNavigationContentDescription(contentDescription);
ArrayList<View> potentialViews = new ArrayList<View>();
//find the view based on it's content description, set programatically or with android:contentDescription
toolbar.findViewsWithText(potentialViews,contentDescription, View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
//Nav icon is always instantiated at this point because calling setNavigationContentDescription ensures its existence
View navIcon = null;
if(potentialViews.size() > 0){
navIcon = potentialViews.get(0); //navigation icon is ImageButton
}
//Clear content description if not previously present
if(hadContentDescription)
toolbar.setNavigationContentDescription(null);
return navIcon;
}
Toolbar is itself a ViewGroup were you can add different views for eg.
<android.support.v7.widget.Toolbar
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
app:theme="#style/ThemeOverlay.AppCompat.ActionBar" >
<TextView ..../>
<ImageView ...../>
</android.support.v7.widget.Toolbar>
Refer your toolbar and its elements from your java code to have control over it as:
Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
ImageView img = (ImageView) toolbar.findViewById(R.id.imgv);

Set NavigationDrawer's ListView margin programmatically

I am currently struggling to design my application the way i want to.
In my app i am using a NavigationDrawer and different fragments. By clicking on an item in the NavigationDrawer i swap out the fragment that is currently active.
There is one main fragment which shows a map and doesn't show a toolbar. When I switch to another fragment I want to show my toolbar and let the user interact with it.
Now when I show the toolbar I have to set the top margin of the NavigationDrawer to the size of the toolbar so it doesn't get overlapped.
When I am showing the toolbar I set the margin of the NavigationDrawer's listview like this:
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mDrawerListView.getLayoutParams();
params.setMargins(0, drawerMarginTop, 0, 0);
mDrawerListView.setLayoutParams(params);
mDrawerListView.requestLayout();
The outcome is like the complete opposite of what i expect. It seems like the margin is applied to the bottom of the view.
Screenshot:
Another thing that annoys me is that the toggle-arrow of the toolbar is not centered correctly. It's a little bit higher than it should be, so it overlaps the system bar in the top and doesn't fill the whole size of the toolbar. I tried to make this clear in the following picture:
If you need any xml or code just let me know and I will edit my question.
Thank you in advance!
EDIT 1+2:
My toolbar style:
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar_navigation"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/my_color"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
</android.support.v7.widget.Toolbar>
EDIT 3:
The Problem with the toggle-arrow not being centered is fixed now. Thanks to Alchete.
Unfortunately the NavigationDrawer is still buggy. I found out that if I open and close the NavigationDrawer many times it somehow changes its layout at one time and the margin is set correctly... Is there any way to force this top happen immediately?
After many times of opening and closing the drawer it looks like this: (Exactly what I want it to look like)
There must be a way to force this immediately, right?
Your alignment issue is most likely due to your toolbar height. You should be setting the toolbar height as follows:
<android.support.v7.widget.Toolbar
android:layout_height="?attr/actionBarSize">
Here's the same issue for reference: android.support.v7.widget.Toolbar icon alignment issue
I would also be using Google's IOSched app for reference on how to set these items up properly. You can find all the code on Github.
Here are their layout files. Scroll down to see their toolbar/navdrawer layouts: https://github.com/google/iosched/tree/dfaf8b83ad1b3e7c8d1af0b08d59caf4223e0b95/android/src/main/res/layout
And, also note that Google's reference design is to OVERLAP the toolbar with the navdrawer -- which is not how you have it. And, the right margin should be equivalent to the toolbar height.
See here: http://www.google.com/design/spec/patterns/navigation-drawer.html
I'm not 100% about this but it looks like you're setting the ViewGroup layout params to be of type MarginLayoutParams. Instead, set the margin on a 'normal' root ViewGroup type e.g. RelativeLayout and pass that to the View:
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT);
params.setMargins(0, drawerMarginTop, 0, 0);
mDrawerListView.setLayoutParams(params);
mDrawerListView.requestLayout();
You may want to change MATCH_PARENT to WRAP_CONTENT depending on your xml.

Use DrawerLayout and FlyOutContainer

I have a problem, I would like to put in my Layout the Drawer Layout and the FlyOutContainer but in the error Log it shows an error:that DrawerLayout cannot be cast to FlyOutContainer what can I do to fix this problem. I need the Drawer Layout to go to the MainActivity.
Hope you can help me and sorry for my bad english.
The code in that demo inflates a layout and casts the root view of the Layout to FlyOutContainer. If you change your layout xml so that the root is now DrawerLayout, then that code no longer runs correctly and you are probably getting ClassCastException. You should do it this way instead (in onCreate()):
setContentView(R.layout.your_activity_layout);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout_id);
FlyOutContainer flyOutContainner = (FlyOutContainer) findViewById(R.id.fly_out_container_id);
Of course, if you don't actually need a reference to these views/layouts, you can just stop after setContentView(...)

Categories

Resources