Crash when clicking button with custom theme - android

I am creating a custom theme for button and using android:onClick event of Button from xml itself to handle the click of Button.
Due to some reason its crashing with below exception
java.lang.IllegalStateException: Could not find a method MyOnClick(View) in the activity class android.view.ContextThemeWrapper for onClick handler on view class android.widget.Button with id 'button1'
And its working fine if I just remove the theme attribute from the Button, below is my theme for Button
<style name="ButtonTheme" parent="#android:style/Widget.Button">
<item name="android:textColor">#FF0000</item>
<item name="android:shadowColor">#FF000000</item>
</style>
And my Button defined in xml as below,
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView1"
android:layout_margin="20dp"
android:onClick="MyOnClick"
android:theme="#style/ButtonTheme"
android:text="Button" />
Here is my java code as well,
public void MyOnClick(View view) {
switch (view.getId()) {
case R.id.button1:
getWindow().setStatusBarColor(getResources()
.getColor(R.color.statusBarColor));
getWindow().setNavigationBarColor(getResources()
.getColor(R.color.statusBarColor));
break;
default:
break;
}
}
So, what could be the reason for crashing? I am able to handle the click event if I remove android:theme="#style/ButtonTheme" attribute from Button Widget from xml.

I've never seen anybody applying the android:theme attribute to an individual View, but after a bit of googling I found out that this is indeed possible, but only since Android 5.0.
A hint of this can be seen at the end here.
And some more detail here.
As the second link explains, a ContextThemeWrapper is used to modify the theme associated with the base Context. However, since your Activity will need to hold on to its own theme, I can only imagine that a new ContextThemeWrapper is created and assigned as the new Context of your View. Since this new Context is not your Activity any more, your callback functions don't exist here and you get the error you describe.
You can use the debugger to prove this yourself (I used Android Studio, but you can probably use the IDE of your choice, the details might be different).
Run the app in debug mode with theme attribute set.
When you get the exception, the stacktrace will contain a reference to the View class where it invokes onClick.
Use this to add a breakpoint before the exception occurs.
Now run the app again in debug mode, click the button
When you hit the breakpoint evaluate the expression getContext(). You will see that this returns an object of type ContextThemeWrapper and it will have a member mBase which points back to your actual Activity, so getContext() itself does not return your Activity and does not have the callback functions you defined on your Activity.
Now remove the theme attribute, leave the breakpoint and run the app again.
When you hit the breakpoint, evaluate the expression getContext() again and you will see that this time it returns your Activity directly, which is why your callbacks work, if you don't set the theme attribute.
In short, it seems like you can't use the android:onClick attribute if you want to make use of this new feature, and you will have to manually assign an OnClickListener as described here

Sometimes when we add style to Button It affects default android clickable behavior.
Try adding property clickable="true" in <Button... />
Or
You can also add <item name="android:clickable" >true</item> to style of button.

After spending so much time on this, the thing that worked for me was to apply the theme in code setTheme(R.style.AppToolbar); in the onCreate() instead of ripping out all the android:OnClick from all the layouts.

Related

Why EditText only accepts Theme?

I was trying to apply a style to an EditText to change it's colorAccent, I tried to set its style and android:textAppearance, but it completely ignored my new settings. The only way I got it to work was by setting its android:theme.
Am I doing something wrong or is this expected behavior? Why?
My style:
<style name="bright_color_cursor" parent="AppTheme">
<item name="colorAccent">#color/primaryBrightColor</item>
<item name="android:textColorHighlight">#color/primaryBrightColor</item>
</style>
My EditText:
<EditText
android:id="#+id/edit_text"
android:theme="#style/bright_color_cursor"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="#android:color/transparent"
android:ems="10"
android:hint="#string/hello"
android:inputType="textCapWords"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/name_edit_text"
app:layout_constraintTop_toBottomOf="#+id/divider" />
Changing android:theme to any of this settings won't work:
style="#style/bright_color_cursor"
or
android:textAppearance="#style/bright_color_cursor"
Yep, this behavior is to be expected with an EditText. We need to style it by using the android:theme property.
When using #style, the EditText doesn't use the values that we set (and thus the style seems to be ignored). This is, because the EditText creates some children views that are not being styled. See my detailed explanation below.
Detailed explanation and the cause
1) First, the meanings of the options tried and what these do:
style: (Note: not prefixed with android:): This sets the styles only for the component itself and does not change the styles of it's underlying children views/layouts.
android:theme: This basically applies to style to itself and applies the style to it's children views/layouts.
android:textAppearance: This one behaves just like #style for styling.
2) The EditText functionality
As we can imagine: an EditText is not just a simple view. It has a background drawable and handles interaction and such. It simply needs some additional views (and logic) for this functionality to work.
For the functionality of the EditText, it adds some subviews as children to be able to do what we expect from it.
3) Back to theming
The subviews that the EditText adds to do it's functionality, are styled just like the other views are being styled. Which means that the child views only inherit the style when we use the android:theme property. Because this property causes it to style the children views too.
And, if we use #style on the edittext, the children will not get this style.
4) Why this happens (only) for EditText?
Well, not really only... The base view of an EditText is a TextView, but a TextView doesn't provide the functionality that an EditText needs. So the EditText adds additional functionality itself.
A Button for example has the TextView as base too. But this class has enough views with the text and background it gets from the base class, and thus a Button doesn't need to add additional views for it's functionality. So for this, using #style works as it creates no children views to style.
Having said this, a small remark:
In fact, in the source the TextView actually contains the editting logic, but in case of a Button it simply doesn't execute that part of code. (A button doesn't need the Editting functionality, thus it's not being executed)

Android: Specify full method path in android:onClick

This question is about Android development. In general, how do you tie a layout XML file to a certain Activity java file? This is relevant in a case such as a button with the android:onClick attribute specified. Suppose you have a layout XML file with a button like the following:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/button_send"
android:onClick="sendMessage" />
So when this button is clicked, a sendMessage(View view) method is called. If more than one Activity has a sendMessage(View view) method, how does Android decide which one to call? There's literally absolutely nothing associating layout files with Activity files. In Android Studio, I've found that the android:onClick="sendMessage" defaults to the main activity's sendMessage method if there is more than one choice. I've also found that Android Studio doesn't let you simply specify the full method path (for example, android:onClick="com.example.Activity2.sendMessage"). Am I missing something?
Edit: I would like to add that Android Studio shows the sendMessage defaulting to a specific activity, REGARDLESS of which Activities have specified the layout via setContentView()
The android:onClick will call the method on the Activity your layout is inflated and attached to. There should be no tight coupling between a layout and it's controller, so thats why you can't specify a "full path".
I'd recommend using a programatical OnClickListener instead of the xml attribute. It gives you much greater control.
There is a tools:context attribute that you can use to tell Android Studio in what context the layout is meant to be used. You specify a class there and then it should take this class to find the correct method
But this attribute is only for the IDE. During Runtime it binds to the method of the activity that inflated the layout.
Of course it will call the method from the activity class of that view. So simply it will call from main activity class if that view is from main activity and if the view is from , for example Activity2, then it will look for the sendMessage method in the Activity2. If it failed to find the sendMessage method in the Activity2 class then it will throw a NullpointerException.

How does android populate stylable members of a View when not all are supplied in custom style

I have a basic question about styles/theme application to actual objects.
Firstly from android documentation Link here
A theme is a style applied to an entire Activity or application,
rather than an individual View (as in the example above). When a style
is applied as a theme, every View in the Activity or application will
apply each style property that it supports.
and from the same article
However, if you apply a style to a View that does not support all of
the style properties, the View will apply only those properties that
are supported and simply ignore the others.
So say I use a native theme of a platform in the android manifest file in the application element.
android:Theme.Holo.Light
So per documents each and every view in all activities/application will be applied style properties from the theme above.
Say I have only one custom style in the entire application and I used it on a button.
<style name="RedColor">
<item name="android:textColor">#FF0000</item>
</style>
<Button
style="#style/RedColor"
android:text="#string/hello" />
So all views in the application will be applied main style/theme android:Theme.Holo.Light
But one view (Button) gets applied my custom style called RedColor.
In RedColor style I did not specify any other properties for button and I also did not intentionally inherit the style from any other.
The document says the View will apply only those properties that
are supported and simply ignore the others.
The Question is when this particular view (Button) becomes an actual object and ofcourse the Button has more than textColor as its members how does android populate the remaining properties of this Button or View ?
Basically if I am not wrong,
As per your question at first the Button will be applied the default theme of the activity. After that when the Button is inflated to display inside the Activity, it will see for the button properties and apply to that button which are applicable to Button.

Getting Style Name of a specific view - Android

I have an EditText and a custom Style, and I would like to know how I can programmatically, get the "name" of this style, like below:
<EditText
android:id="#+id/idValue"
style="#style/integerNumber"
... />
In the code,
EditText edValue = findViewById (R.id.idValue);
In this case, I need to receive "integerNumber". Is there a specific method to get this information? (such as edValue.getResources().getStyle()) ... I could not find at all.
I'm afraid you can't. Looking at the view constructor (in particular ), the style is used just to define view's properties but it's thrown away afterwards. It is not stored anywhere, so I guess you can't retrieve it from the view object.
If you need to get the style you can still (conventionally) add a tag to the views and behave according to that.

Activity exit animations don't work as expected on Android 4.0

I have a theme that changes the activity's open/close/enter/exit animations:
<style name="down_up_theme" parent="Theme.rtlfr">
<item name="android:windowAnimationStyle">#style/down_up_animation</item>
</style>
<style name="down_up_animation" parent="#android:style/Animation.Activity">
<item name="android:activityOpenEnterAnimation">#anim/slide_in_top</item>
<item name="android:activityOpenExitAnimation">#anim/hold</item>
<item name="android:activityCloseEnterAnimation">#anim/hold</item>
<item name="android:activityCloseExitAnimation">#anim/slide_out_bottom</item>
</style>
And in the manifest:
<activity android:name=".activity.ArticlesActivity"
android:theme="#style/down_up_theme" />
The goal is to make the activity content slide down on start, and slide up at exit.
The animations work fine on 2.3. On 4.0, though, the exit animation (slide up) doesn't work. What it does animate is the closing of the activities that are spawned from this activity. In my case, I want to animate the closing of the activity with the list of articles, instead the closing of the article detail has the slide up animation.
I guess I could try to add the closing animation to the activity that spawns the one I want to animate, but it actually spawns activities that should have different animations. I also couldn't find any information on this 2.3 vs. 4.0 difference in the documentation.
How can I make my animations work on 4.0?
I'm not sure why the exit animation set in the theme is not working on ICS+, but calling overridePendingTransition() seems to be working. The simplest way to do this for you is probably to override finish() in your Activity:
#Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.hold, R.anim.slide_out_bottom);
}
I'd like to add just a little extra to this answer; the override animation solution works fine, but you probably don't want to hard-code the animations. It would be nice to get them from the manifest as you would for other versions of the platform.. so....
add a couple of member fields to your activity to hold the ids of the animations attached to your activity..
protected int activityCloseEnterAnimation;
protected int activityCloseExitAnimation;
and somewhere in your onCreate...
// Retrieve the animations set in the theme applied to this activity in the
// manifest..
TypedArray activityStyle = getTheme().obtainStyledAttributes(new int[] {android.R.attr.windowAnimationStyle});
int windowAnimationStyleResId = activityStyle.getResourceId(0, 0);
activityStyle.recycle();
// Now retrieve the resource ids of the actual animations used in the animation style pointed to by
// the window animation resource id.
activityStyle = getTheme().obtainStyledAttributes(windowAnimationStyleResId, new int[] {android.R.attr.activityCloseEnterAnimation, android.R.attr.activityCloseExitAnimation});
activityCloseEnterAnimation = activityStyle.getResourceId(0, 0);
activityCloseExitAnimation = activityStyle.getResourceId(1, 0);
activityStyle.recycle();
then wherever your activity finishes/should apply animation include...
overridePendingTransition(activityCloseEnterAnimation, activityCloseExitAnimation);
and your activities should correctly honour the animations you set in the theme/style attached to activities in your manifest.
I was confused by this problem, too. But fortunately soon later I found what the answer was. You should check your animation file whether its root element is "Set" or not. If it's not, you should wrap it with "Set" element and then ActivityCloseAnimation attribute would work fine.
I have tried it. Hope it could help you.
you shoud look here use overridePendingTransition and windowEnterAnimation/windowExitAnimation shoud work for you

Categories

Resources