I want to create my own ActionBar Layout.
Like this (created in Paint for example)
Is it possible to give the second Button the Up-Navigation Properties? So if I press it, it finish this Activity and starts it's parent.
I want to have the burger Icon for the Navigation Drawer, the Up-Icon for Up-Navigation and the Title of the Activity.
Is it possible? Or is there a solution already?
Actually, it's fairly easy(though it's little hacky) to do.
First, create a drawable for back button(preferably - as a selector, to distinguish pressed/normal state:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#drawable/back_button_pressed"/>
<item android:drawable="#drawable/back_button"/>
</selector>
Next, set this drawable to the logo of the toolbar toolbar.setLogo(R.drawable.back_button_selector);
Then the only thing left is to set click-listener.
View logoView = getToolbarLogoIcon(toolbar);
logoView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
...
private View getToolbarLogoIcon(Toolbar toolbar){
//check if contentDescription previously was set
boolean hadContentDescription = android.text.TextUtils.isEmpty(toolbar.getLogoDescription());
String contentDescription = String.valueOf(!hadContentDescription ? toolbar.getLogoDescription() : "logoContentDescription");
toolbar.setLogoDescription(contentDescription);
ArrayList<View> potentialViews = new ArrayList<>();
//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 setLogoDescription ensures its existence
View logoIcon = null;
if (potentialViews.size() > 0) {
logoIcon = potentialViews.get(0);
}
//Clear content description if not previously present
if (hadContentDescription) {
toolbar.setLogoDescription(null);
}
return logoIcon;
}
(Thanks Nicola's post here). Or if you are not scared of reflection, it can be easily done like this:
try {
Field declaredField = toolbar.getClass().getDeclaredField("mLogoView");
declaredField.setAccessible(true);
View logoView = (View) declaredField.get(toolbar);
logoView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
} catch (Exception ex) {
//error
}
Another possible solution would be to set custom layout to the ActionBar.
Though, I'm advocating to follow the UI/UX guidelines and double-check, if navigation drawer is essential in the secondary activity.
Related
I am trying to toggle my button's background drawables, so that when the user clicks the button its background is changed and when the user clicks the button again its background returns to defaul. Here is my code:
public void Favorites(View V) {
Button star = (Button) findViewById(R.id.buttonStar);
if(star.getBackground().equals(R.drawable.btn_star_off)) {
star.setBackgroundResource(R.drawable.btn_star_on);
} else {
star.setBackgroundResource(R.drawable.btn_star_off);
}
}
I am pretty sure this is not how you use drawables with if statements. Can someone suggest a way to do it?
private boolean isButtonClicked = false; // You should add a boolean flag to record the button on/off state
protected void onCreate(Bundle savedInstanceState) {
......
Button star = (Button) findViewById(R.id.buttonStar);
star.setOnClickListener(new OnClickListener() { // Then you should add add click listener for your button.
#Override
public void onClick(View v) {
if (v.getId() == R.id.buttonStar) {
isButtonClicked = !isButtonClicked; // toggle the boolean flag
v.setBackgroundResource(isButtonClicked ? R.drawable.btn_star_on : R.drawable.btn_star_off);
}
}
});
}
You can create an xml in the drawable folder.
This xml (you choose the name...let's call it "bg_button_star.xml") could look just like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="#drawable/btn_star_on" />
<item android:drawable="#drawable/btn_star_off" />
Then you have to assign this drawable file to the Button background property in the layout file.
android:background="#drawable/bg_button_star"
If you want to do this programmatically then you just have to do:
button.setBackgroundResource(R.drawable.bg_button_star);
When the user click the first time on the button, you set the Selected state to 'true'. The background changes accordingly. (viceversa for the 'false' Selected state).
You can do in your onClick() something like:
if(star.getTag()==R.drawable.btn_star_on){
star.setTag(R.drawable.btn_star_off);
star.setBackgroundResource(R.drawable.btn_star_off);
} else {
star.setTag(R.drawable.btn_star_on);
star.setBackgroundResource(R.drawable.btn_star_on);
}
Obviously it's better to the the tag before the if and else statement based on your informations. I don't know the rest of your code and how you check if this button has to be iniziatilized with the drawable resource btn_star_off or btn_star_on
You can try this.
public void Favorites(View V) {
Button star = (Button) findViewById(R.id.buttonStar);
if(star.getBackground().getConstantState().equals(getResources().getDrawable(R.drawable.btn_star_off).getConstantState()))
{
star.setBackground(R.drawable.btn_star_on);
} else {
star.setBackground(R.drawable.btn_star_off);
}
}
But make sure you are calling this method onClick() of the start button.
Other wise you have to do something like this.
Button star = (Button) findViewById(R.id.buttonStar);
star.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(v.getBackground().getConstantState().equals(getResources().getDrawable(R.drawable.btn_star_off).getConstantState()))
{
v.setBackground(R.drawable.btn_star_on);
} else {
v.setBackground(R.drawable.btn_star_off);
}
}
});
In this case, instead of using Button you should use ToggleButton.
There is a API Guide for it:
http://developer.android.com/guide/topics/ui/controls/togglebutton.html
Dont do it like that. Use a selector resource instead http://www.compiletimeerror.com/2014/03/android-button-selector-tutorial-with.html
I am a new in android programming, I made a layout with this figure:
Now I want to know when one of these buttons clicked I should run an new activity or change visibility to false and show new layout without run a new activity, what is the best solution?
You consider that count of these buttons are more than ten.
I want show a text with image,..(when clicked) because that is a educational book and these buttons are chapters list of that book
for an example if you want to change only the layout then you could do something like this
FirstButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
FirstView();
}
});
/
void FirstView(){
setContentView(R.layout.yourOtherLayout);
// then declare the layout views here.
firstView=false;
}
you can do this in all the buttons just create different methods for each
to handle the Back Button you can declare Boolean variables and use If else Statement to loop through them for example
boolean firstView = true, secondView = true;
#Override
public void onBackPressed(){
if (firstView == false ){
then firstView Is Showing.
// show the view you want and set
firstView = true;
}else if (SO ON)...
else { super.OnBackPressed(); // exit }
}
For specific customer requirement, I need to allow the user of my app ( won't be published in Market) to click on the ActionBar title to execute some actions.
I have been looking in the Android source, but I am not able to find an ID for the actionBar TextView title.
Is there a proper way to handle such clicks?
The title is non-clickable AFAIK. The icon/logo is clickable -- you'll get that via android.R.id.home in onOptionsItemSelected(). Conceivably, the title also routes this way, though they don't mention it and I wouldn't rely upon it.
It sounds like you want a Spinner for the user to choose the actions to execute. If so, use setListNavigationCallbacks(). If you want to remove the title as now being superfluous, use setDisplayOptions(0, DISPLAY_SHOW_TITLE).
If you want something other than a Spinner on the left side of the action bar, use setDisplayOptions(DISPLAY_SHOW_CUSTOM, DISPLAY_SHOW_CUSTOM) and setCustomView(). Note that this approach is not recommended ("Avoid using custom navigation modes in the action bar"), as it may not work well with phones, particularly in portrait mode.
Another possibility would be to remove the title and use a logo instead of the icon, and in the logo have your "title" as part of the image. The whole logo should be clickable, picked up via onOptionsItemSelected().
//onCreate
ActionBar actionBar = getActionBar();
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayShowTitleEnabled(false);
// View actionBarView = getLayoutInflater().inflate(R.layout.action_bar_custom_view, null);
actionBar.setCustomView(actionBarView);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
//your logic for click listner
setListenerForActionBarCustomView(actionBarView);
private void setListenerForActionBarCustomView(View actionBarView) {
ActionBarCustomViewOnClickListener actionBarCustomViewOnClickListener = new ActionBarCustomViewOnClickListener();
actionBarView.findViewById(R.id.text_view_title).setOnClickListener(actionBarCustomViewOnClickListener);
}
private class ActionBarCustomViewOnClickListener implements OnClickListener {
public void onClick(View v) {
switch(v.getId()) {
case R.id.text_view_title:
//finish();
break;
}
}
You can set up a custom toolbar from Support Library by declaring <android.support.v7.widget.Toolbar> in your layout (see Chris Banes' answer for full toolbar layout example).
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- We use a Toolbar so that our drawer can be displayed
in front of the action bar -->
<android.support.v7.widget.Toolbar
android:id="#+id/my_awesome_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/main_toolbar"
android:minHeight="?attr/actionBarSize" />
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
After you can add on click listener in your activity just like to most other Views.
Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
setSupportActionBar(toolbar);
toolbar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MyActivity.this, "Test", Toast.LENGTH_LONG).show();
}
});
If you want to capture touch events on title:
toolbar.setOnTouchListener(new View.OnTouchListener() {
Rect hitrect = new Rect();
public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_DOWN == event.getAction()) {
boolean hit = false;
for (int i = toolbar.getChildCount() - 1; i != -1; i--) {
View view = toolbar.getChildAt(i);
if (view instanceof TextView) {
view.getHitRect(hitrect);
if (hitrect.contains((int)event.getX(), (int)event.getY())) {
hit = true;
break;
}
}
}
if (hit) {
//Hit action
}
}
return false;
}
});
I am working on app which has a titlebar with chronometer on the left and a textview centered in a RelativeLayout.
RelativeLayout take height of textview and fill screen width
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/titlecontainer"
android:orientation="vertical"
android:padding="5dip"
android:layout_height="wrap_content"
android:layout_width="fill_parent" android:background="#color/titlebckgrnd">
I want to hide the chornometer when user clicks on it and unhide it user clicks again.
How this can be achieved?
EDIT, further to the answers and comments:
Here is the color file code
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="titlebckgrnd">#FFD55A2E</color>
<color name="titletext">#FFFFFFFF</color>
</resources>
I used the following code as suggested
final TextView chron = (TextView)findViewById(R.id.chronometer);
((Chronometer) chron).start();
chron.setOnClickListener(new OnClickListener() {
private boolean mToggle = true;
#Override
public void onClick(View v) {
Log.d("Gaurav", "Invisible");
if(mToggle) {
Log.d("Gaurav", String.valueOf(chron.getCurrentTextColor()));
chron.setTextColor(R.color.titlebckgrnd);
mToggle = false;
}
else {
chron.setTextColor(R.color.titletext);
mToogle = true;
}
//chronImage.setVisibility(View.VISIBLE);
//v.setVisibility(View.INVISIBLE);
}
});
but the result is
and it does not respond to any more clicks.
LogCat Results
Even the debugger breakpoints show change in Textcolor value but color change in display does not happen.
If I properly understood your question you can do that way to hide the chronometer:
// We are in your Activity:
final View chronometer= findViewById(R.id.chronometer);
chronometer.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
chronometer.setVisibility(View.GONE);
// Use View.INVISIBLE if you would like to keep the room for this view
}
});
But there will be no view displayed anymore. So depending of where the user should click to have it displayed again, you may have to give your view and/or its text the same color as the background instead of making them invisible:
// should chronometer be a TextView that displays the time:
final TextView chronometer = (TextView) findViewById(R.id.chronometer);
chronometer.setOnClickListener(new View.OnClickListener() {
private boolean mToggle = true;
public void onClick(View v) {
if (mToggle ) {
chronometer.setTextColor(Color.BLACK);
mToggle = false;
}
else {
chronometer.setTextColor(Color.WHITE);
mToggle = true;
}
}
});
I have a field where the user can type a search query in the action bar of the application. This is declared in the action bar using a menu inflate in the Activity:
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
>
<item
android:id="#+id/action_search"
android:showAsAction="ifRoom"
android:actionViewClass="android.widget.SearchView"
android:title="#string/search"
></item>
</menu>
I need to customize the appearance of the SearchView (for instance background and text color). So far I could not find a way to do it using XML (using styles or themes).
Is my only option to do it in the code when inflating the menu?
Edit #1: I have tried programmatically but I cannot get a simple way to set the text color. Plus when I do searchView.setBackgroundResource(...) The background is set on the global widget, (also when the SearchView is iconified).
Edit #2: Not much information on the Search Developer Reference either
Seibelj had an answer that is good if you want to change the icons. But you'll need to
do it for every API version. I was using ICS with ActionBarSherlock and it didn't do justice for me but it did push me in the correct direction.
Below I change the text color and hint color. I showed how you might go about changing the
icons too, though I have no interest in that for now (and you probably want to use the default icons anyways to be consistent)
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Set up the search menu
SearchView searchView = (SearchView)menu.findItem(R.id.action_search).getActionView();
traverseView(searchView, 0);
return true;
}
private void traverseView(View view, int index) {
if (view instanceof SearchView) {
SearchView v = (SearchView) view;
for(int i = 0; i < v.getChildCount(); i++) {
traverseView(v.getChildAt(i), i);
}
} else if (view instanceof LinearLayout) {
LinearLayout ll = (LinearLayout) view;
for(int i = 0; i < ll.getChildCount(); i++) {
traverseView(ll.getChildAt(i), i);
}
} else if (view instanceof EditText) {
((EditText) view).setTextColor(Color.WHITE);
((EditText) view).setHintTextColor(R.color.blue_trans);
} else if (view instanceof TextView) {
((TextView) view).setTextColor(Color.WHITE);
} else if (view instanceof ImageView) {
// TODO dissect images and replace with custom images
} else {
Log.v("View Scout", "Undefined view type here...");
}
}
adding my take on things which is probably a little more efficient and safe across different android versions.
you can actually get a numeric ID value from a string ID name. using android's hierarchyviewer tool, you can actually find the string IDs of the things you are interested in, and then just use findViewById(...) to look them up.
the code below sets the hint and text color for the edit field itself. you could apply the same pattern for other aspects that you wish to style.
private static synchronized int getSearchSrcTextId(View view) {
if (searchSrcTextId == -1) {
searchSrcTextId = getId(view, "android:id/search_src_text");
}
return searchSrcTextId;
}
private static int getId(View view, String name) {
return view.getContext().getResources().getIdentifier(name, null, null);
}
#TargetApi(11)
private void style(View view) {
ImageView iv;
AutoCompleteTextView actv = (AutoCompleteTextView) view.findViewById(getSearchSrcTextId(view));
if (actv != null) {
actv.setHint(getDecoratedHint(actv,
searchView.getContext().getResources().getString(R.string.titleApplicationSearchHint),
R.drawable.ic_ab_search));
actv.setTextColor(view.getContext().getResources().getColor(R.color.ab_text));
actv.setHintTextColor(view.getContext().getResources().getColor(R.color.hint_text));
}
}
You can use the attribute android:actionLayout instead which lets you specify a layout to be inflated. Just have a layout with your SearchView and you won't have to modify anything really.
As to changing text style on the SearchView that is probably not possible as the SearchView is a ViewGroup. You should probably try changing text color via themes instead.
In case anyone wants to modify the views directly, here is how you can change the colors/fonts/images and customize the search box to your pleasure. It is wrapped in a try/catch in case there are differences between versions or distributions, so it won't crash the app if this fails.
// SearchView structure as we currently understand it:
// 0 => linearlayout
// 0 => textview (not sure what this does)
// 1 => image view (the search icon before it's pressed)
// 2 => linearlayout
// 0 => linearlayout
// 0 => ImageView (Search icon on the left of the search box)
// 1 => SearchView$SearchAutoComplete (Object that controls the text, subclass of TextView)
// 2 => ImageView (Cancel icon to the right of the text entry)
// 1 => linearlayout
// 0 => ImageView ('Go' icon to the right of cancel)
// 1 => ImageView (not sure what this does)
try {
LinearLayout ll = (LinearLayout) searchView.getChildAt(0);
LinearLayout ll2 = (LinearLayout) ll.getChildAt(2);
LinearLayout ll3 = (LinearLayout) ll2.getChildAt(0);
LinearLayout ll4 = (LinearLayout) ll2.getChildAt(1);
TextView search_text = (TextView) ll3.getChildAt(1);
search_text.setTextColor(R.color.search_text);
ImageView cancel_icon = (ImageView)ll3.getChildAt(2);
ImageView accept_icon = (ImageView)ll4.getChildAt(0);
cancel_icon.setBackgroundDrawable(d);
accept_icon.setBackgroundDrawable(d);
} catch (Throwable e) {
Log.e("SearchBoxConstructor", "Unable to set the custom look of the search box");
}
This example shows changing the text color and the background colors of the cancel/accept images. searchView is a SearchView object already instantiated with it's background color:
Drawable d = getResources().getDrawable(R.drawable.search_widget_background);
searchView.setBackgroundDrawable(d);
Here is the drawable code:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#color/white" />
</shape>
Obviously, this is hacky, but it will work for now.
From ICS this is doable using themes and styles. I'm using ActionBarSherlock which makes it applicable also for HC and below.
Add a style to define "android:textColorHint":
<style name="Theme.MyHolo.widget" parent="#style/Theme.Holo">
<item name="android:textColorHint">#color/text_hint_corp_dark</item>
</style>
Apply this as "actionBarWidgetTheme" to your theme:
<style name="Theme.MyApp" parent="#style/Theme.Holo.Light.DarkActionBar">
...
<item name="android:actionBarWidgetTheme">#style/Theme.MyHolo.widget</item>
</style>
Presto! Make sure that you use getSupportActionBar().getThemedContext() (or getSupportActionBar() for ActionBarSherlock) if any widgets are initiated where you might have other themes in effect.
How do you inflate the menu xml in your Activity? if you inflate the menu by using getMenuInflator() in your Activity, then the menu and also the searchView get the themed context, that have attached to the activity.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater.inflate(R.menu.search_action_menu, menu);
}
if you check the source code of Activity.getMenuInflator() at API-15, you can see the themed context codes. Here it is.
*/
public MenuInflater getMenuInflater() {
// Make sure that action views can get an appropriate theme.
if (mMenuInflater == null) {
initActionBar();
if (mActionBar != null) {
mMenuInflater = new MenuInflater(mActionBar.getThemedContext());
} else {
mMenuInflater = new MenuInflater(this);
}
}
return mMenuInflater;
}