I'm trying to get e Menu inside my fragment a little more custom. The Code does some resizing on the Button-Symbol which I created (is there by the way any better solution for this?) the Text & Font of the Button are also customized.
The Code runs in a Standalone Activity, running it in a Fragment doesn't work anymore:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_main, container,true);
final Button events = view.findViewById(R.id.events);
// BUTTON FONT THEME
String etext = "<font color=#FFFFFF>NEXT</font> <font color=#8def00> EVENTS </font>";
if (Build.VERSION.SDK_INT >= 24) {
events.setText(Html.fromHtml(etext, 0)); // for 24 api and more
} else {
events.setText(Html.fromHtml(etext)); // or for older api
}
events.setTypeface(ralewayfont);
Drawable iconevents = ContextCompat.getDrawable(getApplicationContext(),R.drawable.ic_calendar);
int WIconCal = iconevents.getIntrinsicWidth();
int HIconCal = iconevents.getIntrinsicHeight();
iconevents.setBounds(0,0,WIconCal/3,HIconCal/3);
events.setCompoundDrawables(iconevents, null, null, null);
}
It doesn't give me any errors - it doesn't resize the Images and doesn't set the custom font on the Buttons.
You should make more layout files that target specific API versions. In your case, I would make a /res/layout-v24/fragment_main.xml and set your v24-specific button attributes there. No need to do all the stuff your doing in your code snippet. Just inflate the layout like you are doing, connect your button with findViewById(), and Android OS will automatically know to use the layout-v24 version if it detects a phone using v24 or higher. Anything below v24 will use your default /res/layout/fragment_main.xml.
Hope that helps!
Related
I'm a fairly new developer, so please go easy on me.
I'm making a chat app, and I'm planning on adding support for custom emojis, similar to how Discord manages custom emojis. However, my app is crashing once I tap on the emoji button. I want it to inflate my layout (emoji_keyboard_layout.xml) and view that in a LinearLayout in ChatActivity.
I've tried adding the view itself to the layout (yeah that didn't work in my case, but if that is the only solution possible, then I will try it again) and I've also tried modifying my onClick, modifying the actual method, but whatever I did, nothing would fix it.
My openEmojiKeyboard method:
private void openEmojiKeyboard(Boolean EMOJI_STATE, Boolean GIF_STATE)
{
View emojiKey = getLayoutInflater().inflate(R.layout.emoji_keyboard_layout, llEmojiKeyboard);
llEmojiKeyboard.addView(emojiKey);
llEmojiKeyboard.setVisibility(View.VISIBLE);
hideKeyboard(etMessage);
final LinearLayout llSelectContent = emojiKey.findViewById(R.id.llSelectContent);
final LinearLayout llSelectToolbar = emojiKey.findViewById(R.id.llSelectToolbar);
final LinearLayout llEmoji = emojiKey.findViewById(R.id.llEmoji);
final LinearLayout llGif = emojiKey.findViewById(R.id.llGif);
final LinearLayout llEmojiSelected = emojiKey.findViewById(R.id.llEmojiSelected);
final LinearLayout llGifSelected = emojiKey.findViewById(R.id.llGifSelected);
final TextView tvEmptyContent = emojiKey.findViewById(R.id.tvEmptyContent);
final TextView tvEmptyContent1 = emojiKey.findViewById(R.id.tvEmptyContent1);
if (EMOJI_STATE && !GIF_STATE) // The emoji keyboard is open, gif keyboard is closed
{
llEmojiSelected.setVisibility(View.VISIBLE);
llGifSelected.setVisibility(View.GONE);
tvEmptyContent1.setText(R.string.add_emoji);
tvEmptyContent.setText(R.string.empty_emoji_content);
}
else if (GIF_STATE && !EMOJI_STATE) // The gif keyboard is open, emoji keyboard is closed
{
llGifSelected.setVisibility(View.VISIBLE);
llEmojiSelected.setVisibility(View.GONE);
tvEmptyContent1.setText(R.string.retry);
tvEmptyContent.setText(R.string.empty_gif_content);
}
}
My activity's onClick event:
case R.id.ivEmoji:
openEmojiKeyboard(EMOJI_STATE, GIF_STATE);
break;
The emoji keyboard functionality is not ready yet, just preparing the layout
Stack Trace
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Crashing on lines llEmojiKeyboard.addView(emojiKey); and openEmojiKeyboard(EMOJI_STATE, GIF_STATE);
The error you have indicated in the logs is telling you that the view (emojiKey) already has a parent (root) view. This is because you passed llEmojiKeyboard as a root view via the second argument in LayoutInflater.inflate(). Since this is already the root view, you don't need to call .addView() after inflating, or if the .addView() call is necessary, you can pass a boolean as a third argument to .inflate() to control whether the newly inflated view gets attached to the root ViewGroup (here is the documentation for that version of the .inflate() method):
View emojiKey = getLayoutInflater().inflate(R.layout.emoji_keyboard_layout, llEmojiKeyboard, false);
In my Android app there is a requirement that a number of UI elements should be disabled until a button click carryout. Can I disable all the UI elements in a layout by referring the layout without disable them one by one. Is it possible.Can some one help me.
You could disable all views recursively like this.
Just pass the layout as view to the method:
private void enableViews(View v, boolean enabled) {
if (v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) v;
for (int i = 0;i<vg.getChildCount();i++) {
enableViews(vg.getChildAt(i), enabled);
}
}
v.setEnabled(enabled);
}
Just run enableViews(view, false) to disable, or enableViews(view, true) to enable again.
use following attribute in your xml layout( as a example textView)
android:visibility="gone"
in button click event
myText.setVisible(myText.VISIBLE)
you can either use them one by one or you can put all invisible content in a single layout and hide the layout. then once you want to show them, just VISIBLE the layout. then all will display
need any more comment.. just comment.
I used the following hack to change the homeAsupIndicator programmatically.
int upId = Resources.getSystem().getIdentifier("up", "id", "android");
if (upId > 0) {
ImageView up = (ImageView) findViewById(upId);
up.setImageResource(R.drawable.ic_action_bar_menu);
up.setPadding(0, 0, 20, 0);
}
But this is not working on most new phones (HTC One, Galaxy S3, etc). Is there a way that can be changed uniformly across devices. I need it to be changed only on home screen. Other screens would have the default one. So cannot use the styles.xml
This is what i did to acheive the behavior. I inherited the base theme and created a new theme to use it as a theme for the specific activity.
<style name="CustomActivityTheme" parent="AppTheme">
<item name="android:homeAsUpIndicator">#drawable/custom_home_as_up_icon</item>
</style>
and in the android manifest i made the activity theme as the above.
<activity
android:name="com.example.CustomActivity"
android:theme="#style/CustomActivityTheme" >
</activity>
works great. Will update again when i check on all devices I have. Thanks #faylon for pointing in the right direction
The question was to change dynamically the Up Home Indicator, although this answer was accepting and it is about Themes and Styles. I found a way to do this programmatically, according to Adneal's answer which gives me the clue and specially the right way to do. I used the below snippet code and it works well on (tested) devices with APIs mentioned here.
For lower APIs, I use R.id.up which is not available on higher API. That's why, I retrieve this id by a little workaround which is getting the parent of home button (android.R.id.home) and its first child (android.R.id.up):
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// get the parent view of home (app icon) imageview
ViewGroup home = (ViewGroup) findViewById(android.R.id.home).getParent();
// get the first child (up imageview)
( (ImageView) home.getChildAt(0) )
// change the icon according to your needs
.setImageResource(R.drawable.custom_icon_up));
} else {
// get the up imageview directly with R.id.up
( (ImageView) findViewById(R.id.up) )
.setImageResource(R.drawable.custom_icon_up));
}
Note: If you don't use the SDK condition, you will get some NullPointerException.
API 18 has new methods ActionBar.setHomeAsUpIndicator() - unfortunately these aren't supported in the support library at this moment
http://developer.android.com/reference/android/app/ActionBar.html#setHomeAsUpIndicator(android.graphics.drawable.Drawable)
edit: these are now supported by the support library
http://developer.android.com/reference/android/support/v7/app/ActionBar.html#setHomeAsUpIndicator(android.graphics.drawable.Drawable)
All you need to do is to use this line of code:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
This will change the icon with the up indicator. To disable it later, just call this function again and pass false as the param.
The solution by checking Resources.getSystem() doesn't work on all devices, A better solution to change the homeAsUpIndicator is to set it #null in style and change the logo resource programmatically.
Below is my code from style.xml
<style name="Theme.HomeScreen" parent="AppBaseTheme">
<item name="displayOptions">showHome|useLogo</item>
<item name="homeAsUpIndicator">#null</item>
<item name="android:homeAsUpIndicator">#null</item>
</style>
In code you can change the logo using setLogo() method.
getSupportActionBar().setLogo(R.drawable.abc_ic_ab_back_holo_light); //for ActionBarCompat
getActionBar().setLogo(R.drawable.abc_ic_ab_back_holo_light); //for default actionbar for post 3.0 devices
Also note that the Android API 18 has methods to edit the homeAsUpIndicator programatically, refer documentation.
You can achieve this in an easier way. Try to can change the homeAsUpIndicator attribute of actionBarStyle in your theme.xml and styles.xml.
If you want some padding, just add some white space in your image.
You can try this:
this.getSupportActionBar().setHomeAsUpIndicator( R.drawable.actionbar_indicator ); //for ActionBarCompat
this.getActionBar().setHomeAsUpIndicator( R.drawable.actionbar_indicator ); //for default actionbar for post 3.0 devices
If you need change the position of the icon, you must create a drawable file containing a "layer-list" like this:
actionbar_indicator.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="#drawable/indicator"
android:right="5dp"
android:left="10dp" />
</layer-list>
use getActionBar().setCustomView(int yourView); because ActionBar haven't method to change homeUp icon!
Adding to Fllo answer Change the actionbar homeAsUpIndicator Programamtically
I was able to use this hack on Android 4+ but could not understand why the up/home indicator was back to the default one when search widget was expanded. Looking at the view hierarchy, turns out that the up/home indicator + icon section of the action bar has 2 implementations and of course the first on is the one for when the search widget is not expanded. So here is the code I used to work around this and get the up/home indicator changed in both cases.
mSearchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
// https://stackoverflow.com/questions/17585892/change-the-actionbar-homeasupindicator-programamtically
int actionBarId = getResources().getIdentifier("android:id/action_bar", null, null);
View view = getActivity().getWindow().getDecorView().findViewById(actionBarId);
if (view == null
|| !(view instanceof ViewGroup)) {
return true;
}
final ViewGroup actionBarView = (ViewGroup)view;
// The second home view is only inflated after
// setOnActionExpandListener() is first called
actionBarView.post(new Runnable() {
#Override
public void run() {
//The 2 ActionBarView$HomeView views are always children of the same view group
//However, they are not always children of the ActionBarView itself
//(depends on OS version)
int upId = getResources().getIdentifier("android:id/up", null, null);
View upView = actionBarView.findViewById(upId);
ViewParent viewParent = upView.getParent();
if (viewParent == null) {
return;
}
viewParent = viewParent.getParent();
if (viewParent == null
|| !(viewParent instanceof ViewGroup)) {
return;
}
ViewGroup viewGroup = (ViewGroup) viewParent;
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = viewGroup.getChildAt(i);
if (childView instanceof ViewGroup) {
ViewGroup homeView = (ViewGroup) childView;
upView = homeView.findViewById(upId);
if (upView != null
&& upView instanceof ImageView) {
Drawable upDrawable = getResources().getDrawable(R.drawable.ic_ab_back_holo_dark_am);
upDrawable.setColorFilter(accentColorInt, PorterDuff.Mode.MULTIPLY);
((ImageView) upView).setImageDrawable(upDrawable);
}
}
}
}
});
If someone uses the library support-v7 appcompat, you can directly call this method:
getSupportActionBar().setHomeAsUpIndicator(int redId)
In other case you can use this solution:
https://stackoverflow.com/a/23522910/944630
If you are using DrawerLayout with ActionBarDrawerToggle, then check out this answer.
this.getSupportActionBar().setDisplayUseLogoEnabled(true);
this.getSupportActionBar().setLogo(R.drawable.about_selected);
Also you can define the logo in manifest in attribute android:logo of and tags and set in theme that you want to use logo instead of app icon in the action bar.
I know how to change the homeAsUpIndicator in the styles xml file. The question is how to change it programmatically.
The reason I want to do it because in some views I support side navigation (sliding menu) - pressing the up/back title button, shows the side menu.
In other views I support the natural up/back botton.
Thus I would like to different indicator icons to indicate the two different logics - side navigation vs. up/back.
Please, lets not argue on the motivation of doing this. That's the given state. Thanks.
int upId = Resources.getSystem().getIdentifier("up", "id", "android");
if (upId > 0) {
ImageView up = (ImageView) findViewById(upId);
up.setImageResource(R.drawable.ic_drawer_indicator);
}
The solution by #matthias doesn't work on all devices, A better solution to change the homeAsUpIndicator is to set it #null in style and change the logo resource programmatically.
Below is my code from style.xml
<style name="Theme.HomeScreen" parent="AppBaseTheme">
<item name="displayOptions">showHome|useLogo</item>
<item name="homeAsUpIndicator">#null</item>
<item name="android:homeAsUpIndicator">#null</item>
</style>
In code you can change the logo using setLogo() method.
getSupportActionBar().setLogo(R.drawable.abc_ic_ab_back_holo_light); //for ActionBarCompat
getActionBar().setLogo(R.drawable.abc_ic_ab_back_holo_light); //for default actionbar for post 3.0 devices
Also note that the Android API 18 has methods to edit the homeAsUpIndicator programatically, refer documentation.
This worked for me
getSupportActionBar().setHomeAsUpIndicator(R.drawable.my_home_as_up)
Although this answer might achieve the expected behaviour, as you can read in the comments below it: "This hack does not work on some devices". I found another way according to Adneal's answer which gives me the clue and specially the right way to do.
Lower API: use id R.id.up to retrieve the related ImageView.
API >= 14: get the relative Parent of Home ImageView (android.R.id.home) and retrieve the first child which is the UpIndicator (android.R.id.up).
Then, this snippet code changes dynamically the UpIndicator:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// get the parent view of home (app icon) imageview
ViewGroup home = (ViewGroup) findViewById(android.R.id.home).getParent();
// get the first child (up imageview)
( (ImageView) home.getChildAt(0) )
// change the icon according to your needs
.setImageDrawable(getResources().getDrawable(R.drawable.custom_icon_up));
} else {
// get the up imageview directly with R.id.up
( (ImageView) findViewById(R.id.up) )
.setImageDrawable(getResources().getDrawable(R.drawable.custom_icon_up));
}
I have not tested on multiple devices (that's why I'm not sure this above code works for all devices), however this seems to work great in APIs mentioned in the update part here.
Note: If you don't make the difference between higher and lower APIs, you will get a NullPointerException because R.id.up is not available in higher API while android.R.id.up is not available in lower API.
I write solution for this. It's not beautiful but works:
public static ImageView getHomeAndUpIndicator(View decorView) {
ImageView res = null;
int upId = Resources.getSystem().getIdentifier("up", "id", "android");
if (upId > 0) {
res = (ImageView) decorView.findViewById(upId);
} else {
if (android.os.Build.VERSION.SDK_INT <= 10) {
ViewGroup acbOverlay = (ViewGroup)((ViewGroup)decorView).getChildAt(0);
ViewGroup abcFrame = (ViewGroup)acbOverlay.getChildAt(0);
ViewGroup actionBar = (ViewGroup)abcFrame.getChildAt(0);
ViewGroup abLL = (ViewGroup)actionBar.getChildAt(0);
ViewGroup abLL2 = (ViewGroup)abLL.getChildAt(1);
res = (ImageView)abLL2.getChildAt(0);
} else if (android.os.Build.VERSION.SDK_INT > 10 && android.os.Build.VERSION.SDK_INT < 16) {
ViewGroup acbOverlay = (ViewGroup)((ViewGroup)decorView).getChildAt(0);
ViewGroup abcFrame = (ViewGroup)acbOverlay.getChildAt(0);
ViewGroup actionBar = (ViewGroup)abcFrame.getChildAt(0);
ViewGroup abLL = (ViewGroup)actionBar.getChildAt(1);
res = (ImageView)abLL.getChildAt(0);
} else {
ViewGroup acbOverlay = (ViewGroup)((ViewGroup)decorView).getChildAt(0);
ViewGroup abcFrame = (ViewGroup)acbOverlay.getChildAt(1);
ViewGroup actionBar = (ViewGroup)abcFrame.getChildAt(0);
ViewGroup abLL = (ViewGroup)actionBar.getChildAt(0);
ViewGroup abF = (ViewGroup)abLL.getChildAt(0);
res = (ImageView)abF.getChildAt(0);
}
}
return res;
}
As a param put: getWindow().getDecorView()
Test on few devices (nexus 7 (4.4.2), samsung galaxy s+ (2.3.6), yaiu g3 (4.2.2)) and emulators with android 2.3.3 and 4.1.1
Here is working code
final Drawable upArrow = getResources().getDrawable(R.drawable.ic_arrow_back_black_24dp);
upArrow.setColorFilter(Color.parseColor("#000000"), PorterDuff.Mode.SRC_ATOP);
getSupportActionBar().setHomeAsUpIndicator(upArrow);
Is it possible to get a list of all Windows in my Android app?
If not, is it possible to get notifications on creation of a new View or a Window?
Cheers :)
For example: I would like to know if there's a visible keyboard view on the screen, or if there's an alert dialog on screen. Is that possible? Can I get the View or Window instance holding it?
Yes this is possible in a number of different ways. All views being displayed on the screen are added to a ViewGroup, which are usually layouts such as R.layout.main, LinearLayout, RelativeLayout, etc.
You can access the views at runtime, after the layouts have been built, using a handler such as onWindowFocusChanged:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
int count = myLayout.getChildCount();
for(int i = 0; i < count; i++)
{
View v = myLayout.getChildAt(i);
...
}
}
You can simply set up a thread inside onWindowFocusChanged that would notify you if a keyboard is created by constantly checking the number of children views of the current layout.
For the keyboard issue, you can use your own keyboard view instance with KeyboardView in your layout: http://developer.android.com/reference/android/inputmethodservice/KeyboardView.html
Use the same principle for the other views you want to handle: manage them yourself in your layout. I don't know if you can in the software you plan to do but this is a way which can work.
You can only get views which are managed by your application.
This includes all views except the status and navigation bars(for higher than HoneyComb). If you choose to have your own InputMethod, that view can be yours as well but you'll need to register the proper keyboard views. See this question for more on that.
Otherwise, if you want to get all the views in your window:
ViewGroup decor = (ViewGroup)activity.getWindow().getDecorView();
int count = decor.getChildCount();
for(int i = 0; i < count; i++) {
View view = decor.getChildAt(i); //voila
}
hey use this code this will help you to find if any dialog is created in your activity
class MyActivity extends Activity {
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
Log.d("TAG", "New Window ATTACHED");
}
}
onAttachedToWindow will be called every time user creates new dialog or something