I have a method that attempts to programatically scroll to a position in a ListView. The method has some conditionals so that its implementation differs slightly based on the Android SDK version the app is running on.
The functionality works fine on 3 android devices that I have tested on. However, I have written a unit test using junit and Roboelectric that checks if the scrolling has made the the item at the target position visible. The test fails. When I debug, I notice that android.os.Build.VERSION.SDK_INT is 0 when running with Roboelectric (i.e., on the desktop vs. device or emulator).
I've tried ignoring the version and just using ListView.smoothScrollToPosition(), but the getFirstVisilePoition() and getLastVisiblePosition() methods continue to return 0, even immediately after I call smoothScrollToPosition(150).
Does anyone know if/how scrolling a listview can be tested using Roboelectric?
Any help would be appreciated - I can't seem to find any information on the topic.
Thanks,
Ana
If you're using robolectric 1.1 or 1.2, here is the source for the AbsListView:
https://github.com/pivotal/robolectric/blob/master/src/main/java/com/xtremelabs/robolectric/shadows/ShadowAbsListView.java
It looks like all the scrolling functionality is it ShadowAdapterView:
https://github.com/pivotal/robolectric/blob/master/src/main/java/com/xtremelabs/robolectric/shadows/ShadowAdapterView.java
It doesn't look like getFirstVisiblePoition() or getLastVisiblePosition() are implemented.
I was able to get the smooth scroll position.
#RunWith(RobolectricTestRunner.class)
public class SmoothScroll {
#Test
public void testSmoothScroll() {
Activity context = new Activity();
ListView view = new ListView(context);
view.smoothScrollToPosition(100);
Assert.assertEquals(100, Robolectric.shadowOf(view).getSmoothScrolledPosition());
}
}
You can get the smooth scrolled position. Based on the height of the elements, you may be able to work out which ones are visible.
Related
I'm new to Jetpack Compose, so I'm struggling to implement a feature which is dynamic colors (and font, size,... but I think they are the same so I'll just focus on color) at run time from backend. I'll let the app the some default colors, and a whole default splash screen just to load the colors setting from the backend. In case the API request failed, it would use the last succeeded requested colors or just the default color.
Tutorials I found round the internet was just about changing the dark/light theme at run time, not changing a specific color in the color pack. In those tutorials, the color is defined in Colors.kt file which is not a composable or class or object, ...
I imagine the color within lightColors or darkColors would be something like this.
return lightColors(
primary = Color(android.graphics.Color.parseColor("#" + dynamicColorMap["One"])),
...
}
And when dynamicColorMap changes in the splashscreen, all screen later will have reference to the new value, but I don't know how to update its variable outside of a composable.
I thought of using DB to store the colors, but getting the data from DB is async, so it cannot be query in the default Colors.kt like var colorOne = DBManager.getColor("One"), I can run the async task in my splash screen before changing to the next screen but then the problem again is how to have a global state that my theme composable wrapper can have access to on every screen?
I just don't know where to start for these case.
Thank you for your time
EDIT:
I currently having the project structured in MVVM. For now, only one activity (MainActivity) is present, and inside that activity, the splash screen component or home screen or login screen,... are being navigated. So is it a good practice to create a viewmodel for the mainactivity screen, that can holds the color state for the theme?
Thanks #Maciej Ciemiega for the suggestion. I ended up structure my code like that.
In my MainActivity.kt I create a viewmodel for it.
val mainActivityViewModel by viewModels<MainActivityViewModel>()
MyTheme(mainActivityViewModel = mainActivityViewModel) {
initNavigationController(navController)
Surface(color = MaterialTheme.colors.background) {
if (mainActivityViewModel.appSettingsState.value.appSettings.colorsMapLight.size != 0
&& mainActivityViewModel.appSettingsState.value.appSettings.colorsMapDark.size != 0) {
navController.navigate(NavigationDestinations.homeScreen)
}
}
}
my initNavigationController function shows the splashscreen first. But it doesn't do anything. The getting app settings configuration is called in MyTheme composable via the mainActivityViewModel, and MyTheme will use the state from the viewmodel to define the theme, and the navController.navigate is based on the state as you guys can see in the if above.
I don't know if this is a good practice or not, or when my app grows it would be a mess or not, but at least it works for me. I tried with font styles too and it works like a charm.
I've run into a bit of an issue related to a whitelist Web Browser my company has been developing / maintaining for one of our product lines. The browser runs on top of Qt 4.8.6, using qtwebkit (Migration to 5.X would be ideal, but the embedded Linux OS we're using is too old to support the newer versions based on our testing, and upgrading to a newer OS is too costly to us / our customers). The primary interface to the browser is a 6x8 touchscreen, mounted inside an aircraft cockpit.
For sites that have things like scrollable/embedded maps (ex. Google Maps), the users of the browser want the ability to drag the entire page when they are selecting something outside of the map, and drag just the map (without the entire page scrolling) when the map is selected (Ala most of the popular mobile browsers).
Thus far, I am able to do one or the other, but not both:
When I hook mouse handlers into a QWebView or QGraphicsWebView, I can turn the cursor into a hand and very easily support dragging of the entire web page. However, that inhibits the page's ability to handle the mouse events for when a user is pulling over a map (i.e. When a user drags over a map, it drags the entire page without moving the map).
When I don't add in the hooks to handle mouse events, things like maps are scrollable by grapping/dragging them, but of course the user loses the ability to drag the entire page.
Right now, the browser uses the later, with scroll bars disabled and a directional-arrow overlay to allow the user to scroll the entire page (as the display size is limited, and scrollbars take up too much space when they are sized large enough for the user to interact with them)...but this is not ideal.
My Question: Is there any easy way to make it so that the page, and elements in a page, can be scrolled seamlessly?
Thanks!
Rob
Seems to me like you need to check if you are over such a map and ignore(pass along) the event in that case. I think you should be able to do something like this:
bool GraphicsWebView::isOverMap(QPoint pos) {
QWebPage* webPage = this->page();
if (webPage) {
QWebFrame* webFrame = webPage->frameAt(pos);
if (webFrame) {
QString selectorQuery = "#map-canvas"; // Based on https://developers.google.com/maps/tutorials/fundamentals/adding-a-google-map
QList<QWebElement> list = webFrame->findAllElements(selectorQuery).toList(); // Find all the maps!
foreach(QWebElement element, list) {
if (element.geometry().contains(pos)) {
return true; // Cursor is over a map
}
}
}
}
return false; // No match
}
Obviously this is a pretty specific function but there is probably a way to come up with a better selector query that will apply to all those kinds of QWebElement.
Assuming you hook mouse events by subclassing QGraphicsWebView and reimplementing void mouseMoveEvent(QGraphicsSceneMouseEvent * event), I suggest you do something like:
void GraphicsWebView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
if (isOverMap(mapFromScene(event->scenePos()).toPoint())) { // We got a map!
event.ignore(); // Clear the accept flag
return; // Return, we're done here
}
handleMoveView(); // Not over any maps, let's scroll the page
}
This part of the doc explains how events are handled with regard to the topmost item. I especially recommend you read the third paragraph.
Hope that helps!
EDIT: Did a bit more research and it looks like something like that could be more generic:
graphicsView.focusItem()->flags().testFlag(QGraphicsItem::ItemIsMovable);
It's at the very least worth investigating as a replacement to isOverMap()
EDIT: Gotcha, here is something you can try then.
Start by subclassing QGraphicsSceneMouseEvent and add a signal called void destroyedWithoutAccept() that's emitted in the destructor if the event has not been accepted.
Then modify mouseMoveEvent to look like this:
void GraphicsWebView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
MyEvent myEvent = new MyEvent(event); // Copy event
event.accept(); // accept original event
connect(myEvent, SIGNAL(destroyedWithoutAccept),
this, SLOT(handleMoveView)); // Callback if unused
QGraphicsWebView::mouseMoveEvent(myEvent); // Pass it to Base class
}
If that works, it might introduce a bit of delay if deleteLater is used to destroy it. But in that case reimplement it as well.
I have a button in one of view controller of tab bar controller. All set up in storyboard. I registered action method like this
- (IBAction)buttonPressed:(id)sender {
NSLog(#"Button pressed");
}
The thing is that once I make left and top constraints (to force it stay in the right upper corner) touch up inside event stops working after I change rotation. So just open app in portrait mode - method is working. Change to landscape and I cannot tap button suddenly.
I've recreated problem in this easy example project.
Many thanks.
Just put the following code in you TabBarViewController class.
- (void)viewDidLayoutSubviews
{
// fix for iOS7 bug in UITabBarController
self.selectedViewController.view.superview.frame = self.view.bounds;
}
Recently I noticed same bug in my application. First I tried Slavco Petkovski method. But this caused me another bug with rotating and getting right bounds and frame, so I kept searching.
I found another solution for this problem, mainly setting autoresizing mask of view controller's view in xib. But since arrows in inspector in my Xcode (version 5.0.1) are inactive and you can't set them, you have to open xib file in text editor find autoresizingMask property for main view and change it like this:
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
EDIT:
Alternatively you can do this in your view controller's code - same result as in changes in xcode:
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
I have this code, which works fine if a cell in the IgGrid control is being edited:
var verticalContainer = $("#BookLabor_scrollContainer");
var topPos = verticalContainer.scrollTop();
$("#BookLabor").igGrid("option", "dataSource", blankLaborDS);
$('#BookLabor').igGrid('dataBind');
verticalContainer.scrollTop(topPos);
However, when I use an IgDialog that I have pop open on a grid cell with a button click event, this is not scrolling back to the row being edited:
var verticalContainer = $("#BookLabor_scrollContainer");
var topPos = verticalContainer.scrollTop();
$("#BookLabor").igGrid("option", "dataSource", blankLaborDS);
$('#BookLabor').igGrid('dataBind');
verticalContainer.scrollTop(topPos);
There is a virtual scroll method for the IgGrid, but the online documentation does not explain in detail how to use it.
Any tricks, tips, hints from all you Infragistics experts out there?
The scroll related API is very basic and what you are using is pretty much comparable:
.igGrid("scrollContainer") is merely a shorthand so you don't have to use #BookLabor_scrollContainer (it's an internal id)
.igGrid("virtualScrollTo", scrollContainerTop); is just like scroll top when you are using virtual scrolling, which you might be (can't tell without more code) so you might want to try that out.
HOWEVER, is there a reason to call dataBind after cell edit? ( I'm having a hard time finding a scenario for that). It is not intended by any means and it creates a lot of overhead with bigger data. If you need to update cell values you should be using the Updating API that does not require re-bind and will not require scroll after as well..see:
http://help.infragistics.com/jQuery/2012.2/ui.iggridupdating#methods
As for the dialog, the Updating again provides a row template that internally uses the dialog and I highly recommend that if row editing is acceptable. Sample:
http://www.infragistics.com/products/jquery/sample/grid/row-edit-template
I need to write a C++ GUI such that user can make a flowchart / pipeline by selecting several blocks from a toolbar and putting them into a window and connecting them in some order which he wants and then program runs the flowchart. (For simplicity just consider each block's task is to print some number. My problem is GUI)
Does anyone ever try a similar thing / any experience?
Is it possible to make such a GUI in WxWidget or any other Graphics/Window-form library?
Is it possible to use VTK to make the GUI?
Do you know of any similar open source work?
I have developed several apps with GUIs that do this sort of thing.
The one I am most pleased with is called VASE: A GUI used to create the layout, set parameters and view results of a process flow simulator.
It is not a trivial task, though once you have done one or two, there are many ideas that you can reuse and it goes quickly.
The two biggest challenges drawing the lines connecting the objects ( as you can see, even in VASE, this problem is not completely solved ) and storing that layout in a format that can be easily recovered and redrawn.
Is there any particular issue you need help with?
If you want a really, really, simple example to get you started I have re-implemented a couple of basic features ( all nice and clean, no copyright restrictions ) - left click to select, drag to move, right click to connect.
Here is the source code repository - http://66.199.140.183/cgi-bin/vase.cgi/home
Here's what it looks like
I have implemented a simplified connector, which I call a pipe. To give you a flavour of how to do this kind of stuff, here is the code to add a pipe when the user right clicks
/**
User has right clicked
If he right clicks on a flower
and there is a different flower selected
then connect the selected flower to the right clicked flower
if he right clicks on empty background
create a new flower
*/
void cVase::MouseRightDown( wxMouseEvent& event )
{
// find flower under click
iterator iter_flower_clicked = find( event.GetPosition() );
// check there was a flower under click
if( iter_flower_clicked != end() ) {
// check that we have a selected flower
if( ! mySelected )
return;
// check that selected flower is different from one clicked
if( mySelected == (*iter_flower_clicked) )
return;
// construct pipe from selected flower to clicked flower
myPipe.push_back(cPipe( mySelected, *iter_flower_clicked ));
} else {
// no flower under click
// make one appear!
cFlower * pflower = Add();
pflower->setLocation( event.GetPosition() );
}
// redraw everything
Refresh();
}
And here is the code to draw a pipe
/**
Draw the pipe
From starting flower's exit port to ending flower's entry port
*/
void cPipe::Paint( wxPaintDC& dc )
{
dc.SetPen( *wxBLUE_PEN );
dc.DrawLine( myStart->getExitPort(), myEnd->getEntryPort() );
}
You can see the rest of the wxWidgets code that ties all this together by browsing the source code repository.
I think using a library such as wxArt2D would be easier than using the standard wxWidgets drawing classes. The wires sample of wxArt2D looks similar to what you are looking for.
Maybe you can have a try with the tiny tool called Flowchart to Code, you can get the flowchart needed,like this. It can be downloaded here:http://www.athtek.com/flowchart-to-code.html#.Ug4z29JPTfI