Note: I've seen the existing question titled "Align Snackbar's Action on the right", however this does not address my particular question.
According to the material design spec the action in a snackbar should be right/end aligned. The default behaviour on smaller screens seems to work as expected (full width of screen, action is aligned to the right of the screen), but on tablets I'm seeing the action immediately next to the description/title text with some padding. Example here:
Snackbar action position example
I've seen this on a real Nexus 9 (api 25), and 3 emulators (api 22, 23, and 24) in both portrait and landscape.
The layout xml for the snackbar contents in the Android source (design_layout_snackbar_include.xml) seems to suggest the action button should be right/end aligned so I'm a bit baffled as to why I'm not seeing this.
I first saw this occurring in one of the apps my company is developing, and I've now made a test app to reproduce the issue (which I used to produce the example image linked earlier). All the app does is display "Hello World!" in an activity, and when the back button is pressed a snackbar is shown to confirm the action. My test activity looks like this:
package au.com.test.snackbartest;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity
{
#Override
protected void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
}
#Override
public void onBackPressed()
{
Snackbar snackbar = Snackbar.make( findViewById( R.id.activity_main ), "Exit?", Snackbar.LENGTH_LONG );
snackbar.setAction( "EXIT", new View.OnClickListener()
{
#Override
public void onClick( View v )
{
finish();
}
} );
snackbar.show();
}
}
The layout xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="#+id/activity_main"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="au.com.test.snackbartest.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"/>
</RelativeLayout>
Using a coordinator layout instead of relative layout doesn't affect this behaviour. Also, extending Activity instead of AppCompatActivity makes no difference either.
So my question is, am I using the snackbar wrong somehow, is this a bug in Android, or is the design spec simply left up to the developer to fully implement with a custom snackbar layout?
Any help or clarification on this would be greatly appreciated!
This is a bug introduced with the 25.1.0 support library. Reverting back to 25.0.1 results in the correct behaviour. Turns out a bug report had already been filed here:
Issue 231850: Snackbar Action Text Not Right-Aligned in 25.1.0
Thanks ianhanniballake for the suggestion of it being a regression in the support library update.
Related
I have searched a lot for this on stackoverflow and on some other professional websites but not found any solution.
I have tried different methods but result was about 0. Some methods work for me but only in that condition when I clicked in top menu navigation bar. But I don't want to show action/top navigation bar.
I only want to show these items in bottomnavigation bar like Recent News, Hot Stories, Most Visited. There are three activities which I want to start by clicking on these items, because my app is a webview app.
For this purpose I am using onOptionItemSelected I think that's wrong. So question goes here >>
I have three buttons in bottom navigation.
(action_item1) = on click it should start second_activity
(action_item2) = on click it should start third_activity
(action_item3) = on click it should start fourth_activity
Please help me I am new in android studio.
Navigation XML is here!
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/action_item1"
android:icon="#drawable/ic_recent"
android:title="Recent News" />
<item
android:id="#+id/action_item2"
android:icon="#drawable/ic_hot"
android:title="Hot Stories" />
<item
android:id="#+id/action_item3"
android:icon="#drawable/ic_most"
android:title="Most Visited" />
</menu>
Mainactivity.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.pkg.webview.webview">
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
android:layout_marginStart="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/navigation" />
</android.support.constraint.ConstraintLayout>
Mainactivity.java
package com.pkg.webview.webview;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebView;
public class MainActivity extends AppCompatActivity{
private ProgressBar pb;
private WebView webView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
getSupportActionBar ().hide ();
setContentView (R.layout.activity_main);}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater ().inflate (R.menu.navigation, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId ()) {
case R.id.action_item1:
startActivity (new Intent (this, secondactivity.class));
break;
}
return super.onOptionsItemSelected (item);
}
}
From what I have understood, you want to implement Bottom Navigation and open different activities/screens for different items.
I have searched a lot for this on stackoverflow and on some other professional websites but not found any solution.
Everything is not available for copy paste as per your requirement.
I only want to show these items in bottomnavigation bar like Recent News, Hot Stories, Most Visited. There are three activities which I want to start by clicking on these items because my app is a webview app.
To dive into more details refer this tutorial. For your simplicity in this tutiorial Bottom Navigation is implemented through BottomNavigationView provided in android.support.design.widget.BottomNavigationView and fragments are used for different screens as per our requirement.
I want to start by clicking on these items because my app is a webview app.
You can open webview inside these fragments. eg in OnCreate of your fragment you can load webview.
Please help me I am new in android studio.
As a community, we always Welcome New People. Follow the community guidelines and feel free to ask anything after you have done your thorough research.
It's a good thing that you started, now Instead of diving directly into it, take a step back and understand it's working.
May the force be with you..
Hope this helps.
Happy Coding...
For an app I'm developing I wanted to reload the UI after a user input (basically resetting it completely after they made changes to it). I wanted to try avoiding destroying/recreating the activity and use setContentView() instead because it's a lot faster.
However when I do that I'm having an issue: the newly created UI doesn't respect the fitsSystemWindows="true" and part of it ends up behind the android's status bar.
I managed to boil it down to that code example to test it :
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<Button
android:text="Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/button" />
</LinearLayout>
MainActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
reloadUI();
}
});
}
public void reloadUI() {
setContentView(R.layout.layout);
}
}
When I load the app, I get the expected layout, that is a simple button on top of the screen, right below the status bar:
However, once I click the button which calls setContentView a second time (showing the same XML), the Button gets behind the status bar:
Calling mainContainer.getMeasuredHeight() to check what happens gives me 1848px on the first start of the app (on a screen that is 1920px tall, so its height is 72px less than the whole screen, 72px being the height of the status bar), but once I call setContentView again the mainContainer.getMeasuredHeight() gives me 1920px.
Am I missing something here? I could force the mainContainer to stick to a 1848px height with a 72px top padding, but I'd prefer to avoid an ugly hack like this.
So, what you want is to ask the framework to dispatch once more WindowInsets to your root view. That's precisely what ViewCompat.requestApplyInsets(View) will do:
Ask that a new dispatch of View.onApplyWindowInsets(WindowInsets) be performed. This falls back to View.requestFitSystemWindows() where available.
Applying just one line should resolve all your concerns:
public void reloadUI() {
setContentView(R.layout.layout);
// `R.id.mainContainer` is the id of the root view in `R.layout.layout`
ViewCompat.requestApplyInsets(findViewById(R.id.mainContainer));
}
I had the same problem. My solution is to change the rootView marginTop or paddingTop to adapt to the View manually.
Background
I have a rather complex layout being shown to the user in an activity.
One of the views is an EditText.
Since I had to make one of the views stay behind the soft-keyboard, yet the rest above it, I had to listen to view-layout changes (written about it here).
The problem
I've noticed that whenever the EditText has focus and shows its caret, the entire view-hierarchy gets re-layout.
You can see it by either looking at the log of the listener I've created, or by enabling "show surface updates" via the developers settings.
This causes bad performance on some devices, especially if the layout of the activity is complex or have fragments that have complex layouts.
The code
I'm not going to show the original code, but there is a simple way to reproduce the issue:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.user.myapplication.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="just some text"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="phone"
android:text="write here"
android:textSize="18dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="just some text 2"/>
</LinearLayout>
</FrameLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(android.R.id.content).getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
#Override
public boolean onPreDraw() {
Log.d("AppLog", "onPreDraw");
return true;
}
});
}
}
What I've tried
When disabling the caret (using "cursorVisible", which for some reason is called a "cursor" instead) , I can see that the problem doesn't exist.
I've tried to find an alternative to the built-in caret behavior, but I can't find. Only thing I've found is this post, but it seems to make it static and I'm not sure as to how well it performs (performance and compatibility vs normal caret).
I've tried to set the size of the EditText forcefully, so that it won't need to cause invalidation of the layout that contains it. It didn't work.
I've also noticed that on the original app, the logs can (for some reason) continue being written even when the app goes to the background.
I've reported about this issue (including sample and video) here, hoping that Google will show what's wrong or a fix for this.
The question
Is there a way to avoid the re-layout of the entire view hierarchy ? A way that will still let the EditText have the same look&feel of normal EditText?
Maybe a way to customize how the EditText behaves with the caret?
I've noticed that whenever the EditText has focus and shows its caret,
the entire view-hierarchy gets re-layout.
This is not true. Size and position of EditText is constant - there is no re-layouting. You can check it by using code below.
findViewById(android.R.id.content).getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Log.d("AppLog", "Layout phase");
}
});
Because of blinking caret - EditText constatly calls invalidate(). This forces the GPU to draw EditText again.
On my nexus 5 (marshmallow) I see that only EditText beeing redrawn (Show GPU view updates - enabled).
How about overriding dispatchOnPreDraw() all the vies you use in activity and having flag to check whether that specific view needs to redraw ?
As you need to disable redraw of all other views only when a text view is on focus. So when a text view is on focus have a flag to disable the redrawing of other views.
if dispatchOnPreDraw() method returns false then refreshing of view will be continues else not. I don't know how complex is your layout and how many views are used, but here a separate class should extent a view used and override that method, and also need a mechanism/variable to distinguish the object in current focus.
Hope this method helps!
I'm developing an app with SupportMapFragment and custom view switching mechanism. Right now i styles app, to make its window to be transparent using styles.xml, but with that change i see a strange problem when using maps. When user switches it current view from one that uses map fragment to another, part of screen that was used by map on previous view becames transparent, for about 1 second.
In image below i present some description, on right i marked using yellow color situation than im talking about:
on left side is view that i present map using SupportMapFragment, on the right is one i have switched next, with 2 diffrent views(ImageView and TextView),but yellow part of TextView is transparent like my application window, su user can notice eg. apps menu. This is not what im trying to achive so Im looking way to get rid of this effect.
My code for switching views is like follows:
public void switchAppView(View view){
mMainView.removeViewAt(0);
mMainView.addView(view,0);
}
the mMainView is initialized in onCreate Method, by code:
#Override
public void onCreate(Bundle icicle){
super.onCreate(icicle);
setContentView(R.layout.activity_main);
mMainView = (RelativeLayout) findViewById(R.id.mymain_layout);
}
my activity_main.xml layout presents similar to:
<RelativeLayout
android:id="#+id/mymain_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="#+id/replacable"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="visible"
></FrameLayout>
<FrameLayout
android:id="#+id/extra"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="invisible"
></FrameLayout>
</RelativeLayout>
I tried to search clues and situations like that but I didnt find any, so if anyone can help i would be grateful, Thanks for help.
becames transparent, for about 1 second.
I'm guessing you are using black background and you really mean it becomes black.
In that case what you see is a known issue.
You may read more about it here:
http://code.google.com/p/gmaps-api-issues/issues/detail?id=4659
and here:
http://code.google.com/p/gmaps-api-issues/issues/detail?id=4639
I have a faux dialog which uses this layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/containerPageConatiner">
<FrameLayout android:id="#+id/dialogHolder"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:padding="15dp"
android:layout_gravity="center"
android:background="#drawable/panel_picture_frame_bg_focus_blue"/>
</FrameLayout>
I place a fragment inside the <FrameLayout> depending on the dialog which is opening - The activity controlling the Dialog looks like this:
<activity
android:label="#string/app_name"
android:name=".activity.DialogActivity"
android:theme="#style/CustomTheme.Screen.Transparent"
android:windowSoftInputMode="adjustResize">
Unfortunately when you click on an edit text inside of the dialog, no resizing takes place. The windowSoftInputMode literally makes no difference as the functionality is the same as pan mode.
Documentation says "This of course only works for applications that have a resizeable area that can be reduced to make enough space" but doesn't tell you what it means by "a resizeable area" and makes me think that in some way I don't have a resizeable area?
If anyone knows what's up can they help me out?
EDIT
Surrounding the dialog like so doesn't change anything:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/containerPageConatiner"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<FrameLayout
android:id="#+id/dialogHolder"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:padding="15dp"
android:layout_gravity="center"
android:background="#drawable/panel_picture_frame_bg_focus_blue"/>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
EDIT2
Scrollview as parent doesn't help either:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/containerPageConatiner"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/dialogHolder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="15dp" />
</ScrollView>
I created a new project in order to try and get the basic features working for window resizing and the slowly moved it towards the target peice of my project. Doing this I tracked the problem down to this:
In my theme hierarchy I had this property:
<item name="android:windowFullscreen">true</item>
which was burried at the level of Theme.Black.NoTitleBar.FullScreen - An ancestor of my custom theme.
The documentation suggests that this is a "Flag indicating whether this window should fill the entire screen". That sounds like a good thing to have if you have an app which takes up the whole screen... Except it still takes up the whole screen without the flag.
In fact, once you've taken this out, there is absolutely no change in the app at all... apart from adjustResize now works perfectly.
A while back i also had the same issue in a library i've created. (MaterialDrawer)
As far as i can see all the provided answers don't solve the main issue, they just point to remove the fullscreen flag (android:windowFullscreen), which is no solution for many out there.
The above mentioned "issue" only appears in Android versions starting with API Level 19 (KITKAT), because they changed the behavior. To be correct it is no issue, it is working as intended. See the comment by a Android employee (Android-Issue).
So i started digging around the Android source and came to the following solution by using the ViewTreeObserver.OnGlobalLayoutListener and reacting if the Keyboard gets shown / or hidden. If the Keyboard gets shown i add the padding to the bottom of the container view which will then emulate the same as the adjustResize would do.
Solution
To simplify the usage i've wrapped the whole thing in a simple KeyboardUtil helper class.
/**
* Created by mikepenz on 14.03.15.
* This class implements a hack to change the layout padding on bottom if the keyboard is shown
* to allow long lists with editTextViews
* Basic idea for this solution found here: http://stackoverflow.com/a/9108219/325479
*/
public class KeyboardUtil {
private View decorView;
private View contentView;
public KeyboardUtil(Activity act, View contentView) {
this.decorView = act.getWindow().getDecorView();
this.contentView = contentView;
//only required on newer android versions. it was working on API level 19 (Build.VERSION_CODES.KITKAT)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
decorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
}
}
public void enable() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
decorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
}
}
public void disable() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
decorView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
}
}
//a small helper to allow showing the editText focus
ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
decorView.getWindowVisibleDisplayFrame(r);
//get screen height and calculate the difference with the useable area from the r
int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
int diff = height - r.bottom;
//if it could be a keyboard add the padding to the view
if (diff != 0) {
// if the use-able screen height differs from the total screen height we assume that it shows a keyboard now
//check if the padding is 0 (if yes set the padding for the keyboard)
if (contentView.getPaddingBottom() != diff) {
//set the padding of the contentView for the keyboard
contentView.setPadding(0, 0, 0, diff);
}
} else {
//check if the padding is != 0 (if yes reset the padding)
if (contentView.getPaddingBottom() != 0) {
//reset the padding of the contentView
contentView.setPadding(0, 0, 0, 0);
}
}
}
};
/**
* Helper to hide the keyboard
*
* #param act
*/
public static void hideKeyboard(Activity act) {
if (act != null && act.getCurrentFocus() != null) {
InputMethodManager inputMethodManager = (InputMethodManager) act.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(act.getCurrentFocus().getWindowToken(), 0);
}
}
}
You can then use it in your activity or fragment by doing the following:
//initialize the KeyboardUtil (you can do this global)
KeyboardUtil keyboardUtil = new KeyboardUtil(activity, getContent().getChildAt(0));
//enable it
keyboardUtil.enable();
//disable it
keyboardUtil.disable();
The whole util class is used in the above mentioned library MaterialDrawer and can be found here KeyboardUtil. This will always contain the latest version. (if there are improvements)
It seems that the problem is with FrameLayout, as it behaves that way, that each child occupying visible space of that frame, therefore no need to resize to fit children.
Try to use RelativeLayout. It should work.
Without using a ScrollView as my parent I just added android:fitsSystemWindows="true" to my parent view (which was a RelativeLayout) and adjustResize to the Manifest for the activity and it worked.
Try to put your LinearLayout on a ScrollView, that worked for me once..
I've had to set
<item name="android:windowFullscreen">false</item>
Despite, I've never set it to true and app actually wasn't full screen.
As original poster discovered when the Fullscreen Flag is assigned to an activity the android:windowFullscreen attribute will not work and so your window will not resize when the soft keyboard is visible and it won't be scrollable.
Simply removing the Fullscreen flag and not using a Fullscreen theme will allow scrolling when the soft keyboard is visible.
I don't know why, but if you have <item name="android:windowTranslucentNavigation">true</item> in your theme, change it to false. And it will start working. Really strange.
Ensure you set windowTranslucentStatus to false in your styles.