So I was trying to make a ActionButton like Trello have (click on a button, a black overlay apears, and other buttons appear on the screen).
But I had one weird problem: I cannot make the alpha animation work.
I tryed in two ways:
private void initializeComponent(final Context ctx, final AttributeSet attrs) {
blackOverlay.setAlpha(0.0f);
blackOverlay.setVisibility(View.VISIBLE);
blackOverlay.setClickable(true);
actionButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final boolean closed = blackOverlay.getAlpha() == 0.0f;
blackOverlay.animate().alpha(closed ? 1f : 0f).setDuration(500).setListener(null);
});
}
So in this way, the view blackOverlay is always visible and the animation should work. But it doesn't. Clicking the button does not make any difference on alpha. The only change is that toggling the button makes the non-overlay content work/stop work (as it should since blackOverlay is clickable).
So I tryed another approach: not setting the alpha to 0.0f so the overlay will start visible to the user. Basically commenting the first line of initializeComponent method.
private void initializeComponent(final Context ctx, final AttributeSet attrs) {
//blackOverlay.setAlpha(0.0f);
blackOverlay.setVisibility(View.VISIBLE);
blackOverlay.setClickable(true);
actionButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final boolean closed = blackOverlay.getAlpha() == 0.0f;
blackOverlay.animate().alpha(closed ? 1f : 0f).setDuration(500).setListener(null);
}
});
}
In this way, the button only toggles the alpha, it doesn't animate it.
Any ideas? I've already tryed a lot of solutions here on StackOverflow.
Thanks!
This is my xml layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/blackoverlay"
android:background="#color/black_overlay">
</LinearLayout>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/action_button"
android:layout_gravity="bottom"
android:src="#drawable/plus"
android:layout_margin="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
OK so I did a MCVE as karaokyo said but the fun thing was: It worked on MCVE.
So I started looking at my entire code and I found that I had a setOnClickListener for a Button that had the same name as action_button. So I just changed the IDs to not be the same and everything is working now.
It seens it was my bad, I'm stupid lol
So for anyone that is reading this: Try to create a MCVE from scratch (new project even) and see if it works. It maybe be something else non-related interfering in your code.
Related
This is what I have done so far. Created FloatingActionButton. Now As the + icon is pressed a translucent layer should be there at the back.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.getbase.floatingactionbutton.FloatingActionsMenu
android:id="#+id/actionMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="60dp"
fab:fab_addButtonColorNormal="#color/primary"
fab:fab_addButtonColorPressed="#color/primary_dark"
fab:fab_addButtonPlusIconColor="#ffffff">
<com.getbase.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="openAudio"
fab:fab_colorNormal="#EA1E63"
fab:fab_colorPressed="#EA1E63"
fab:fab_icon="#drawable/ic_action_mic" />
</com.getbase.floatingactionbutton.FloatingActionsMenu>
</RelativeLayout
Try this.
floatingActionMenuButton.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() {
#Override
public void onMenuToggle(boolean opened) {
if (opened) {
//menu opened
} else {
//menu closed
}
}
});
use setBackgroundResource or setBackgroundColor. I think first is pretty simple.
Second one takes an int as an argument. So, just convert your hex color (for example #55000000) into decimal and it will work as well.
I had the same issue and i fixed it in following way.
I added a relative layout which will match parent in both width and height.
Set its background color to black and set alpha to your required opacity.
<RelativeLayout
android:id="#+id/obstructor"
android:visibility="invisible"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:alpha="0.75"
android:background="#android:color/black">
</RelativeLayout>
And then on the menu item expanded and collapsed make this visible and invisible.
mFabMenu = (FloatingActionsMenu) findViewById(R.id.multiple_actions);
final RelativeLayout obstrucuterView = (RelativeLayout) findViewById(R.id.obstructor);
obstrucuterView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (obstrucuterView.getVisibility() == View.VISIBLE) {
mFabMenu.collapse();
return true;
}
return false;
}
});
mFabMenu.setOnFloatingActionsMenuUpdateListener(new FloatingActionsMenu.OnFloatingActionsMenuUpdateListener() {
#Override
public void onMenuExpanded() {
if (obstrucuterView.getVisibility() == View.INVISIBLE)
obstrucuterView.setVisibility(View.VISIBLE);
}
#Override
public void onMenuCollapsed() {
if (obstrucuterView.getVisibility() == View.VISIBLE)
obstrucuterView.setVisibility(View.INVISIBLE);
}
});
Hope this helps.
There is another custom library which is more advanced than what you are using right now.
Get it here
Clans floating Action Button
Set this to true and it will solve your problem. Do let me know if it helps
fabPlusButton.setClosedOnTouchOutside(true);
If you are using Clans floating Action Button then perhaps fab:menu_backgroundColor might be something that you could have a look at if it satisfies your use-case. ofcourse the layout width and height should both match parent (This solution has worked for me)
I've tried to approach this from different angles without luck. Maybe asking a general question can help.
Technically I'm using osmdroid's MapView implementation, not Google's Maps API, but I think this question is a more general programmatic Views vs main_activity.xml defined views in onCreate.
Basically in my MainActivity if I onCreate a View, like MapView, then set it as the ContentView programmatically, I have to also programmatically add in any other Views I want to display in my app:
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mapView = new MapView(this, 256);
...
this.setContentView(this.mapView);
}
If I attempt to set the ContentView as activity_main, the MapView can't be adjusted onCreate. Maybe I'm missing something: (note that I have methods that handle loading a custom offline tile set, and place markers on the map, etc...)
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.mapView = (MapView)findViewById(R.id.mapview);
...
this.intializeMapTiles();
this.mapView.setBuiltInZoomControls(true);
this.mapView.setMultiTouchControls(true);
this.mapController.setCenter(new GeoPoint((int)(50.349622 * 1E6), (int)(-71.823700 *1E6)));
...
this.mapView.invalidate();
}
Here's my activity_main.xml in this case:
<RelativeLayout 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=".MainActivity" >
<org.osmdroid.views.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="false"/>
</RelativeLayout>
When trying to get the MapView from the ContentView (acitivty_main), none of my method changes to it make any affect. It's as if I don't have access the exact MapView that's being rendered. I've tried invalidating my MapView but it doesn't matter. I get a default looking and behaving MapView.
The reason I'm trying to solve this is naturally I'm looking for my app to include more than a single MapView. I would like to include a SlidingDrawer, or some method of displaying a View with buttons that is only displayed when you long press on a map marker. (note that I have Toast pop ups being displayed on map marker long presses, so I'm good in this regard)
I'd have to add these other Views (SlideingDrawer, etc...) programmatically and not from the main_activity.xml. Even that has a catch-22, where the SlidingDrawer constructor needs an AttributeSet from xml that's painful to build yourself. (I tried) Then you also have to worry about the layout as well.
Anyone have any suggestions? General or otherwise? Thanks!
This might actually be useful to others for a number of reasons.
If you're stuck having to use a View that can only be configured the way to need via its programmatic constructor (e.g. you could just include the View from your activity_main.xml, but the View isn't what you need it to be unless you construct it yourself, like with offline tile maps using OSMDroid's MapView) then you're stuck extending that View and implementing that View's constructor that includes the AttributeSet. The AttributeSet is basically a structure parsed from the activity_main.xml xml for that view. That constructor will be called automatically in Activity when you this.setContentView(R.layout.activity_main) from onCreate(). So any custom constructor stuff needs to go in that constructor for your extended View.
For example, I had to extend the OSMDroid MapView, then implement my offline map tile source from the super entirely. NOTE you have to super() the 1st line in an extended constructor because object methods aren't available until after the inherited constructor is complete, so any super() method calls have to be to static methods.
public class FieldMapView extends MapView {
public FieldMapView(Context context, AttributeSet attrs) throws Exception {
super(
context,
256,
new DefaultResourceProxyImpl(context),
FieldMapView.getOfflineMapProvider(context, MainActivity.mapTileArchiveFilename),
null,
attrs);
this.setUseDataConnection(false);
this.setBuiltInZoomControls(false);
this.setMultiTouchControls(true);
}
Then in my activity_main.xml I point to the extended version of the View: (e.g. FieldMapView)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/rootview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<com.test.FieldMapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="false"/>
So now I have my extended View taking care of any programmatic style requirements, how did I get a SlidingDrawer working with it? I created a SlidingDrawer with a 0dip height View as the handle. I then included a LinearLayout that contains buttons, whatever you want, etc...
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/rootview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<com.test.FieldMapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="false"/>
<SlidingDrawer
android:layout_width="wrap_content"
android:id="#+id/slidingDrawerActions"
android:content="#+id/action_content"
android:padding="10dip"
android:layout_height="75dip"
android:handle="#+id/handle2"
android:layout_alignBottom="#id/mapview"
android:orientation="vertical"
android:clickable="false">
<LinearLayout
android:layout_width="wrap_content"
android:id="#+id/action_content"
android:orientation="horizontal"
android:gravity="center"
android:padding="10dip"
android:background="#FF999999"
android:layout_height="wrap_content"
android:clickable="false">
<View
android:id="#id/handle2"
android:layout_width="0dip"
android:layout_height="0dip" />
<ImageButton
android:id="#+id/chatActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dip"
android:src="#drawable/ic_action_edit"
android:text="Chat">
</ImageButton>
</LinearLayout>
</SlidingDrawer>
</RelativeLayout>
In my MainActivity onCreate() I just find the SlidingDrawer View and assign any listeners accordingly. For opening the drawer when long pressing a Marker in the MapView (this is getting more OSMDroid specific now) I naturally have an OnItemGestureListener to open the drawer:
class NodeGestureListener implements OnItemGestureListener<NodeOverlayItem> {
#Override
public boolean onItemLongPress(int index, NodeOverlayItem node) {
if(slidingDrawerActions.isOpened() || slidingDrawerActions.isMoving()) {
return false;
}
slidingDrawerActions.animateOpen();
return false;
}
The tricky part is I wanted to close it via a click on the MapView (not by touching a close button that takes up space) so I had to assign SlidingDrawer.OnDrawerOpenListener and OnDrawerCloseListener classes. They simply flipped a boolean indicating if the drawer was open or closed. I then set a simple onClickListener for the MapView that closed the drawer if it was open based on the isActionDrawerOpen set by the SlidingDrawer listeners.
public void onCreate(final Bundle savedInstanceState) {
...
this.mapView.setOnClickListener(new MapViewClickListener());
...
this.slidingDrawerActions = (SlidingDrawer)findViewById(R.id.slidingDrawerActions);
this.slidingDrawerActions.setOnDrawerOpenListener(new SlidingDrawerOpenListener());
this.slidingDrawerActions.setOnDrawerCloseListener(new SlidingDrawerCloseListener());
...
}
...
private boolean isActionDrawerOpen = false;
class SlidingDrawerOpenListener implements SlidingDrawer.OnDrawerOpenListener {
#Override
public void onDrawerOpened() {
isActionDrawerOpen = true;
}
}
class SlidingDrawerCloseListener implements SlidingDrawer.OnDrawerCloseListener {
#Override
public void onDrawerClosed() {
isActionDrawerOpen = false;
}
}
private boolean skippedMapViewClickListener = false;
class MapViewClickListener implements OnClickListener {
public void onClick(View view) {
if(isActionDrawerOpen) {
if(skippedMapViewClickListener) {
slidingDrawerActions.animateClose();
skippedMapViewClickListener = false;
} else {
skippedMapViewClickListener = true;
}
}
}
}
Note the skippedMapViewClickListener boolean. The problem I had was that the MapView OnClickListener would be called immediately after the SlidingDrawer listener when long pressing the Marker. Meaning the long press would be considered a MapView click, plus the long press itself would open the drawer before OnClickListener was called, so OnClickListener would always see the drawer as open, and would close it. What I did was effectively skip the 1st onClick this way, so the drawer would stay open until you clicked on the MapView. Seems to work great.
I hope this helps someone. There are like 4 problems I solved with this approach.
How do I make the settings navigation for SwitchReference like Android native settings app?
Where when u click on WiFi region(not on the switch) it will navigate to a new screen:
My app only change the switch from ON to OFF and vice versa even when I'm not clicking on the switch.
I'm using PreferenceFragment and xml for the screen. And my preference is following the example from Android PreferenceFragment documentation. I develop my app on ICS 4.0 API 14.
Anyone know how to do this?
Edited:
My XML look like this:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:layout="#layout/preference_category"
android:title="User Settings" >
<SwitchPreference
android:key="pref_autorun"
android:layout="#layout/preference"
android:summary="Autorun SMODE on boot"
android:title="Autorun SMODE" />
<SwitchPreference
android:key="pref_wifi_control"
android:layout="#layout/preference"
android:selectable="false"
android:summary="Controls your Wi-Fi radio automatically based on hotspot availability"
android:title="Wi-Fi Radio Control" />
</PreferenceCategory>
</PreferenceScreen>
By taking a look at the source of the stock Settings app, you can find how they did it.
Basically, they use a custom ArrayAdapter (much like you would do with a ListView) to display rows with Switch buttons. And for the second screen, they simply use the CustomView available in the ActionBar.
I wrote an article with a sample code to show how you can do it in your project. Be careful though, this can only wirk in API Level 14 or higher, so if you target older devices, keep an old style preference screen.
I see 2 questions here: 1. How to listen to preference click outside the switch area? 2. How to put a switch in the actionbar?
I'll answer question 1:
I created a new SwitchPreference class and overrode the onClick method to do nothing. This prevents the setting change when clicking outside the switch.
public class SwitchPreference extends android.preference.SwitchPreference {
#Override
protected void onClick() {
}
}
Usage (xml):
<android.util.SwitchPreference
android:key="whatever"
android:title="Whatever" />
Usage (java):
SwitchPreference switchPreference = (SwitchPreference) findPreference("whatever");
switchPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
DialogUtils.showToast(Preferences.this, "Clicked outside switch");
return true;
}
});
switchPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
DialogUtils.showToast(Preferences.this, "Clicked inside switch and setting changed");
return true;
}
});
I gave this one a try and struggled a bit. I thought I would share my experience.
At first I tried the answer by XGouchet since it had the most up votes. The solution was fairly complicated and required using preference headers which are very cool but did not fit what I was doing. I decided the easiest thing for me to do is to wrap up my preferenceFragment in a regular fragment and make fake the switch preference with a regular view. I dug up the android source for a preference and came up with this
<LinearLayout 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:orientation="vertical"
tools:context="com.lezyne.link.ui.homeScreen.settingsTab.SettingsFragment">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
</FrameLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:background="#e1e1e1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:paddingRight="?android:attr/scrollbarSize">
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="6dip"
android:layout_marginLeft="15dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_weight="1">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#android:id/title"
android:layout_below="#android:id/title"
android:maxLines="4"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary" />
</RelativeLayout>
<!-- Preference should place its actual preference widget here. -->
<RelativeLayout
android:id="#+id/widget_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingEnd="36dp">
<Switch
android:thumb="#drawable/switch_inner"
android:id="#+id/switch1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true" />
<TextView
android:id="#+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:text="#string/Notifications"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:background="#e1e1e1" />
</LinearLayout>
The FrameLayout at the top gets a preference fragment like so
getChildFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new SettingsPreferencesFragment(), "SettingsPreferencesFragment")
.commit();
Then I can get assign my click listeners as I would in any regular view. SettingsPreferencesFragment is just totally standard preference fragment.
This solution seemed pretty good, but then I noticed weird layout issues on tablets. I realized that I would have trouble getting this solution to look right on all devices and I needed to use a real switchPreference not a fake one.
============== Solution 2 ===============
AlikElzin-kilaka's solution was nice and simple but did not work when I tried. I tried a 2nd time to make sure that I had not just done it wrong. I kept playing around and came up with something that seems to work. He has a good point about
2 questions here: 1. How to listen to preference click outside the
switch area? 2. How to put a switch in the actionbar?
Really only question (1) is worth answering because question 2 has been answered here and other places
I realized the only way to get access to the views in a preference was to create a child class and override onBind. So I came up with this child class of SwitchPreference that creates separate click handlers for the switch as the entire view. Its still a hack though.
public class MySwitchPreference extends SwitchPreference {
public MySwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MySwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
getView(null,null);
}
public MySwitchPreference(Context context) {
super(context);
}
public interface SwitchClickListener{
public void onSwitchClicked(boolean checked);
public void onPreferenceClicked();
}
private SwitchClickListener listener = null;
public void setSwitchClickListener(SwitchClickListener listener){
this.listener = listener;
}
public Switch findSwitchWidget(View view){
if (view instanceof Switch){
return (Switch)view;
}
if (view instanceof ViewGroup){
ViewGroup viewGroup = (ViewGroup)view;
for (int i = 0; i < viewGroup.getChildCount();i++){
View child = viewGroup.getChildAt(i);
if (child instanceof ViewGroup){
Switch result = findSwitchWidget(child);
if (result!=null) return result;
}
if (child instanceof Switch){
return (Switch)child;
}
}
}
return null;
}
protected void onBindView (View view){
super.onBindView(view);
final Switch switchView = findSwitchWidget(view);
if (switchView!=null){
switchView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener!=null) listener.onSwitchClicked(switchView.isChecked());
}
});
switchView.setFocusable(true);
switchView.setEnabled(true);
}
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener!=null) listener.onPreferenceClicked();
}
});
}
}
It uses the recursive function findSwitchWidget to walk the tree until it finds a Switch. I would have rather write code like this:
Switch switchView = view.findViewById(android.R.id.switchView);
but there does not seem to be a way to get to that internal id value that I know of. Anyhow once we have the actual switch we can assign listeners to it and the container view. The switch preference won't update automatically so its necessary to save the preference yourself.
MySwitchPreference switchPreference = (MySwitchPreference) findPreference("whatever");
switchPreference.setSwitchClickListener(new MySwitchPreference.SwitchClickListener() {
#Override
public void onSwitchClicked(boolean checked) {
//Save the preference value here
}
#Override
public void onPreferenceClicked() {
//Launch the new preference screen or activity here
}
});
Hopefully this 2nd hack wont come back to bite me.
Any one see any potential pitfalls of this method?
I also put a slightly improved version of the code on github https://gist.github.com/marchold/45e22839eb94aa14dfb5
I have this layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.components.game.GameView
android:id="#+id/game_id"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<RelativeLayout
android:id="#+id/ChatLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="invisible"
android:focusable="true"
android:focusableInTouchMode="true" >
<Button
android:id="#+id/ChatCancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="X" />
<Button
android:id="#+id/ChatOkButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="OK" />
<EditText
android:id="#+id/ChatEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#+id/ChatOkButton"
android:layout_toRightOf="#+id/ChatCancelButton"
android:maxLength="50"
android:singleLine="true" />
</RelativeLayout>
</RelativeLayout>
It's a RelativeLayout over a canvas. At start time it's invisible but when a user clicks a button the layout should become visible.
The problem is that it's not becoming visible. The layout is there but it's just not drawing it. If I press the position where the layout should appear it receives the event and opens the keyboard but it's not drawing the whole layout.
What is the problem?
If I set the RelativeLayout to visible at the beginning it works fine. it shows the layout and if I toggle between invisible and visible it works fine.
I made a workaround that almost always works.
I start the layout visible and than do that in the oncreate:
chatLayout.postDelayed(new Runnable() {
#Override
public void run() {
chatLayout.setVisibility(View.INVISIBLE);
}
}, 50);
But I don't like it and want to understand what's the problem.
The code:
It starts from a canvas button which send a message to a handler:
public void showInputLayout() {
Message.obtain(gameHandler, SHOW_INPUT_LAYOUT).sendToTarget();
}
In the handler:
case SHOW_INPUT_LAYOUT:
gameActivity.setChatVisibility(true);
break;
setChatVisibility:
public void setChatVisibility(boolean isVisible) {
int visible = isVisible ? View.VISIBLE : View.INVISIBLE;
chatLayout.setVisibility(visible);
if(isVisible){
chatEditText.setFocusable(true);
chatEditText.requestFocus();
}
}
Add a click listener to RelativeLayout and switch the visibility between GONE and VISIBLE. Try something like this:
int visibility = View.VISIBLE;
RelativeLayout layout = (RelativeLayout)findViewById(R.id.ChatLayout);
layout.setVisibility(visibility);
layout.setOnClickListener(new View.OnClickListener{
public void onClick(View v)
{
if(visibility == View.VISIBLE)
visibility = View.GONE;
else
visibility = View.VISIBLE;
v.setVisibility(visibility);
}
})
I ran into a similar issue recently, and for my case the problem was actually in the onDraw() method of the view underneath (should be com.components.game.GameView in your case). See if you can add calls to Canvas' getSaveCount(), save() and restoreToCount() in your drawing code, similar to this:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int saveCount = canvas.getSaveCount();
canvas.save();
// custom drawing code here ...
// use Region.Op.INTERSECT for adding clipping regions
canvas.restoreToCount(saveCount);
}
I believe what happened was that sometimes the framework set the clipping regions for the elements on top of our Canvas-drawing widget before our onDraw() method is called so we need to make sure that those regions are preserved.
Hope this helps.
I come to you on bended knee, question in hand. I am relatively new to Android, so pardon any sacrilegious things I might say.
Intro: I have several layouts in the app, that all have to include a common footer. This footer has some essential buttons for returning to the home page, logging out, etc.
I managed to get this footer to appear in all the requisite pages with the help of the Include and Merge tags. The issue lies in defining on click listeners for all the buttons. Although I can define the listeners in every activity associated with screens that include the footer layout, I find that this becomes terribly tedious when the number of screens increases.
My question is this: Can I define a button click listener that will work across the application, which can be accessed from any screen with the use of the android:onClick attribute of the Button?
That is to say, I would like to define the button click listener once, in a separate class, say FooterClickListeners, and simply name that class as the listener class for any button clicks on the footer. The idea is to make a single point of access for the listener code, so that any and all changes to said listeners will reflect throughout the application.
I had the same problem with a menu which I used in several layouts. I solved the problem by inflating the layout xml file in a class extending RelativeLayout where I then defined the onClickListener. Afterwards I included the class in each layout requiring the menu. The code looked like this:
menu.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageButton android:id="#+id/map_view"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:src="#drawable/button_menu_map_view"
android:background="#null"
android:scaleType="fitCenter"
android:layout_height="#dimen/icon_size"
android:layout_width="#dimen/icon_size">
</ImageButton>
<ImageButton android:id="#+id/live_view"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:src="#drawable/button_menu_live_view"
android:background="#null"
android:scaleType="fitCenter"
android:layout_height="#dimen/icon_size"
android:layout_width="#dimen/icon_size">
</ImageButton>
<ImageButton android:id="#+id/screenshot"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:src="#drawable/button_menu_screenshot"
android:background="#null"
android:scaleType="fitCenter"
android:layout_height="#dimen/icon_size"
android:layout_width="#dimen/icon_size">
</ImageButton>
</merge>
MenuView.java
public class MenuView extends RelativeLayout {
private LayoutInflater inflater;
public MenuView(Context context, AttributeSet attrs) {
super(context, attrs);
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.menu, this, true);
((ImageButton)this.findViewById(R.id.screenshot)).setOnClickListener(screenshotOnClickListener);
((ImageButton)this.findViewById(R.id.live_view)).setOnClickListener(liveViewOnClickListener);
((ImageButton)this.findViewById(R.id.map_view)).setOnClickListener(mapViewOnClickListener);
}
private OnClickListener screenshotOnClickListener = new OnClickListener() {
public void onClick(View v) {
getContext().startActivity(new Intent(getContext(), ScreenshotActivity.class));
}
};
private OnClickListener liveViewOnClickListener = new OnClickListener() {
public void onClick(View v) {
getContext().startActivity(new Intent(getContext(), LiveViewActivity.class));
}
};
private OnClickListener mapViewOnClickListener = new OnClickListener() {
public void onClick(View v) {
getContext().startActivity(new Intent(getContext(), MapViewActivity.class));
}
};
}
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/main"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<SurfaceView android:id="#+id/surface"
android:layout_width="fill_parent"
android:layout_weight="1"
android:layout_height="fill_parent">
</SurfaceView>
<!-- some more tags... -->
<com.example.inflating.MenuView
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>
with the <com.example.inflating.MenuView /> tag, you are now able to reuse your selfwritten Layout (incl onClickListener) in other layouts.
This is something that is getting added to roboguice in the near the future. It will allow you to build controller classes for things like titlebar's and footers and have the events autowired for you.
Checkout http://code.google.com/r/adamtybor-roboguice/ for the initial spike.
Basically if you are using roboguice you can define a component for footer and just inject that footer component into each activity.
Unfortunately you still have to add the controller to every activity, just like you did with the include layout, but the good news is everything gets wired up for you and all your logic stays in a single class.
Below is some pseudo code of some example usage.
public class FooterController {
#InjectView(R.id.footer_button) Button button;
#Inject Activity context;
#ContextObserver
public void onViewsInjected() {
button.setOnClickListener(new OnClickListener() {
void onClick() {
Toast.makeToast(context, "My button was clicked", Toast.DURATION_SHORT).show();
}
});
}
}
public class MyActivity1 extends RoboActivity {
#Inject FooterController footer;
}
public class MyActivity2 extends RoboActivity {
#Inject FooterController footer;
}
The solution as you describe is impossible, sorry. But you can have common parent activity for all your activities that use the footer. In the activity just provide handler methods for your footer buttons, then just inherit from it every time you need to handle the footer actions.