please see: http://i.imgur.com/iwikd69.png (the single "lorem" is a subtitle)
I am using the v7.21 appcompat library. I'd like to set a title to a Toolbar and if its too long then it should show as it does now (upper example in the image attached), only 1 line and it ends with ... if it doesnt fit. However I want the toolbar to expand (and then collapse respectively) onClick (possibly animated somehow) and show the full title (lower example)
Now I miss a few things here:
I dont see any method which would tell me if the title fits or not. (getSupportActionBar().isTitleTruncated() returns false even if the title doesn't fit, but maybe this is not the method I need, its not even a method of the Toolbar's class)
I can't seem to set the Toolbar's height programatically (even if i could, animating it would be a pain even more because I am targeting >=api15)
Is it possible to execute what I want or should I find a different solution?
Thanks
create custom toolbar
here is the example
/**
* Create the Action Bar and set the Custom View to it.
* Set content insets absolute (0,0) to hide the bottom margin for Action Bar.
*
*/
public void initializeAppToolbar()
{
actionbar = getSupportActionBar();
actionbar.setDisplayShowHomeEnabled(false);
actionbar.setDisplayShowCustomEnabled(true);
actionbar.setDisplayShowTitleEnabled(false);
actionbarView = getLayoutInflater().inflate(R.layout.custom_actionbar,null);
ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT,ActionBar.LayoutParams.MATCH_PARENT);
actionbar.setCustomView(actionbarView, layoutParams);
Toolbar parent = (Toolbar) actionbarView.getParent();
parent.setContentInsetsAbsolute(0, 0);
parent.setBackgroundResource(R.drawable.top_nav);
toolbar_title = (TextView)actionbarView.findViewById(R.id.toolbar_title);
// set click listener on toolbar_title.. and perform expand and collapse
// need to check this condition for lollipop and greater version
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().setStatusBarColor(getResources().getColor(R.color.statusBarDark));
}
}
here is the custom_actionbar.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/top_nav"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="#+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Profile"
android:textColor="#android:color/white"
android:textStyle="normal"
android:textSize="24sp" />
Related
I am using a DrawerLayout on my Android app which works fine but I am having problems with the menu itself, where I want to have a collapsible section and some static items in the menu.
The exact layout I want to achieve is like this:
Drawer Title
-> Expandable List
Menu Item 1
Menu Item 2
And when the Expandable list is open to have something like this:
Drawer Title
-> Expandable List
Expandable List Item 1
Expandable List Item 2
Menu Item 1
Menu Item 2
The problem I have is that the menu doesn't seem to sit in the flow of the view like other elements do, so if I have my ExpandableListView inside the NavigationView that contains the menu, it opens over the other menu items and there doesn't seem to be a way to move them.
To try and address this I have moved the ExpandableListView into a separate layout that provides the header for the menu. This now draws everything correctly but I can't open the list view any more, which is definitely a problem. In fact it does open - or at least the onGroupExpandListener is triggered - but although the height of the header is set to wrap_content and I invalidate it on expand and collapse, the size of the header remains resolutely the same. To work around this I am manually changing it's size in the onGroupExpandListener and onGroupCollapseListener as follows.
In my layout I have a NavigationView like this:
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="#menu/drawer_view" >
</android.support.design.widget.NavigationView>
The header looks like this:
<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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="#color/colorPrimary" >
<ImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:padding="10dp"
app:srcCompat="#drawable/main_icon" />
<TextView
android:id="#+id/drawer_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_gravity="left|start|center"
android:layout_marginStart="70dp"
android:paddingStart="5pt"
android:text="Options"
android:textColor="#FFFFFF"
android:textSize="16pt"
android:textStyle="bold" />
</RelativeLayout>
<ExpandableListView
android:id="#+id/menu_expandable_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" >
</ExpandableListView>
</LinearLayout>
In my code, I am currently setting up the ExpandableListView ( complete with a bunch of superfluous hacks because I'm trying to figure out the problem ) like this:
private void setOptionsMenuItems(final NavigationView menuContainer) {
final View v = menuContainer.inflateHeaderView(R.layout.drawer_header);
final ExpandableListView optionsMenu = (ExpandableListView) v.findViewById(R.id.menu_expandable_list);
final MyExpandableListAdapter adapter = new MyExpandableListAdapter(this, allTheItems );
optionsMenu.setAdapter(adapter);
optionsMenu.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
setCurrentItem(allTheItems[childPosition]);
return true;
}
});
optionsMenu.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
#Override
public void onGroupExpand(int groupPosition) {
v.setMinimumHeight(v.getChildAt(0).getHeight() + adapter.getOpenHeight());
v.invalidate();
}
});
optionsMenu.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
#Override
public void onGroupCollapse(int groupPosition) {
v.setMinimumHeight(v.getChildAt(0).getHeight() + adapter.getClosedHeight());
v.invalidate();
}
});
}
What this version of the code does is to enlarge and shrink the header correctly when the group is opened or closed ( adapter.getOpenHeight()/getClosedHeight() gives you the dimension you might expect ) but the actual child items never get rendered. Doing the same enlargement in an onGroupClickListener is no different, although I suspect that the child elements are being culled from the view because the layout system assumes they are invisible, rather than the view being resized. If I manually make the header taller, so that everything is in view when the ExpandableList is expanded, it opens and closes as normal but obviously this does not allow me to move the other menu items up and down, which is the whole point.
This all seems inordinately complex for what must be a common use case so if I am taking completely the wrong approach here please let me know. All I want is for the first item in my menu to be an ExpandableList and for the other menu items to be regular menu items that move down when the the ExpandableList is opened and move back up when it is closed.
What do I need to do to have a working collapsible list of options in my menu?
Edit: With some more time on this, what I think is happening is that the list is bypassing drawing the new sections because it has measured that there is no visible room for them - although the resize can be triggered from the onGroupClickListener the actual change in visible size doesn't occur until the next drawing pass, so when the base ListView tests to see whether there is room to write the list, it is coming up false.
I did not find a way to do this using a conventional menu- instead the solution I came to was adding my other menu items as ExpandableListView groups so they simply appear at the top level of the list view. This allowed me to create the effect I was looking for, at the cost of not using menus the 'correct' way.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:EMVideoView="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#color/MUVCastleRock">
<com.devbrackets.android.exomedia.ui.widget.EMVideoView
android:id="#+id/video_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
EMVideoView:useDefaultControls="true" />
How do I change the color of the default controls (where you would see the play button)? I don't want to change the background behind the video, but instead the play bar. This is because my background is grey and so I want to change the color so that the bar is more visible.
EDIT:
#Shank suggested that I replace the images of the buttons in /exomedia/ui/widget/VideoControls.java
Although, I wasn't trying to change the images of these buttons, analyzing this class lead to my answer.
There are several functions within this class to change the settings of the default video controls.
You can set a title, description, subtitle, change out the button images (as Shank suggested), and solve my particular problem by changing the characteristics of the containers that contain the video controls (named controlsContainer).
The default container is initialized in retrieveViews() by the line:
controlsContainer = (ViewGroup) findViewById(R.id.exomedia_controls_interactive_container);
Using this, I simply called this reference from my EMVideoView and changed the color as appropriate:
emVideoView = (EMVideoView) myView.findViewById(R.id.video_view);
ViewGroup textContainer = (ViewGroup) emVideoView.findViewById(R.id.exomedia_controls_interactive_container);
textContainer.setBackgroundColor(ContextCompat.getColor(getContext(),R.color.myColor));
Other useful methods that I discovered were as such:
emVideoView.getVideoControls().setTitle("title");
emVideoView.getVideoControls().setDescription("description");
emVideoView.getVideoControls().setSubTitle("sub");
emVideoView.getVideoControls().setPlayPauseImages(R.drawable.logo,R.mipmap.ic_launcher);
I have a LinearLayout in which a TextView's visibility and background (GradientDrawable) changes according to a function myFunction():
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:animateLayoutChanges="true"
android:gravity="center"
android:orientation="vertical" >
(...Some views...)
<TextView
android:id="#+id/currentPercentage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:gravity="center"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:singleLine="true"
android:text="XX.X%"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#color/White" />
</LinearLayout>
The currentPercentage TextView has GONE visibility by default and, according to some events in the fragment that contains it, may have it changed to Visible (or back to GONE) and its background to a different GradientDrawable like so:
myFunction(...){
TextView currentPercentage= (TextView) getView().findViewById(R.id.currentPercentage);
if(condition ... ) {
Color color = // Color based on the condition...
GradientDrawable gd = new GradientDrawable(
GradientDrawable.Orientation.TL_BR,
new int[] {color,color});
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
int dp = Math.round(10f / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
gd.setCornerRadius(dp);
currentChartPercentage.setBackground(gd);
} else if( otherCondition...)
{
// ... similar stuff ...
} else {
// Hide the currentPercentage TextView
currentPercentage.setVisibility(View.GONE);
}
}
This works fine as the TextView's background and visibility change smoothly whenever myFunction() is called and the other elements in the LinearLayout move (with animation) to make room for the TextView.
My issue is that whenever the visibility goes from GONE to VISIBLE, the View fades in nicely (as expected because of android:animateLayoutChanges="true") but right in the end shows up with an annoying black background where the GradientDrawable round corners are (see image).
Right after that, if I touch something else or drag the fragment (it's inside a ViewPager), the black background disappears. If myFunction() is called again, with the View already VISIBLE, then the background color changes as desired with no black background.
Also, if I disable the animation, I don't get the black background too. Thus, the problem seems to be related to the visibility going from GONE to VISIBLE with an animation.
This behavior is obtained on an emulator with Android 4.3 and I haven't tested it on my real device yet.
Does anybody have a clue on why this may be happening?
EDIT:
Just tested this on a real device with ICS without any issue.
EDIT 2:
I once had a problem with an undesirable background showing up in a ListView similar to Background ListView becomes black when scrolling but in this case, setting a cacheColorHint does nothing.
I am working on a Android Project in which I need to show a Button or ImageView on header of my activity(Screen). Below is my XML layout of my activity.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/app"
android:layout_width="1dp"
android:layout_height="1dp"
android:layout_margin="2px"
android:orientation="vertical"
android:padding="2px" >
<LinearLayout
android:id="#+id/tabBar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="#+id/BtnSlide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="0px"
android:padding="0px"
android:src="#drawable/button" />
</LinearLayout>
</LinearLayout>
With the above layout, I can see my black button image just below the Proximity title. Is it possible to show my button image to left of Proximity instead of getting shown one line below Proximity?
Or
Is there any way, I can make the image which is left to Proximity title clickable? if I can do that, then I don't need to show Black Button image at the top.
That image is coming from AndroidManifest.xml file. I am not sure how to make that clickable.
With the above layout, I can see my black button image just below the
Proximity title. Is it possible to show my button image to left of
Proximity instead of getting shown one line below Proximity?
Since Proximity is in titlebar you need to create your own custom titlebar to be able to place button to titlebar. Here is example how to achieve it.
Also try to think an usage of ActionBar.
Try this
Button b=new Button(context);
View v = findViewById (android.R.id.title); // Getting the title bar view
v.addView(b); // setting Button
v.setClickable(true);
v.setOnClickListener(new OnClickListener() {
#Override public void onClick(View v) {
Toast.makeText(context, "You have clicked on Title", Toast.LENGTH_SHORT).show();
}
});
How ever I'll suggest you to use ActionBar
Note: I haven't tried that. Let me know if it work for you
Can you overlay a view on top of everything in android?
In iPhone I would get the new view set its frame.origin to (0,0) and its width and height to the width and height of self.view. Adding it to self.view would then cause it to act as an overlay, covering the content behind (or if it had a transparent background then showing the view behind).
Is there a similar technique in android? I realise that the views are slightly different (there are three types (or more...) relativelayout, linearlayout and framelayout) but is there any way to just overlay a view on top of everything indiscriminately?
Simply use RelativeLayout or FrameLayout. The last child view will overlay everything else.
Android supports a pattern which Cocoa Touch SDK doesn't: Layout management.
Layout for iPhone means to position everything absolute (besides some strech factors). Layout in android means that children will be placed in relation to eachother.
Example (second EditText will completely cover the first one):
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/root_view">
<EditText
android:layout_width="fill_parent"
android:id="#+id/editText1"
android:layout_height="fill_parent">
</EditText>
<EditText
android:layout_width="fill_parent"
android:id="#+id/editText2"
android:layout_height="fill_parent">
<requestFocus></requestFocus>
</EditText>
</FrameLayout>
FrameLayout is some kind of view stack. Made for special cases.
RelativeLayout is pretty powerful. You can define rules like View A has to align parent layout bottom, View B has to align A bottom to top, etc
Update based on comment
Usually you set the content with setContentView(R.layout.your_layout) in onCreate (it will inflate the layout for you). You can do that manually and call setContentView(inflatedView), there's no difference.
The view itself might be a single view (like TextView) or a complex layout hierarchy (nested layouts, since all layouts are views themselves).
After calling setContentView your activity knows what its content looks like and you can use (FrameLayout) findViewById(R.id.root_view) to retrieve any view int this hierarchy (General pattern (ClassOfTheViewWithThisId) findViewById(R.id.declared_id_of_view)).
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id = "#+id/Everything"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- other actual layout stuff here EVERYTHING HERE -->
</LinearLayout>
<LinearLayout
android:id="#+id/overlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right" >
</LinearLayout>
Now any view you add under LinearLayout with android:id = "#+id/overlay" will appear as overlay with gravity = right on Linear Layout with android:id="#+id/Everything"
You can use bringToFront:
View view=findViewById(R.id.btnStartGame);
view.bringToFront();
The best way is ViewOverlay , You can add any drawable as overlay to any view as its overlay since Android JellyBeanMR2(Api 18).
Add mMyDrawable to mMyView as its overlay:
mMyDrawable.setBounds(0, 0, mMyView.getMeasuredWidth(), mMyView.getMeasuredHeight())
mMyView.getOverlay().add(mMyDrawable)
I have just made a solution for it. I made a library for this to do that in a reusable way that's why you don't need to recode in your XML. Here is documentation on how to use it in Java and Kotlin. First, initialize it from an activity from where you want to show the overlay-
AppWaterMarkBuilder.doConfigure()
.setAppCompatActivity(MainActivity.this)
.setWatermarkProperty(R.layout.layout_water_mark)
.showWatermarkAfterConfig();
Then you can hide and show it from anywhere in your app -
/* For hiding the watermark*/
AppWaterMarkBuilder.hideWatermark()
/* For showing the watermark*/
AppWaterMarkBuilder.showWatermark()
Gif preview -
I have tried the awnsers before but this did not work.
Now I jsut used a LinearLayout instead of a TextureView, now it is working without any problem. Hope it helps some others who have the same problem. :)
view = (LinearLayout) findViewById(R.id.view); //this is initialized in the constructor
openWindowOnButtonClick();
public void openWindowOnButtonClick()
{
view.setAlpha((float)0.5);
FloatingActionButton fb = (FloatingActionButton) findViewById(R.id.floatingActionButton);
final InputMethodManager keyboard = (InputMethodManager) getSystemService(getBaseContext().INPUT_METHOD_SERVICE);
fb.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
// check if the Overlay should be visible. If this value is false, it is not shown -> show it.
if(view.getVisibility() == View.INVISIBLE)
{
view.setVisibility(View.VISIBLE);
keyboard.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);
Log.d("Overlay", "Klick");
}
else if(view.getVisibility() == View.VISIBLE)
{
view.setVisibility(View.INVISIBLE);
keyboard.toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);
}
bringToFront() is super easy for programmatic adjustments, as stated above. I had some trouble getting that to work with button z order because of stateListAnimator. If you end up needing to programmatically adjust view overlays, and those views happen to be buttons, make sure to set stateListAnimator to null in your xml layout file. stateListAnimator is android's under-the-hood process to adjust translationZ of buttons when they are clicked, so the button that is clicked ends up visible on top. This is not always what you want... for full Z order control, do this: