Using Qt Designer, I created an Item class inheriting from QWidget, and added a few widgtes.
Then, again using Qt Designer, I created a MainWindow from QMainWindow, and added a QListWidget object called list, and a QPushButton called pushButton.
On MainWindow::MainWindow(QWidget *parent), I added to the default code:
ui->list->setSizeAdjustPolicy(QListWidget::AdjustToContents);
On void MainWindow::on_pushButton_clicked(), I wrote:
Item *my_item = new Item(this);
QListWidgetItem * item = new ListWidgetItem();
item->setSizeHint(QSize(0, 400));
ui->list->addItem(item);
ui->list->setItemWidget(item, my_item );
Testing on the Linux Ubuntu running on my notebook, it all goes well, but when I run on my Android Moto G4 cell phone, the Item objects inserted in list are never displayed correctly. Using 400 in setSizeHint makes the widgets to be displayed, but cut at the bottom. Using, say, 100, makes the widgets to be squeezed, impossible to read.
Does anyone have any idea on how to make it work?
Thanks!!
Related
I have a Qt app containing a Qt3DWindow as well as multiple QWidgets. To use both, the Qt3DWindow is embedded via QMainWindow::createWindowContainer() which works fine both on Windows and Android. This is not the case for an QObjectPicker attached to a QEntity, the QObjectPicker::clicked event is only rised on Windows, not on Android. However, if i remove the Qt3DWindow from the QMainWindow and use it 'standalone' again, QObjectPicker works as expected on both platforms.
I've tested this usecase with different Qt versions (5.10, 5.12, 5.13 beta) and different tool chains (NDK R14 with GCC, NDK R19 with Clang) without success. In some rare cases I get a QObjectPicker::clicked() event but from a touch event fare away from the screen position of the object.
To reproduce the problem, it's best to extend to "Qt 3D: Simple C++ Example".
Add the following includes to main.cpp:
#include <Qt3DRender/QObjectPicker>
#include <Qt3DRender/QPickEvent>
#include <QObject>
#include <QtWidgets/QApplication>
#include <QGuiApplication>
#include <QtWidgets/QMainWindow>
Add the following code at the end of main.cpp/createScene() right before the return statement:
Qt3DRender::QObjectPicker* picker = new Qt3DRender::QObjectPicker();
QObject::connect(picker, &Qt3DRender::QObjectPicker::clicked, material, [material](Qt3DRender::QPickEvent *pickEvent){
qDebug() << "Sphere clicked";
static_cast<Qt3DExtras::QPhongMaterial*>(material)->setAmbient(QColor(rand()%255,rand()%255,rand()%255));
});
sphereEntity->addComponent(picker);
To compile and deploy for Android, create a AndroidManifest.xml and remove the "density" flag from "android:configChanges".
The running app should display the torus and the moving sphere and when touching the sphere the color of both changes randomly.
Next replace the QGuiApplication app(argc, argv); with QApplication app(argc, argv); in main.cpp/main() and append the following code right before the return statement:
QMainWindow* mainWindow = new QMainWindow();
mainWindow->resize(800, 600);
auto centralwidget = new QWidget(mainWindow);
mainWindow->setCentralWidget(centralwidget);
auto container = QMainWindow::createWindowContainer(&view,mainWindow->centralWidget());
mainWindow->show();
container->resize(mainWindow->centralWidget()->size());
Now the Android app shows the same scene inside a widget, but touching the sphere does not change the color. (On Windows it works in contrast)
Comment out the last three lines makes the example working again:
//auto container = QMainWindow::createWindowContainer(&view,mainWindow->centralWidget());
//mainWindow->show();
//container->resize(mainWindow->centralWidget()->size());
Any ideas whether this is a misconfiguration or a bug?
Thanks to the hint of user3405291 I finally got it working on Android by attaching an event filter to the container widget returned by QMainWindow::createWindowContainer, filtering out QEvent::MouseButtonRelease, call QScreenRayCaster::trigger with the event position as argument and receive the picked objects via QScreenRayCaster::hitsChanged.
On Windows, this procedure also works, but only if the event filter is attached to the Qt3DWindow itself, not to the container widget.
My assumption is, on Windows mouse events are forwarded from the container widget to the Qt3DWindow and on Android they are consumed by the container widget instead. As QObjectPicker seems to listen (only) on events on the Qt3DWindow it does not work properly on Android and there is no option to manually forward events to it.
But this is only a superficial impression and I would be happy about any further clarification.
Object picker works only with mouse click. If you need touch gestures, you need to use QScreenRayCaster as explained here
I took the source I found here:
https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs
And created a custom renderer in a Xamarin Forms Android project. I got the project to build and the menu to open / close as expected as well as display the starting detail page.
The detail page is a "NavigaionPage" in Xamarin.Forms which is actually just a ViewGroup with a bunch of code to make it work with Push / Pop functions.
When I push a new Page, one that has a custom renderer and native RelativeLayout as a subview, the Page appears blank white until I rotate orientation.
After some research in the code, I realized both OnMeasure and OnLayout was not being called in the Page which was being pushed to the NavigationPage / detail page (with the pushed page's size stuck at 0x0 until orientation change).
I created another custom renderer but this time for the NavigationPage which looks like this:
public class MasterDetailContentNavigationPageRenderer : NavigationPageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e)
{
base.OnElementChanged(e);
if(e.OldElement != null)
{
e.OldElement.Pushed -= handleOnPushed;
}
if(e.NewElement != null)
{
e.NewElement.Pushed += handleOnPushed;
}
}
private void handleOnPushed(object sender, EventArgs e)
{
var w = MeasureSpec.MakeMeasureSpec(MeasuredWidth, MeasureSpecMode.Exactly);
var h = MeasureSpec.MakeMeasureSpec(MeasuredHeight, MeasureSpecMode.Exactly);
Measure(w, h);
Layout(Left, Top, Right, Bottom);
}
}
This custom renderer for the detail page / NavigaionPage worked for 2 out of 3 of my pushed Pages.
The main / most important page did not fully add all of the UI elements.
The Page that was pushed and missing UI has SOME of the UI. The following is a list of how the page is displayed:
--- SongViewerLayout : RelativeLayout
------ RelativeLayout
--------- ViewerTopBar (draws all buttons except one)
--------- DocumentView (blank white spot between top bar and pagination)
--------- ViewerPagination (draws background color but not page buttons)
If I change orientations the missing button appears in the top bar, the page numbers show up and the document view sort of draws but it's off.
If I go back to using Xamarin.Forms provided MasterDetailPage the UI just loads as expected.
I have studied the code in the Xamarin.Forms repo but none of it really applies to the inner workings of the elements that are added. In other words, the detail page (which in my case is a NavigationPage) gets added on SetElement(...) and some handlers are assigned ... but nothing I could tell that looks for Pages being pushed and then responding. I would assume / expect the NavigationPage just to work as expected now that it's a subview of the MasterDetailPage / DrawerLayout.
Note: the views that seems to have the most issues are added programmatically and given "LayoutParamaters". The views found in the AXML seem to just show up.
Is there something I am missing to "initialize" a layout in Android? I have made native apps in Android and not had to do anything special.
Why would the UI above the NavigationPage cause the NavigationPage not to do standard initialization?
What am I missing???
Edit:
I created a working example of this issue on my GitHub account which you can clone here:
https://github.com/XamarinMonkey/CustomMasterDetail
Build and run CustomMasterDetail.Droid (Notice the UI is a MasterDetailPage)
Tap any item
The bottom blue bar has no page numbers.
Rotate orientation the page numbers display.
Stop the build
Comment out the entire class "MainMasterDetailPageRenderer.cs"
Rebuild / run the app
Tap any item
Page numbers are shown right away as expected just because it is now using the default MasterDetailPage!
Give suggestions please!
Edit #2:
Thanks to some feedback, it does not seem to be an issue in 6.0 devices. My testing device is a "Samsung Galaxy Tab Pro" with v5.1.1. And unfortunately I need this app to go back to 4!
Edit #3:
The issue has to be adding a view programmatically in Android 5.1.1 to a native RelativeLayout (which is pushed to a NavigationPage detail page ) after it is inflated in Xamarin.Forms. Calling Measure / Layout manually seems to solve the issue. But I need a more automated solution.
I came up with a solution that works. It might be expensive but it seems to layout fast on devices I have tested.
Basicly, I read up on Android and found a way to listen for layout changes using the ViewTreeObserver.GlobalLayout event combined with calling Measure / Layout on the detail and master ViewGroups.
public void MeasureAndLayoutNative()
{
if(_childView != null)
{
IVisualElementRenderer renderer = Platform.GetRenderer(_childView);
if(renderer.ViewGroup != null)
{
var nativeView = renderer.ViewGroup;
var w = MeasureSpec.MakeMeasureSpec(nativeView.MeasuredWidth, MeasureSpecMode.Exactly);
var h = MeasureSpec.MakeMeasureSpec(nativeView.MeasuredHeight, MeasureSpecMode.Exactly);
nativeView.Measure(w, h);
nativeView.Layout(nativeView.Left, nativeView.Top, nativeView.Right, nativeView.Bottom);
}
}
}
I updated my code example above with the working changes!
I am writing test cases to check the proper functioning of the Android Audio Recorder App.
In one such test case, I want my Python code to display the names of recordings in the terminal.
Eg:
Recording20.mp3
Recording19.mp3
...
...
Recording3.mp3
Recording2.mp3
Recording1.mp3
Recording0.mp3
All the TextView content has the same resource-id: text1
Below is the screenshot from UIAutomatorViewer
I am using Ubuntu 14.04.
I implemented scroll method :
i = 0
while i <= 2:
for num in range(0,5):
element1 = WebDriverWait(self.driver, 15).until(EC.presence_of_element_located((By.XPATH, '//android.widget.ListView/android.widget.TextView[#index= %d]' % num)))
self.assertIsNotNone(element1)
print element1.text
element_to_tap = self.driver.find_element_by_xpath('//android.widget.ListView/android.widget.TextView[#index= 5]')
element_to_drag_to = self.driver.find_element_by_xpath('//android.widget.ListView/android.widget.TextView[#index= 0]')
self.driver.scroll(element_to_tap, element_to_drag_to)
i = i +1
Here, I am trying to display 5 list elements each time, before scrolling.. I had 15 list elements right now.
Result I am getting now is :
Recording15.mp3
Recording14.mp3
Recording13.mp3
Recording12.mp3
Recording11.mp3
Recording6.mp3
Recording5.mp3
Recording4.mp3
Recording3.mp3
Recording2.mp3
Recording6.mp3
Recording5.mp3
Recording4.mp3
Recording3.mp3
Recording2.mp3
ok
Recordings in the middle are missing.. It scrolls completely to the bottom..
How can I find the total count of the android
ListView contents ? It would be helpful if I could get a way to count those, in order to put as a condition in loops. It gets terminated, when condition becomes false.
I searched a lot, but couldn't find.
I am too close to the answer, yet too far..
I developed a simple javafx application to be ported in Android Environment, however I cant type any characters in the TextField. I guess its a bug, how to fix this one?
Th problem on galaxy S5 android 5.0.1 is not present but on galaxy tab 4 android 5.0.2 it doesn't work i type but none is displyed.
Tried with normal textfield. And the problem persist also I have added the properties .
Another strange rhig is that the space where recognizer. And the del button . The text not
THe code by example is very easy
Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
double width = visualBounds.getWidth();
double height = visualBounds.getHeight();
TextField tt= new TextField();
tt.setTranslateY(-150);
StackPane stackPane = new StackPane();
stackPane.getChildren().addAll(tt);
borderpane.setCenter(stackPane);
Scene scene = new Scene(borderpane, width, height);
stage.setScene(scene);
Assuming that CustomTextField is just a custom TextField, this is a known issue, not related to the CustomTextField itself, given that it works in other device.
If you debug it:
./adb logcat -v threadtime
you surely find an exception that explains the issue: a StackOverFlow exception.
On older devices it can be solved adding this: create a java.custom.properties file, and include in it this property:
monocle.stackSize=128000
You may also include this one:
monocle.platform=Android
(it will be soon included by default in the next version)
Put the file at the root of your classpath, e.g. in the folder src/android/resources of your project.
Build and deploy the project on your mobile and check again.
I have set up a small mobile application and during tests I have stumbled upon a problem with older versions of mobile devices running Android version 2. Please note that iPhones, iPads and newer versions of Android, namely 4.xx display the pages well. The problem is as follows:
When page is called directly from the link:
Home
it is properly displayed.
However, when there is a click handler on a link, like here:
$(document).on('click', '#lstAddrList li', function ()
{
var anchor = $(this).find('a');
sessionStorage.SiteAddr = anchor.attr('id');
changePage();
});
the list line (in this case) stays selected and nothing happens. It is ONLY after the calling page is refreshed directly from the browser when the called page is displayed. I have a feeling that older Androids do not properly handle changePage() method.
Will you have some ideas?