i have a Barrier in activity_constraint_layout, and want change it's type based some data from network, but setType(int type) is not work.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_constraint_layout)
clContainer = findViewById(R.id.clContainer)
// worked here
val barrier = findViewById<Barrier>(R.id.barrier)
barrier.type = Barrier.START
clContainer.setOnClickListener {
// do not work here
barrier.type = Barrier.END
}
}
The statement barrier.type = Barrier.END executes the following withing the Barrier class:
public void setType(int type) {
mIndicatedType = type;
}
As you can see, it only sets the value of a variable. You also need to request a layout as follows:
clContainer.setOnClickListener {
// do not work here
barrier.type = Barrier.END
barrier.requestLayout()
}
Once you do this, you should see the effect you want.
Related
I'm building an Android app using purely Jetpack Compose. My entire application is wrapped under one scaffold, and has a ViewModel for each "screen" (which are composables) in my app. Because of that, I have some conditional statements in my scaffold to determine the floating action button (FAB) based on the route. However, one of the FABs needs access to a function in a ViewModel, which is only created when I navigate to the route that holds that composable, and I'm at a loss on the best way to give the FAB access to that viewmodel function.
Take the following example (based off my code), and note the FAB for the route "route3".
#AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp()
}
}
#Composable
fun MyApp() {
val navController = rememberNavController()
val backstackEntry = navController.currentBackStackEntryAsState()
val scaffoldState = rememberScaffoldState()
Surface(color = MaterialTheme.colors.background) {
Scaffold(
topBar = { ... },
bottomBar = { ... },
floatingActionButton = {
when (backstackEntry.value?.destination?.route) {
"route2" -> FAB2(navController)
"route3" -> FAB3(navController) // Needs to access function from viewModel3
}
},
scaffoldState = scaffoldState,
) {
MyNavHost(navController, scaffoldState)
}
}
}
#Composable
fun MyNavHost(navController: NavHostController, scaffoldState: ScaffoldState) {
NavHost(
navController = navController,
startDestination = "route1"
) {
composable("route1") { Destination1() }
composable("route2") { Destination2() }
composable("route3") { Destination3() }
}
}
#Composable
fun Destination1() { ...}
#Composable
fun Destination2() { ... }
#Composable
fun Destination3() {
val viewModel3: CustomViewModel = hiltViewModel()
Screen3(viewModel3)
}
}
So my main question is, if the FAB3 variable needs to access a function from viewModel3, how would I go about doing it?
I decided to just switch over to using a scaffold for every screen.
Honestly, this makes managing routes a lot easier, because in the single scaffold scenario, it was getting difficult managing all of the possible routes for things like the TopBar and FAB in large when() blocks.
But if anyone has a solution to the original question that would be appreciated!
Is there a way to implement a Dialog for Location setting like the image below which gets triggered when app requires GPS location and doesn't find. Hitting OK will right away turn on the system GPS. This seems more convenient for users instead of taking them to location and manually turn on.
Is it possible to implement such thing in Flutter?
Expanded View of dialog:
Credits to Rajesh, as answered here. The plugin lets you add this native dialog for a quick location setting.
The implementation is quite simple as this:
import 'package:location/location.dart';
var location = Location();
Future _checkGps() async {
if(!await location.serviceEnabled()){
location.requestService();
}
}
#override
void initState() {
super.initState();
_checkGps();
}
In Kotlin, try this code:
class HomeActivity : AppCompatActivity() {
private val requestLocation = 199
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableLoc()
}
private fun enableLoc() {
val mLocationRequest = LocationRequest.create()
mLocationRequest.interval = 10000
mLocationRequest.fastestInterval = 5000
// mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest)
val client = LocationServices.getSettingsClient(this)
val task =
client.checkLocationSettings(builder.build())
task.addOnSuccessListener(this) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
}
task.addOnFailureListener(this) { e ->
if (e is ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
e.startResolutionForResult(
this,
requestLocation
)
} catch (sendEx: SendIntentException) {
// Ignore the error.
}
}
}
}
}
I need to recollect some data calling to a method is connecting to a webservice.
problem: Imagine I need to update the content text of a label control according to this remote gathered information. Until all this data is recollected I'm not going to be able to show the label.
desired: I'd like to first show the label with a default text, and as I'm receiving this information I want to update the label content (please, don't take this description as a sucked code, I'm trying to brief my real situation).
I'd like to create an observable sequence of these methods. Nevertheless, these method have not the same signature. For example:
int GetInt() {
return service.GetInt();
}
string GetString() {
return service.GetString();
}
string GetString2 {
return service.GetString2();
}
These methods are not async.
Is it possible to create an observable sequence of these methods?
How could I create it?
Nevertheless, which's the best alternative to achieve my goal?
Creating custom observable sequences can be achieved with the Observable.Create. An example using your requirements is shown below:
private int GetInt()
{
Thread.Sleep(1000);
return 1;
}
private string GetString()
{
Thread.Sleep(1000);
return "Hello";
}
private string GetString2()
{
Thread.Sleep(2000);
return "World!";
}
private IObservable<string> RetrieveContent()
{
return Observable.Create<string>(
observer =>
{
observer.OnNext("Default Text");
int value = GetInt();
observer.OnNext($"Got value {value}. Getting string...");
string string1 = GetString();
observer.OnNext($"Got string {string1}. Getting second string...");
string string2 = GetString2();
observer.OnNext(string2);
observer.OnCompleted();
return Disposable.Empty;
}
);
}
Note how I have emulated network delay by introducing a Thread.Sleep call into each of the GetXXX methods. In order to ensure your UI doesn't hang when subscribing to this observable, you should subscribe as follows:
IDisposable subscription = RetrieveContent()
.SubscribeOn(TaskPoolScheduler.Default)
.ObserveOn(DispatcherScheduler.Current)
.Subscribe(text => Label = text);
This code uses the .SubscribeOn(TaskPoolScheduler.Default) extension method to use a TaskPool thread to start the observable sequence and will be blocked by the calls the Thread.Sleep but, as this is not the UI thread, your UI will remain responsive. Then, to ensure we update the UI on the UI thread, we use the ".ObserveOn(DispatcherScheduler.Current)" to invoke the updates onto the UI thread before setting the (data bound) Label property.
Hope this is what you were looking for, but leave a comment if not and I'll try to help further.
I would look at creating a wrapper class for your service to expose the values as separate observables.
So, start with a service interface:
public interface IService
{
int GetInt();
string GetString();
string GetString2();
}
...and then you write ServiceWrapper:
public class ServiceWrapper : IService
{
private IService service;
private Subject<int> subjectGetInt = new Subject<int>();
private Subject<string> subjectGetString = new Subject<string>();
private Subject<string> subjectGetString2 = new Subject<string>();
public ServiceWrapper(IService service)
{
this.service = service;
}
public int GetInt()
{
var value = service.GetInt();
this.subjectGetInt.OnNext(value);
return value;
}
public IObservable<int> GetInts()
{
return this.subjectGetInt.AsObservable();
}
public string GetString()
{
var value = service.GetString();
this.subjectGetString.OnNext(value);
return value;
}
public IObservable<string> GetStrings()
{
return this.subjectGetString.AsObservable();
}
public string GetString2()
{
var value = service.GetString2();
this.subjectGetString2.OnNext(value);
return value;
}
public IObservable<string> GetString2s()
{
return this.subjectGetString2.AsObservable();
}
}
Now, assuming that you current service is called Service, you would write this code to set things up:
IService service = new Service();
ServiceWrapper wrapped = new ServiceWrapper(service); // Still an `IService`
var subscription =
Observable
.Merge(
wrapped.GetInts().Select(x => x.ToString()),
wrapped.GetStrings(),
wrapped.GetString2s())
.Subscribe(x => label.Text = x);
IService wrappedService = wrapped;
Now pass wrappedService instead of service to your code. It's still calling the underlying service code so no need for a re-write, yet you still are getting the observables that you want.
This is effectively a gang of four decorator pattern.
I have an abstract class in my mind and I can't implement its several features in swift, so I use C++ to deliver my thoughts:
template <class T>
class Swapping {
public:
void swap() { _foregroundIndex = backgroundIndex() }
virtual void cleanup() = 0;
T* foreground() { return _buffer[foregroundIndex()]; }
T* background() { return _buffer[backgroundIndex()]; }
void setForeground(T* foreground) { _buffer[foregroundIndex()] = foreground; }
void setBackground(T* background) { _buffer[backgroundIndex()] = background; }
private:
short foregroundIndex() { return _foregroundIndex; }
short backgroundIndex() { return _foregroundIndex ^ 1; }
short _foregroundIndex = 0;
T* _buffer[2] = {NULL, NULL};
}
The main contradiction is that
The pure virtual method cleanup() requires all subclasses to implement it explicitly (can achieve in swift with protocol)
The instance variable _foregroundIndex has an initial value (cannot achieve using protocol)
The instance variable _foregroundIndex is restricted to be private ( cannot achieve using protocol)
On the other hand, if I use a class instead of protocol, then I can't guarantee cleanup() method is overriden.
One may suggest that put the virtual method in a protocol and the instance variable in a class. That may work but is not a obsession-satisfying one.
P.S. Objective-C is not Swift. Any objc_runtime related workaround is not preferred.
There’s an obvious solution, which I have seen often but will certainly not satisfy you is:
func cleanup() {
fatalError("You must override cleanup()")
}
Then you could try using extensions to extend the protocol with default implementations, but extensions don’t allow stored properties and so you would most likely need some external objects or other magic you certainly also dislike.
As I noted above in the comments, you might need to rethink your design. I don’t know what you really intend to do, but maybe something like this would work out for you:
class Swapper<T> {
private var foregroundIndex = 0
private var backgroundIndex: Int {
return foregroundIndex ^ 1
}
private var buffer: [T?] = [nil, nil]
private let cleanupHandler: () -> ()
init(cleanupHandler: #escaping () -> ()) {
self.cleanupHandler = cleanupHandler
}
func cleanup() {
cleanupHandler()
}
var foreground: T? {
get {
return buffer[foregroundIndex]
}
set {
buffer[foregroundIndex] = newValue
}
}
var background: T? {
get {
return buffer[backgroundIndex]
}
set {
buffer[backgroundIndex] = newValue
}
}
func swap() {
foregroundIndex = backgroundIndex
}
}
This makes more sense to me as this allows any types to be swapped with any clean up handler, without having to subclass the class every time.
In JavaFX, how do you model the following:
I show a List of Customers in a Scene. On the left side there is a table on the right side (contentPane) the currently select customer's details are shown.
(Relevant part of) Main-Controller:
#jfxf.FXML
protected def newButtonPressed(): Unit =
{
contentPane.getChildren.clear
contentPane.getChildren.add(FXMLLoader.load(GUILoader.load("customers/form.fxml")))
}
There is a Button to add a new Customer. Upon clicking this button instead of opening a Popup, I replace the "details"-part of the scene and add a form there.
Now for this form (designed - like the rest of the GUI - in the SceneBuilder and saved as .fxml) I use another controller.
class Form extends Main with jfxf.Initializable
{
#jfxf.FXML
private var foreNameTextField: jfxsc.TextField = _
#jfxf.FXML
private var lastNameTextField: jfxsc.TextField = _
#jfxf.FXML
private var ageTextField: jfxsc.TextField = _
override def initialize(url: URL, resourceBundle: ResourceBundle): Unit =
{
}
#jfxf.FXML
protected def ok(): Unit =
{
// TODO validation
val newPerson = new Person(-1, foreNameTextField.getText, lastNameTextField.getText, ageTextField.getText.toInt)
// Save to DB
// Close whole form
}
}
When I'm done with filling in a new customer's detail I click on another button (that calls ok()) and save it to a database.
What I want to do now is close the form and replace it with the detail-form.
Something like calling a protected method in the main-controller like:
protected def clearDetails(): Unit =
{
contentPane.getChildren.clear
contentPane.getChildren.add(savedOldDetails)
}
won't work of course. (Will throw a runtime-exception because there is no contentpane in the sub/form-controller (even if I make it protected)
In Qt (C++) I'd use signals/slots and connect them accordingly.
Seems like in JavaFX there is nothing the like. How am I supposed to share such information?
Do I need to create a "super-controller" for the contentPane?
(I don't know Scala, so I'll write this in Java, hope that is ok).
You can define an observable property in the Form controller, and observe it when you load the form from the main controller:
public class Form implements Initializable {
private final ObjectProperty<Person> person = new SimpleObjectProperty<>(null);
public ObjectProperty<Person> personProperty() {
return person ;
}
public final Person getPerson() {
return personProperty().get();
}
public final void setPerson(Person person) {
personProperty().set(person);
}
// ... code you had before...
#FXML
protected void ok() {
Person person = new Person(-1, foreNameTextField.getText(), lastNameTextField.getText(), ageTextField.getText());
// save to DB...
personProperty().set(person);
}
}
Now in your main controller, load the form as follows:
#FXML
protected void newButtonPressed() {
contentPane.getChildren().clear();
FXMLLoader loader = new FXMLLoader(getClass().getResource("customers/form.fxml"));
Parent form = loader.load();
Form formController = loader.getController();
formController.personProperty().addListener((obs, oldPerson, newPerson) {
if (newPerson != null) {
// clear form, etc, e.g.
clearDetails();
}
});
contentPane.getChildren().add(form);
}