On some devices such as Samsung S8, navigation bar can be hide or show, that's a question in some condition.
Samsung S8's navigation bar can be hide or show by click left bottom button
I didn't find straight way to determine even if in the Android sources code.
And I google some issues, such as A good solution to check for navigation bar , but it doesn't help.
Any help is very appreciated.
First, credit the original author: https://www.jianshu.com/p/ddfbabd614b6
For the Samsung phones (i.e, S8, S9, etc) you can detect if the navigation bar is showing via listening to a Samsung event.
private static final String SAMSUNG_NAVIGATION_EVENT = "navigationbar_hide_bar_enabled";
Then just listen to this event, and do your thing:
private void checkNavigationBar() {
if (isSamsungVersionNougat()) { // check if Samsung phones
// detect navigation bar
try {
// there are navigation bar
if (Settings.Global.getInt(activity.getContentResolver(), SAMSUNG_NAVIGATION_EVENT) == 0) {
// Your code
// example: galleryViewModel.navigationBarHeight.set(getNavigationBarHeight());
} else { // there are no navigation bar
// Your code
// example: galleryViewModel.navigationBarHeight.set(0);
}
} catch (Exception ignored) {
}
barHideEnableObserver = new BarHideEnableObserver(new Handler());
activity.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(SAMSUNG_NAVIGATION_EVENT),
true, barHideEnableObserver);
} else {
galleryViewModel.navigationBarHeight.set(getNavigationBarHeight());
}
}
Use this method, worked for me. Make sure the view has been rendered first to make sure that getHeight() doesn't return 0. Also make sure that the rootView you are using is meant to take up the whole screen.
public static boolean hasNavBar (Activity activity, View rootView) {
if (activity == null || rootView == null)
return true;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
return true;
Display d = activity.getWindowManager().getDefaultDisplay();
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
d.getRealMetrics(realDisplayMetrics);
int viewHeight = rootView.getHeight();
if (viewHeight == 0)
return true;
int realHeight = realDisplayMetrics.heightPixels;
return realHeight != viewHeight;
}
Related
Currently, this is how I implement Chrome custom tabs
String url = "http://www.google.com/";
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(WelcomeFragment.this.getActivity(), Uri.parse(url));
I was wondering, is it possible to have Chrome custom tabs as View object?
The reason I'm asking so that that, previously, I have a fragment, which is having ViewAnimator object. ViewAnimator will in-turn animate between 2 WebViews.
One WevView is displaying mobile version of the web page. Another WebView is displaying desktop version of the web page.
Here's the code which used to alternate between the 2 WebViews
public void updateWebView() {
int index = getCurrentWebViewHolderIndex();
final WebViewHolder webViewHolder = webViewHolders[index];
if (webViewHolder == null) {
return;
}
final WebView webView = webViewHolder.webView;
boolean loadUrl = false;
boolean reload = false;
synchronized (monitor) {
if (false == webViewHolder.loadUrl) {
webViewHolder.loadUrl = true;
loadUrl = true;
} else if (webViewHolder.error) {
webViewHolder.error = false;
reload = true;
}
}
if (loadUrl) {
webView.loadUrl(getUrl(index));
} else if (reload) {
webView.reload();
}
final WebViewFragmentActivity activity = (WebViewFragmentActivity)WebViewFragment.this.getActivity();
if (activity != null) {
final int progress = webViewHolder.progress;
if (progress >= 100) {
activity.setProgressBarVisibilityEx(false);
} else {
activity.setProgressBarVisibilityEx(true);
activity.setProgressEx(progress);
}
}
if (index == 0) {
// Slide from left.
Animation slideInLeftFast = AnimationUtils.loadAnimation(this.getActivity(), R.anim.slide_in_left_fast);
Animation slideOutRightSlow = AnimationUtils.loadAnimation(this.getActivity(), R.anim.slide_out_right_slow);
this.webViewViewAnimator.setInAnimation(slideInLeftFast);
this.webViewViewAnimator.setOutAnimation(slideOutRightSlow);
} else {
// Slide from right.
Animation slideInRightFast = AnimationUtils.loadAnimation(this.getActivity(), R.anim.slide_in_right_fast);
Animation slideOutLeftSlow = AnimationUtils.loadAnimation(this.getActivity(), R.anim.slide_out_left_slow);
this.webViewViewAnimator.setInAnimation(slideInRightFast);
this.webViewViewAnimator.setOutAnimation(slideOutLeftSlow);
}
if (webViewViewAnimator.getChildCount() >= 2) {
webViewViewAnimator.removeViewAt(0);
}
webViewViewAnimator.addView(webView);
webViewViewAnimator.setDisplayedChild(webViewViewAnimator.getChildCount() - 1);
}
Here's the XML code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/web_view_linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal" >
<ViewAnimator
android:id="#+id/web_view_view_animator"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
</LinearLayout>
I was told that Chrome Custom Tabs is having a much better performance than WebView.
However, I don't find a way, to let single fragment holding 2 different Chrome Custom Tabs. As, they are Intent, not View.
But, is there any way, to have Chrome custom tabs as View object?
Chrome Custom Tabs, will launch its own UI on a full screen. You cannot have it like a View in XML or Java/Kotlin.
As per the docs here - https://developer.chrome.com/docs/android/custom-tabs/overview/, it lets you customize 3 things in the UI only -
Toolbar color
Enter and exit animations
Add custom actions to the browser toolbar, overflow menu and bottom toolbar
Is it possible to programmatically detect when a menu is overflowed?
My intention is to have a menu item always be visible (SHOW_AS_ACTION_ALWAYS), except for in the case where it would cause other items to overflow, in which case, don't show the menu item at all. That is:
if (overflowed) actionBarMenu.removeItem(id);
You are not saying where this menu is appearing, so I'll just give an example of what you can do with a Toolbar. What you need to do is to get the reference to the ActionMenuView from the Toolbar and then call isOverflowMenuShowing on it, something like this:
private boolean isOverflowShowing(Toolbar toolbar) {
if(toolbar == null) {
return false;
}
for(int i = 0; i < toolbarView.getChildCount(); i++) {
View v = toolbarView.getChildAt(i);
if(v instanceof ActionMenuView) {
return ((ActionMenuView)v).isOverflowMenuShowing();
}
}
return false;
}
This is crude and dirty - and I haven't tested it - but it should get you started.
I have created a small library to place Views beside/above/below an existing View (e.g. Help arrow or something like that), I use
MainView.getLocationOnScreen(..);
to determine the position of the Main View where the Sibling View will be placed nearby.
Usually I'm determining the top (Y) of the Main View by the method above minus the height of the status bar using the following method:
protected boolean isTranslucentStaturBar()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window w = ((Activity) mainActionView.getContext()).getWindow();
--> return // SOME EXPRESSION TO DETERMINE IF THE STATUS BAR IS TRANSLUCENT <--- ?????
// I Need to know what expression I need to write here
// i.e. How to ready the flag: WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
}
return false;
}
protected int getStatusBarHeight() {
if (isTranslucentStaturBar()) {
return 0;
}
int result = 0;
int resourceId = mainActionView.getContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = mainActionView.getContext().getResources().getDimensionPixelSize(resourceId);
}
return result;
}
My problem is with Androids >= Kitkat, where you can actually set the status bar to translucent and window content spread to fill the place below the status bard icons..
OK so after digging deeply, I reached out to this solution:
protected boolean isTranslucentStatusBar()
{
Window w = ((Activity) mainActionView.getContext()).getWindow();
WindowManager.LayoutParams lp = w.getAttributes();
int flags = lp.flags;
// Here I'm comparing the binary value of Translucent Status Bar with flags in the window
if ((flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) {
return true;
}
return false;
}
Thanks mate! Translated to Xamarin Android:
bool trans;
var flags = Window.Attributes.Flags;
if ((flags & WindowManagerFlags.TranslucentStatus) == WindowManagerFlags.TranslucentStatus)
trans = true;
else
trans = false;
Hi am using a SwipeListView that has two buttons on its back view i'm trying to programatically set the SwipeListView so that it doesn't swipe by setting the swipe mode to none. the problem i am having is the front view is now not registering the click. Does any one know why???
Heres what i have tried so far
final SwipeListView messagesList = (SwipeListView)v.findViewById(R.id.list);
if(r_deleteMessages == false || r_markMessages == false) messagesList.setSwipeMode(SwipeListView.SWIPE_MODE_NONE);
if(messageData != null){
ViewGroup.LayoutParams params = messagesList.getLayoutParams();
int size;
size = messageData.size();
params.height = (SM_Global.pxFromDp(context, 80) * size) +3;
messagesList.setLayoutParams(params);
messagesList.requestLayout();
messagesList.setFocusable(false);
final MessagesAdapter messagesAdapter = new MessagesAdapter(context, R.layout.layout_message_item, messageData,messagesList,"profile");
messagesList.setAdapter(messagesAdapter);
Log.v("Auth","CAN READ MESSAGES | " + r_readMessages);
messagesList.setSwipeListViewListener(new BaseSwipeListViewListener() {
#Override
public void onClickFrontView(int position) {
super.onClickFrontView(position);
Log.v("Auth","CLICKED ");
}
});
You could add a Listener to the list view and override onChangeSwipeMode
if(r_deleteMessages == false || r_markMessages == false){
mList.setSwipeListViewListener(new BaseSwipeListViewListener() {
#Override
public int onChangeSwipeMode(int position) {
return SwipeListView.SWIPE_MODE_NONE;
}
});
}
This way you will still get touch events.
You may also need to do mList.setSwipeOpenOnLongPress(false); to disablr the long click
see: https://github.com/47deg/android-swipelistview/issues/9
I tried the suggested ways but didn't work for me. So I made changes in my List Adapter & handled the click event there. Now it is working fine.
I have an app where I handle all the touches myself instead of using touch and gesture detection APIs, because it is a floating window and is the only way that works.
One of the things I do is change the color of the view under the finger.
OnTouch I check which view is under the finger if it is different from the previous I run:
myView.setBackgroundColor(getResources().getColor(R.color.white));
It doesn't work when I go to the view next to the current and return very fast.
I have checked it with logs and the view found is correct. And I have also checked and the line where setBackgroundColor is, is executed.
So I don't know what else to do. Are any cases in which setBackgroundColor doesn't work? Is it that if onTouch takes too much time to execute doesn't finish its tasks?
Any clue of how to fix this?
EDIT:
It only fails when I go to the view next to the current and return fast.
I didn't add the code because I thought it was harder to read than the abstraction I did. I have cleaned it up and posted.
If you think any methods called are relevant I can add them.
EDIT 2:
Code that runs if ACTION is not ACTION_DOWN or ACTION_UP. Those cases are not related.
if ((isPortrait && isPortraitMeasured) || (!isPortrait && isLandscapeMeasured)) {
//Log.d("algor", "Here calculate where it is");
final int lastCol = currentColumn;
final int lastRow = currentRow;
findCell((int) event.getRawX(), (int) event.getRawY());
if ((lastCol == currentColumn && lastRow == currentRow)) {
if (isPortrait && currentRow==-1 || (!isPortrait && currentColumn==-1)
&& !wasPressed && currentTable!=mainTable) {
//is actionBar. Check if finger is over back icon, to go back
//Code not related to the problem...
}
} else {
int currentIndex = getAppsListIndex();
if (currentIndex >= 0) {
View nextApp;
if (isPortrait)
nextApp = cellsP.get(currentTable).get(currentIndex);
else
nextApp = cellsL.get(currentTable).get(currentIndex);
final Object tag = nextApp.getTag();
if (tag instanceof FolderData) {
//Code not related to the problem...
} else {
Log.d("fastf", "time to change color");
//nextApp.setBackgroundColor(getResources().getColor(R.color.white));
nextApp.setBackgroundColor(whiteColor);
//nextApp.setBackground(getResources().getDrawable(R.color.white));
/*final View app = nextApp;
app.post(new Runnable() {
#Override
public void run() {
app.setBackgroundColor(getResources().getColor(R.color.white));
}
});*/
}
} else {
//Code not related to the problem...
}
int lastIndex = getAppsIndexFromInts(lastRow, lastCol);
//lastCol != -2 is because otherwise, on opening the launcher it animates
// the last app launched
if (lastIndex >= 0 && lastCol != -2) {
View lastApp;
if (isPortrait)
lastApp = cellsP.get(currentTable).get(lastIndex);
else
lastApp = cellsL.get(currentTable).get(lastIndex);
ObjectAnimator animator = ObjectAnimator.ofInt(lastApp,
"backgroundColor", getResources().getColor(R.color.clear_gray),
getResources().getColor(R.color.white_overlay_transition));
animator.setDuration(500);
animator.setEvaluator(new ArgbEvaluator());
animator.start();
}
}
}
You should use
nextApp.setBackgroundResource(...) instead of others.
Because of your "R.color.white" is a resource.
Have a nice day.
It was an old question but, I faced same problem and resolved with this change.
try it
myView.setBackground(getResources().getDrawable(R.color.white));
myView.setBackgroundColor(getResources().getColor(R.color.bgcolor));
color.xml
<color name="bgcolor">#ffffff</color>