View ignores alpha value after View.VISIBLE - android

I have a button ,with alpha set to 0.5, and its visibility is gone in the layout.
<Button
android:id="#+id/Button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#color/black_color"
android:alpha="0.5"
android:visibility="gone"/>
At some point, I wish to make it visible ( Button.setVisibility(View.VISIBLE); ), but when I do - it's not half-transparent (0.5). It appears as if alpha is set to 1.

This problem is usually the result of having android:animateLayoutChanges="true" in the parent view. The reason is that the layout animation of setting visibility also changes the alpha of the view and overrides the change made by setAlpha.
To resolve this you can either remove android:animateLayoutChanges="true" from the parent or create a custom view to set the visibility in onVisibilityChanged like this:
public class AlphaView extends View {
private static final String TAG = AlphaView.class.getSimpleName();
public AlphaView(Context context) {
super(context);
}
public AlphaView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public AlphaView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public AlphaView(Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected void onVisibilityChanged(#NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (visibility == VISIBLE) {
setAlpha(0.5f);
}
}
}

I ran into this problem as well. It seems to be a bug in Android itself. My solution was to avoid setting visibility, and to adjust alpha only. My view has a visibility of 'visible' in the XML, and starts off with the XML alpha tag value set to 0.0. Then, when I want it to be visible, I adjust the alpha programmatically:
dimmerView.setAlpha(.15f);
I disappear it by setting the alpha again to zero. Theoretically, you might need to adjust various views position on the z-axis with bringToFront (and in the case of a button you might want to remove its listener when alpha is set to zero), but in my implementation it did not seem to be necessary.

After setting Button Gone to Visible, add Alpha of the Button
like :
buttonObject.setAlpha(.5f);

Related

Android: FAB above the KeyBoard combined with the SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flag

The problem is that the FAB does not stay above the keyboard when using this flag:
this.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
I tried :
android:fitsSystemWindows="true"
It works but it removes the SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN effect.
android:windowSoftInputMode="adjustResize"
It does not work.
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
It also does not work
Any sugestion ?
I just found a simple and reliable solution if you are using the system UI approach (https://developer.android.com/training/system-ui/immersive.html).
It works in the case when you are using View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, e.g. if you are using CoordinatorLayout.
It won't work for WindowManager.LayoutParams.FLAG_FULLSCREEN (The one you can also set in theme with android:windowFullscreen), but you can achieve similar effect with SYSTEM_UI_FLAG_LAYOUT_STABLE (which "has the same visual effect" according to the docs) and this solution should work again.
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION /* If you want to hide navigation */
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
I've tested it on my device running Marshmallow.
The key is that soft keyboards are also one of the system windows (such as status bar and navigation bar), so the WindowInsets dispatched by system contains accurate and reliable information about it.
For the use case such as in DrawerLayout where we are trying to draw behind the status bar, We can create a layout that ignores only the top inset, and applies the bottom inset which accounts for the soft keyboard.
Here is my custom FrameLayout:
/**
* Implements an effect similar to {#code android:fitsSystemWindows="true"} on Lollipop or higher,
* except ignoring the top system window inset. {#code android:fitsSystemWindows="true"} does not
* and should not be set on this layout.
*/
public class FitsSystemWindowsExceptTopFrameLayout extends FrameLayout {
public FitsSystemWindowsExceptTopFrameLayout(Context context) {
super(context);
}
public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#RequiresApi(Build.VERSION_CODES.LOLLIPOP)
public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(),
insets.getSystemWindowInsetBottom());
return insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0);
} else {
return super.onApplyWindowInsets(insets);
}
}
}
And to use it:
<com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Your original layout here -->
</com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout>
The credits go to : #Hai Zhang

setMinHeight and setMaxHeight in android custom view

Hi I want to set android custom buttons' setMinHeight and setMaxHeight
I have android button widget in the Library project and user of SDK(library project) can take use of that custom Button but I want to put restriction that button's Minimum size has to be 200dp and button's maximum height can not exceed 350dp how do i achieve that from custom view Button custom class?
Tried searching lot of thread but not sure yet.
public class MyCustomButton extends android.widget.Button {
public MyCustomButton(Context context) {
super(context);
applyDefaults(null);
}
public MyCustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
applyDefaults(attrs);
}
public MyCustomButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
applyDefaults(attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MyCustomButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
applyDefaults(attrs);
}
private void applyDefaults(AttributeSet attrs) {
String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height");
String width = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_width");
Log.e("MVYAS=======", "height===" + height);
Log.e("MVYAS=======", "width===" + width);
setUpButtonForLoginOrLogout();
setAllCaps(false);
setMinHeight(getResources().getDimensionPixelSize(R.dimen.mid_button_min_height));
setMinWidth(getResources().getDimensionPixelSize(R.dimen.mid_button_min_width));
setMaxHeight(getResources().getDimensionPixelSize(R.dimen.mid_button_max_height));
setMaxWidth(getResources().getDimensionPixelSize(R.dimen.mid_button_max_width));
}
}
and while using into layout.xml file
<com.example.library.widget.MyCustomButton
android:id="#+id/my_button"
android:layout_width="153dp"
android:layout_height="57dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignWithParentIfMissing="true"
android:layout_margin="10dp"
styleButton:mobileid="inverted"/>
Here user should not be able to create button height to 57dp as its lower than the desired button height.
Putting restriction by adding setMinHeight() and setMaxHeight() dose not work.
How do i achieve that. Your help appreciated.
Thanks in Advance.
Just add these below two methods in MyCustomButtom class and try it:
#Override
public void setMinimumHeight(int minHeight) {
super.setMinimumHeight(minHeight);
}
#Override
public void setMinHeight(#Px int minHeight) {
super.setMinHeight(minHeight);
}
And one more thing, add below line in applyDefaults() function.
setMinimumHeight(getResources().getDimensionPixelSize(R.dimen.mid_button_min_height));

Extending Preference classes in Android Lollipop = losing animation

Just for extending CheckBoxPreference or SwitchPreference on Android Lollipop, the widget (the checkbox or the switch) won't have animation anymore.
I'd like to extend SwitchPreference to force api < 21 to use SwitchCompat instead of the default one they are using (which is obviously wrong).
I am using the new AppCompatPreferenceActivity with appcompat-v7:22.1.1 but that doesn't seem to affect the switches.
The thing is that with just extending those classes, without adding any custom layout or widget resource layout, the animation is gone.
I know I can write two instances of my preference.xml (on inside values-v21) and it will work... But I'd like to know why is this happening and if somebody knows a solution without having two preference.xml.
Code example:
public class SwitchPreference extends android.preference.SwitchPreference {
public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public SwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SwitchPreference(Context context) {
super(context);
}
}
This or the same for CheckBoxPreference and then using:
<com.my.package.SwitchPreference />
Will make the animation in a Lollipop device to be gone.
--
Another thing I tried for the SwitchPreference (that I can with CheckBoxPreference) is to give a layout with the default id but #android:id/switchWidgetis not public while #android:id/checkbox is. I also know I can use a <CheckBoxPreference /> and give a widget layout that is in fact a SwitchCompat, but I'd like to avoid that (confusing the names).
It seems I found a fix for your issue.
Extensive Explanation
In SwitchCompat, when toggling the the switch, it tests a few functions before playing the animation: getWindowToken() != null && ViewCompat.isLaidOut(this) && isShown().
Full method:
#Override
public void setChecked(boolean checked) {
super.setChecked(checked);
// Calling the super method may result in setChecked() getting called
// recursively with a different value, so load the REAL value...
checked = isChecked();
if (getWindowToken() != null && ViewCompat.isLaidOut(this) && isShown()) {
animateThumbToCheckedState(checked);
} else {
// Immediately move the thumb to the new position.
cancelPositionAnimator();
setThumbPosition(checked ? 1 : 0);
}
}
By using a custom view extending SwitchCompat, I found out, that isShown() always returns false, because the at third iteration of the while, parent == null.
public boolean isShown() {
View current = this;
//noinspection ConstantConditions
do {
if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
ViewParent parent = current.mParent;
if (parent == null) {
return false; // We are not attached to the view root
}
if (!(parent instanceof View)) {
return true;
}
current = (View) parent;
} while (current != null);
return false;
}
Interestingly, the third parent is the second attribute passed to getView(View convertView, ViewGroup parent) in Preference, means the PreferenceGroupAdapter didn't get a parent passed to its own getView(). Why this happens exactly and why this happens only for custom preference classes, I don't know.
For my testing purposes, I used the CheckBoxPreference with a SwitchCompat as widgetLayout, and I also didn't see animations.
Fix
Now to the fix: simply make your own view extending SwitchCompat, and override your isShown() like this:
#Override
public boolean isShown() {
return getVisibility() == VISIBLE;
}
Use this SwitchView for your widgetLayout style, and animations work again :D
Styles:
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
…
<item name="android:checkBoxPreferenceStyle">#style/Preference.SwitchView</item>
…
</style>
<style name="Preference.SwitchView">
<item name="android:widgetLayout">#layout/preference_switch_view</item>
</style>
Widget layout:
<de.Maxr1998.example.preference.SwitchView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null"
android:clickable="false"
android:focusable="false" />
Sometimes Extending from a Class is not the best solution. To avoid loosing the animations you could instead Compose it, I meant creating a Class where you have a SwitchPreference field variable and apply the new logic to it. It's like a wrapper. This worked for me.
i manage to fix it like this and animations is working before it was going to the state directly without animation:
FIX:
CustomSwitchCompat.class
public class CustomSwitchCompat extends SwitchCompat {
public CustomSwitchCompat(Context context) {
super(context);
}
public CustomSwitchCompat(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean isShown() {
return getVisibility() == VISIBLE;
}
}
In your layout do this: preference_switch_layout.xml
<com.example.CustomSwitchCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null"
android:clickable="false"
android:focusable="false"
app:switchMinWidth="55dp"/>
and in your preference.xml do this:
<CheckBoxPreference
android:defaultValue="false"
android:key=""
android:widgetLayout="#layout/preference_switch_layout"
android:summary=""
android:title="" />
I was having this issue, when I was using custom layout (app:layout) for SwitchPreference. At first, switch animation was triggered, but after a little scrolling it stopped and switch was jumping without animation. I tried every solution from stackoverflow, but nothing helped.
After debugging of SwitchCompat.setChecked method I found out that this condition is failing:
public void setChecked(boolean checked) {
...
if (getWindowToken() != null && ViewCompat.isLaidOut(this)) {
animateThumbToCheckedState(checked);
} else {
// Immediately move the thumb to the new position.
cancelPositionAnimator();
setThumbPosition(checked ? 1 : 0);
}
}
Concretely ViewCompat.isLaidOut(this) returned false. I guess this is a bug either in View or Preference (or subclasses). Anyway, I was able to fix this with little hack.
I created a subclass of SwitchCompat and did override setChecked method, where I call requestLayout() and in onNextLayout I call SwitchCompat's setChecked method. This guarantees that isLaidOut condition is true when changing checked state.
Full code of custom SwitchCompat:
class SwitchCompatFix #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = androidx.appcompat.R.attr.switchStyle,
): SwitchCompat(context, attrs, defStyleAttr) {
override fun setChecked(checked: Boolean) {
doOnNextLayout {
post { super.setChecked(checked) }
}
requestLayout()
}
}
public class SwitchPreference extends android.preference.SwitchPreference {
public SwitchPreference(Context context) {
this(context, null);
}
public SwitchPreference(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.checkBoxPreferenceStyle);
}
public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
try {
Field canRecycleLayoutField = Preference.class.getDeclaredField("mCanRecycleLayout");
canRecycleLayoutField.setAccessible(true);
canRecycleLayoutField.setBoolean(this, true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}

Custom view with children inside it(buttons, edittexts, etc.)

I have custom view which extends imageview (with glow touch). I want to add elements like buttons, textviews, to make glow touch when they are touched. I read that custom view cannot have children because only layouts can have them.
Is there any workaround to solve this stuff?
Code:
public class CustomView extends ImageView{
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context) {
super(context);
.........
}
With regards
You are correct about the fact that only layouts (ViewGroups) can contain Views, and Views itself can not.
Instead of making a custom View, you can make a custom ViewGroup. In there you can add the Views you need, like the ImageViews and the others you mention (Buttons, EditText, etc).

Rotated ( 90 degrees ) root ViewGroup

I am trying to create ViewGroup based on FrameLayout that might be rotated 90 degrees CW / CCW and it still will be working correctly
So far my results are not so sucesful. So far it looks like that ( left side before rotation, right after; sorry for bright red )
Layout for Activity
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.TestProject.RotatedFrameLayout
android:id="#+id/container"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00F"/>
</RelativeLayout>
RotatedFrameLayout
public class RotatedFrameLayout extends FrameLayout {
private boolean firstMeasure = true;
public RotatedFrameLayout( Context context ) {
super( context );
init();
}
public RotatedFrameLayout( Context context, AttributeSet attrs ) {
super( context, attrs );
init();
}
public RotatedFrameLayout( Context context, AttributeSet attrs, int defStyle ) {
super( context, attrs, defStyle );
init();
}
private void init() {
setRotation( 90f );
}
#Override
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec ) {
super.onMeasure( heightMeasureSpec, widthMeasureSpec );
}
}
Some extra info
I don't want to use Animation rotation because buttons aren't clickable that way
I don't want to use landscape mode because in landscape on screen navigation buttons took a lot of space on Nexus 7 ( this is the main reason why I am trying to greate that rotated
It seems that only left and right side of the screen are out of bounds
It is quite hard to do and I think it is not worth doing. But if you really want to do this you need:
pass to ViewGroup correct size dimentions (swap width and height).
rotate ViewGroup canvas 90 degrees.
At this point everything should look fine, but touch events not working properly.
intercept all touch events and swap x and y. Then pass fixed events to ViewGroup.
I dont have any code samples and have never seen any ) This way should work, we did scale transformations with fragments where we had to fix touch events coordinates when fragment was scaled.
I havent tested it heavily but this works:
public class RotatedFrameLayout extends FrameLayout {
public RotatedFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public RotatedFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RotatedFrameLayout(Context context) {
super(context);
init();
}
#SuppressLint("NewApi")
private void init() {
setPivotX(0);
setPivotY(0);
setRotation(90f);
}
#SuppressLint("NewApi")
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setTranslationX(getMeasuredHeight());
}
}

Categories

Resources