Is there a way to customize the threshold for ViewPager scrolling? - android

I am not able to find a way to change the touch threshold for scrolling pages in ViewPager:
http://developer.android.com/reference/android/support/v4/view/ViewPager.html
Looking at the source code, ViewPager has a method called determineTargetPage that checks to see if the move touch gesture distance > threshold range, but looks like there's no way to modify this range.
Any suggestions on how I can control this threshold (if at all possible)?

Going out on a bit of a limb here; I have no doubt that you may have to tweak this concept and/or code.
I will recommend what I did in the comments above; to extend ViewPager and override its public constructors, and call a custom method which is a clone of initViewPager() (seen in the source you provided). However, as you noted, mFlingDistance, mMinimumVelocity, and mMaximumVelocity are private fields, so they can't be accessed by a subclass.
(Note: You could also change these methods after the constructors are called, if you wanted to.)
Here's where it gets a bit tricky. In Android, we can use the Java Reflection API to make those fields accessible.
It should work something like this:
Class clss = getClass.getSuperClass();
Field flingField = clss.getDeclaredField("mFlingDistance"); // Of course create other variables for the other two fields
flingField.setAccessible(true);
flingField.setInt(this, <whatever int value you want>); // "this" must be the reference to the subclass object
Then, repeat this for the other two variables with whatever values you want. You may want to look at how these are calculated in the source.
Unfortunately, as much as I would like to recommend using Reflection to override the private method determineTargetPage(), I don't believe it's possible to do this--even with the expansive Reflection API.

Related

How to trigger recomposition when only a property of an object changes Jetpack-Android

Imagine the following object
data class CourseState(
val key:Int=0,
val name:String="",
val courses:Courses=Courses())
Implementing the following pattern
private val _courseState = mutableStateOf(CourseState())
val courseState: State<CourseState> = _courseState
I can trigger recomposition of my UI by calling:
_courseState.value = CourseState()
but not by calling:
_courseState.value.courses.addCourse(Course("some course))
this is a bit frustrating because even though the object has clearly changed I am forced to create a whole new instance of the parent object in order to elicit a small change in it.
Now, I know than behind the scenes Compose is using the .equals() method in order to acertain if it should recompose the layout so I ve had a few ideas on how to achieve the desired behaviour.
overwrite the equals method: it would imply a bit of boilerplate code and it would have to be done for the entire set of nested classes that make up my object. this might work but seems dangerous and cumbersome.
use a clone method or a constructor that accepts an instance of its own class as a parameter to create an identical copy of my object that would nevertheless represent a new instance that I can modify and then pass as the mutable state value. sounds easier than the previous optoin but elegance is something different
dive deep into the State and MutableState classes and find out if there is a way to make them behave as I want. I am relying on some of you to have done this before so I dont have to XD
Let me know what you think or if there is some other ovbious solution that has just eluded me so far
There are two options I would consider:
As you mention, create new instances of your objects for every change. With data classes and copy, it's quite easy, it will add some overhead though.
Make all the data that you need to change observable. If you only want to observe them from compose, make it State, otherwise you can use Flow or LiveData. I suppose that your Courses class contains some List to which
you are adding items. Make it a
mutableStateListOf(),
whenever you add something there, composables that use it should
recompose automatically.

Where to put helper methods?

I have a method that darkens a given hex color and percent. Currently, the only place I use this method is within one of my Activity classes (I may or may not end up using it in other classes later on).
public static int darkenColor(int color, int percent) { ... }
However, where should I put this method? Should I create a new class called Helpers that contains all of these methods that I may use only once throughout the entire app?
This is just a matter of choice. You can have Set of utility classes and have these helper methods to be in those classes. But, This method is for not used in one of your activity, and If you do not see that it will get reused in the near future in some other point, Put it as a private method inside your Activity. I say this because you do not want to over complicate the code and also By this way another developer can easily follow the flow of execution.
But after sometimes if you feel, that this code is getting reused, put that into a logically meaningful Utility class. When the code base is huge, you do not have any choice to follow a solid standardization of there to put your code, That is why there are things like Layered architectures etc.

why Google calls variables with the prefix "m"?

why Google calls variables with the prefix "m" for example:
private int mSectionResourceId;
private int mTextResourceId;
I see it in all examples. But i not understand why they do it?
And now i have some example where it practic very good. If a called variabels without prefix i need write
public SimpleSectionedRecyclerViewAdapter(Context context, int sectionResourceId, int textResourceId,
RecyclerView.Adapter baseAdapter) {
this.sectionResourceId = sectionResourceId;
this.textResourceId = textResourceId;
but if i use prefix i can write
public SimpleSectionedRecyclerViewAdapter(Context context, int sectionResourceId, int textResourceId,
RecyclerView.Adapter baseAdapter) {
mSectionResourceId = sectionResourceId;
mTextResourceId = textResourceId;
I think it more readable. Who can explain to me the pros and cons of a prefix?
The variables starting with m are telling you they are variables in the scope of your class. Member of the class.
Link to Android Code Style Guide
The m just stands for 'Member'. It is simply declared that your Variable is a Class-Member.
It is more readable Code, because you know where Class Members got declared, so you can find it pretty fast. You don't need to write this, even if you don't prefix your Variables with an m.
In your Example, this only makes it more readable when there is no prefix-m. Another developer knows that it is a instance variable (member variable) and so declared on top or bottom of the class.
It is a prefix for class member variables. It's just a naming convention.
Mostly sure, taken from Hungarian Notation where similar prefix: m_ stands for exactly the same).
Referring to pros & cons:
Pros:
it allows to type fewer chars during programming,
programmers that are used to use Hungarian Notation may found it easier to follow the code.
Cons:
as the code changes very often, it is easy to forget about changing prefixes every time, when variable changes it's purpose (especially during prototyping),
it makes the code starts to smell bad,
Generally, it is some kind of reinventing the wheel. Java has this keyword that should be more than enough for accessing proper variable. If it's not, the code requires refactoring, maybe because of naming glitches or using too wide variable scopes.
Personally, I do not recommend to use Hungarian Notation (even the part of Android Code Style). We have great IDEs that increases the readability of the code.
There is an exception. The code, where Hungarian Notation (or more general, specific code style) was already been used. It is a matter of consistency.
The m is just a member variable. A class member if you will. Useable with constructors like WebView M WebView then later on you would use something like mWebView.loadurl("example.com"); it's just a placeholder for the variable you created. You don't have to add the member class variable as an m but it's more organized if you do

Robolectric Custom Shadow Object

OOTB, Robolectric does not support Locales that well. Therefore, if your app is dependent on locales (which a lot of apps are if they are i18n'nd properly) this can be a royal pain. Long story short, I created my own ShadowFooGeocoder and ShadowFooAddress that allow me to simulate the locale I want. They're basically re-implementations of the existing shadows.
However, when I bind my class as such: bindShadowClass(ShadowFooGeocoder.class), this works great. At runtime, the correct shadow is returned. The problem is that I want to set up the simulations on this object and I'm not sure how. shadowOf(instance) where instance is an injected GeoCoder returns ShadowGeoCoder. I've tried working directly with the ShadowWrangler, but that also returns a ShadowGeocoder.
How can I get at my shadowed class that I've bound through the bindShadowClass(...) call so I can set my expectations (simulations)?
Note: This is a repost of the same question on the Robolectric group here. I posted here because my success rate of getting anyone to answer questions on the group is fairly low. I'm hoping for a better result here.
What I've basically done here is extend ShadowGeocoder like this:
#SuppressWarnings({"UnusedDeclaration"})
#Implements(Geocoder.class)
public class ShadowFooBarGeocoder extends ShadowGeocoder {
// implementation stuff
}
Then I would bind it using the bindShadowClasss(...) and when I retreive the shadow via the static shadowOf(...) call I get back a "ShadowGeocoder" which is an instance of ShadowFooBarGeocoder. I then cast it to that type and perform whatever work I need to.

Android: How to best pass data to a view?

I have a view that displays all the levels of my game. These levels are read by the activity and then passed into the view. I could read them from the view, but it's not really its responsibility, and I'm a fan of separation of concerns.
Right now, I'm calling a setter for this:
((GameView) findViewById(R.id.game)).setLevels(loadLevels());
However, I don't like the fact that the view will be dysfunctional if I forget to call the setter. Is there a better way to pass the levels in?
It is also a bit a matter of preference. Theoretically it's perfectly fine to pass the levels as you're doing. Alternatively, if you need more than just set the levels, but provide further functionalities (i.e. also saving of levels) I normally use a separate class responsible for handling such things (i.e. a Repository, some "Manager" class etc...). This class is then passed into the View on the constructor preferably s.t. one is forced to provide it. Of course, in order to separate things, I use interfaces rather than specific implementations s.t. it may then look as follows:
public class MyView {
public MyView(ILevelLoader levelLoader){
this.levelLoader = levelLoader;
}
...
}
Often, this may not work, because the view is something instantiated by the framework directly rather than by the application. In such a situation you're forced to do it through an appropriate setter. It is some sort of MVC/MVP pattern.
Just for your interest, you might also want to take a look at IoC containers and dependency injection. Guice provided by Google is a nice framework I've already used on Android.
I hope I didn't miss the point, but here goes:
Generally you have either a function setting something (like the text for a textview), or an attribute you set in the xml.
Take a look over at this answer I got on a question: How to layout a 'grid' of images in the center of the screen
There are some things the custom view needs, but lets take an example: 'numColumns'.
you can set it using setNumColumns (that would be the equivalent of your loadLevels() ? )
you can ignore it, it'll revert to default.
you can set it as an attribute lik so: app:numColumns="3"
You can try to use the attribute or the default in the class to accomplish this.
Make your view an abstract class with an abstract method getLevels()? This way, when you instantiate the class if you forget to pass the levels in your code won't compile.
Whether or not this is better is a matter of taste I guess :)

Categories

Resources