Android visibility not working for MotionLayout - android

I'm trying to make visibility changes for a view under MotionLayout using this answer https://stackoverflow.com/a/62658424/5412554
but for me, it's not working under observe. For eg:
viewModel.messageLinkedList.observe(viewLifecycleOwner) {
binding.motionLayout.getConstraintSet(R.id.start).getConstraint(binding.deleteAllText.id).propertySet.mVisibilityMode = 1; // 1 - ignore or 0 - normal
binding.deleteAllText.visibility = View.GONE
}
If I use simply in onCreateView of fragment it works.
For eg:
binding.motionLayout.getConstraintSet(R.id.start).getConstraint(binding.deleteAllText.id).propertySet.mVisibilityMode = 1; // 1 - ignore or 0 - normal
binding.deleteAllText.visibility = View.GONE
Please help me with the correct solution.

I don't know it works with data-binding but I found a Solution for Kotlin, maybe you can something figure out:
motion_layout_id.getConstraintSet(R.id.start)?.let {
it.setVisibility(R.id.deleteAllText, View.GONE)
motion_layout_main.requestLayout() // this must be done to apply the visibility change
}

Related

How to translate an included layout in an activity?

I want to translate my included layout on Y-axis in my activity. I could do it before if was using data binding but now since the root view my included layout is i cannot get it like this.
ConstraintLayout layout = (ConstraintLayout) mbinding.includedlayout;
Ive tried this:
LayoutBottomSheetBinding bottomSheet =
LayoutBottomSheetBinding.inflate(getLayoutInflater());
bottomSheet.setViewModel(mActivityViewModel);
bottomSheet.constraintLayoutBottomSheet.setTranslationY(-300);
. It does not give any error but nothing happens on my UI and i just see the included layout and it does not move up or down. I guess this makes is referring to another instance of that xml (not sure).
LayoutBottomSheetBinding bottomSheet =
LayoutBottomSheetBinding.inflate(getLayoutInflater());
bottomSheet.setViewModel(mActivityViewModel);
bottomSheet.constraintLayoutBottomSheet.setTranslationY(-300);
ConstraintLayout layout = (ConstraintLayout) includedRootView
mBinding.buttonBottomSheet.setOnClickListener(v -> {
if (position == 0) {
bottomSheet.constraintLayoutBottomSheet.animate().translationY(0);
position = 1;
} else {
bottomSheet.constraintLayoutBottomSheet.animate().translationY(-300);
position = 0;
}
});
Can anyone help me or tell me what am i doing wrong ? I just want to be able to translate that included layout like im doing above.
You have to start the animation:
bottomSheet.constraintLayoutBottomSheet.animate().translationY(0).start();

View added programatically not changing visibility after a long time not used

I have a problem I have not yet been able to understand, nor solve.
On my android project, I have a BaseActivity. There, among other functions, I decided to add a function to show or hide a loading view when necessary. It works as intended, but sometimes an error happens.
I will try to raise some important info about my project I think can be useful. My app is integrated with an external login app. I call it when the services I call need to refresh it's token. When the user logs in on the app, it calls a listener and give me back control on mine.
The problem is the next one:
I come to an activity that needs to call a service and I have the token all right, but then I lock the phone. After a long period of time, I unlock the phone and, from the same activity, I call again the service. My activity shows de loader as intended and, as my token is expired, I call the login app from it's SDK.
When I come back to my app, and I call the service I wanted successfully, the app tries to hide the loader. This is where the fail comes, as I can't change the visibility to GONE. I looked for it on the view hierarchy and find it, but with visibility = VISIBLE.
Here is the piece of code from the loader, hope someone can find where I'm making the mistake!
abstract class BaseActivity : DaggerAppCompatActivity(){
// These are the IDS of the Views I'm adding to the activity, so I can track them and change their visibility
var imgLoadingID = -1
var rvLoadingID = -1
fun showLoading() {
// If the views are added I show them
if (imgLoadingID > 0 && rvLoadingID > 0) {
val imageView = findViewById<ImageView>(imgLoadingID)
val relativeLayout = findViewById<RelativeLayout>(rvLoadingID)
relativeLayout.visibility = View.VISIBLE
imageView.visibility = VISIBLE
imageView.isClickable = false
imageView.isFocusable = false
} else {
// else I create them and show them
val imgLoading = ImageView(this)
imgLoading.id = View.generateViewId()
imgLoadingID = imgLoading.id
val maxpx = CustomUtils.ViewUtils.converIntToDps(65, this)
Glide.with(this).asGif().load(R.mipmap.loading).into(imgLoading)
val relativeLayout = RelativeLayout(this)
relativeLayout.id = View.generateViewId()
rvLoadingID = relativeLayout.id
var params = RelativeLayout.LayoutParams(maxpx, WRAP_CONTENT)
params.addRule(RelativeLayout.CENTER_IN_PARENT)
relativeLayout.addView(imgLoading, params)
relativeLayout.background = getDrawable(R.color.pure_white_97)
relativeLayout.isClickable = true
relativeLayout.isFocusable = true
findViewById<ViewGroup>(android.R.id.content).addView(relativeLayout, RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT))
imgLoading.visibility = VISIBLE
}
// I lock the back button so people don't cancel my requests
esBackPressedBlocked = true
}
// Here I find the views and change their visibility.
fun hideLoading(){
if(imgLoadingID > 0 && rvLoadingID > 0) {
val imageView = findViewById<ImageView>(imgLoadingID)
val relativeLayout = findViewById<RelativeLayout>(rvLoadingID)
relativeLayout.visibility = View.GONE
imageView.visibility = View.GONE
}
esBackPressedBlocked = false
}
}
I deleted some logs I added to the whole function, but when it fails, it enters on the hideLoading() function, even on the relativeLayout.visibility = View.GONE part.
The function used to be with the Views as an whole object instead of their ids, but I found it more reliable this way, and saving the views instead of their Id's had the same problem.
My main concern is how Android manages my application while the phone is locked for this period of time (the fails happened after 8-10 hours of inactivity). I think something there can be creating this issue. I thought also about the external Login app, since it's sdk is launching their app's intent and calling me from a listener when coming back, but, since my code is being executed, I think Android it's managing my views on an strange way. Or maybe I try to hide the loading view before I'm on the resumed activity... I don't really know.
BTW, I know there are easier solutions on showing a loader, but I wanted to create it the cleanest way. If you have any cleaner approach I'm open to any solution.
If there is anything unclear let me know in the comments, and I hope my English was clear enough to express myself, it's a tricky problem that I can't understand, so it's difficult for me to explain it.
Thanks!!

How to set conditional visibility in android

I want to set visibility of a imageview on the basis of a condition. how would i do it ??
here is my code :
if (web.canGoBack() != true) {
bc.setVisibility(View.INVISIBLE);
}else {
bc.setVisibility(View.VISIBLE);
}
here bc is the imageview over a webview which is in framelayout
What you are trying to do is fine.
But, if want it in 1 line then.
bc.setVisibility(web.canGoBack()? View.VISIBLE : View.INVISIBLE);
Try bc.setVisibility(View.GONE);
But the real issue may be your response from web.canGoBack(). Please do check that condition is working fine.

Robolectric-2.3 testing animation

I'm writing test to my project with Robolectric-2.3.
I'd like to test my UI properties such as Views visibility. The actions of showing/hiding views are wrapped into Animations. How to test it ?
I tried to use ShadowSystemClock.sleep() method to wait until animation ends but it doesn't seem to work as I expected.
#Test
public void testHideSearch() throws Exception {
mListFragment.hideSearch(); //<--- animation launched here
sleep(1000);
View searchEditText = mListFragment.getView().findViewById(R.id.filterEditText);
assertFalse(searchEditText.getVisibility() == View.VISIBLE);
}
What is the correct approach to the issue ?
Try using this instead of sleep:
Robolectric.getUiThreadScheduler.advanceBy(1000);
If you use Animator's your approach should work, but if you use Animations, you'll need to use ShadowAnimation instead. Assuming the actual visibility of your view is changed in onAnimationEnd(), something like the following should work:
ShadowAnimation animation = Robolectric.shadowOf(searchEditText.getAnimation());
animation.invokeEnd();

Android Listview code for enabling Fast Scroll in android framework source code

In android setFastScrollEnabled(true); is used for making ListView fast scroll.
This fast scroll does not work when there are less items in ListView. I read it somewhere that fast scroll in android works only when listview total height is 4 times or more than listview visible height. I have spent hours trying to find it in framework source code, but I am not able to find it.
Can someone point me to place in android framework source code where this condition to disable fast scroll when there are less items in ListView.
Yes ofcourse, here is the link:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/1.5_r4/android/widget/FastScroller.java
This is a condidion between lines 224-227. And for setting how many pages it will be needed to show fast scroll, there is a constant:
private static int MIN_PAGES = 4;
And about disabling it... It's a private field so there is no simply way to do it. You can try use reflections or create custom FastScroller based on original.
But i think the simpliest way is to check like in this condidion in Android code:
//pseudocode
int numberOfPages = listView.itemsCount / listView.visibleItemsCount;
if(numberOfPages > yourValue)
listView.setFastScrollEnabled(true);
else
listView.setFastScrollEnabled(false);
But it may only work if yourValue will be greater than 4. If you want to do it for less values then you need to use reflection or create custom class.
EDIT:
For newest version there is the link:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/widget/FastScroller.java/
And lines are 444-447 :)
And for reflections I would try something like this:
try {
Field scrollerField = AbsListView.class.getDeclaredField("mFastScroller"); //java.lang.reflect.Field
scrollerField.setAccessible(true);
FastScroller instance = scrollerField.get(listViewInstance);
Field minPagesField = instance.getClass().getDeclaredField("MIN_PAGES");
minPagesField.setAccessible(true);
minPagesField.set(instance, yourValue);
} catch (Exception e) {
Log.d("Error", "Could not get fast scroller");
}
It's not tested so i don't know if it really works.
You can try setting the attribute
android:fastScrollAlwaysVisible="true"
in your listview xml
Trying to adapt the answer from MichaƂ Z., I finally ended up doing this :
listView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
val numberOfPages: Int = listView.count / listView.visibleItemsCount
listView.isFastScrollAlwaysVisible = numberOfPages > THRESHOLD
}
It works just fine for me

Categories

Resources