I have tried with following method to make scroll down from top to the bottom on the screen but it seems not responding at all. Do you have any idea what is the reason ?
public void scrolTest(){
TouchAction tc=new TouchAction(driver);
Dimension dimension=driver.manage().window().getSize();
Double screenHeightStart = dimension.getHeight() * 0.5;
int scrollStartY = screenHeightStart.intValue();
Double screenHeightEnd = dimension.getHeight() * 0.2;
int scrollEndY = screenHeightEnd.intValue();
int scrollX=dimension.getWidth()/2;
tc.longPress(scrollX,scrollStartY).moveTo(scrollX,scrollEndY).release(); //(0,scrollStartY,0,scrollEndY,2000);
}
You are not using perform() method.
tc.longPress(scrollX,scrollStartY).moveTo(scrollX,scrollEndY).release().perform();
Try this code
public void scrollTest() {
Dimension dimension = driver.manage().window().getSize();
int scrollStartY = (int) (dimension.getHeight() * 0.5);
int scrollEndY = (int) (dimension.getHeight() * 0.2);
int scrollX = dimension.getWidth() / 2;
int heightOffset = scrollStartY - scrollEndY;
//Also note that in moveTo function, you have to provide the offSet values, not the (x,y) coordinates
//of the point where you want to move. Hence, i have written 0 in x coordinate (as we don't want to
//change x coordinate) and calculated the heightOffset separately.
new TouchAction(driver).press(scrollX, scrollStartY).moveTo(0, heightOffset).release().perform();
}
Related
I'm working on an app which allows the user to rotate an object with iOS touch controls.
I have the following script working fine, with 1 issue that I can't seem to crack.
GameObject mainCamera;
public Camera camMain;
// One Touch Rotation
public float rotateSpeed = 0.5f;
static float pitch = 0.0f, yaw = 0.0f, zed = 0.0f, pitchBravo = 0.0f, yawBravo = 0.0f;
// Two Touch Zoom
public float perspectiveZoomSpeed = 0.1f;
// Three Touch Pan
public float panSpeed = 0.5f;
private float xAxis = 0.0f, yAxis = 0.0f;
private float xMain, yMain, zMain;
// Game Objects, Public or Private
private GameObject bravo;
void Update()
{
// Grabs Bravo
bravo = GameObject.Find ("bravo");
pitch = bravo.transform.eulerAngles.x;
yaw = bravo.transform.eulerAngles.y;
// One Touch controls rotation of Bravo
if (Input.touchCount == 1)
{
// Retrieves a single touch and names it TouchZero
Touch touchZero = Input.GetTouch (0);
// The start of the rotation will be aligned with Bravo's current rotation
//pitch = bravo.transform.eulerAngles.x;
//yaw = bravo.transform.eulerAngles.y;
// Times the difference in position of touch between frames by the rotation speed. deltaTime to keep movement consistent on all devices
pitch += touchZero.deltaPosition.y * rotateSpeed * Time.deltaTime;
yaw -= touchZero.deltaPosition.x * rotateSpeed * Time.deltaTime;
// Assigns the new eulerAngles to Bravo
bravo.transform.eulerAngles = new Vector3 (pitch, yaw, 0.0f);
}
// Two Touch contols the Field of View of the Camera aka. Zoom
if (Input.touchCount == 2)
{
mainCamera = GameObject.Find("main");
// Store both touches.
Touch touchZero = Input.GetTouch(0);
Touch touchOne = Input.GetTouch(1);
// Find the position in the previous frame of each touch.
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
// Find the magnitude of the vector (the distance) between the touches in each frame.
float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;
// Find the difference in the distances between each frame.
float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag;
// Otherwise change the field of view based on the change in distance between the touches.
camMain.fieldOfView += deltaMagnitudeDiff * perspectiveZoomSpeed;
// Clamp the field of view to make sure it's between 0 and 180.
camMain.fieldOfView = Mathf.Clamp(camMain.fieldOfView, 2.0f, 30.0f);
xAxis -= touchOne.deltaPosition.x * panSpeed * Time.deltaTime;
yAxis -= touchOne.deltaPosition.y * panSpeed * Time.deltaTime;
zMain = mainCamera.transform.position.z;
mainCamera.transform.position = new Vector3 (xAxis, yAxis, zMain);
}
}
With this script the object rotates left and right perfectly, 360°. But when the model is rotated up and down it gets to the 90° or -90° mark and bugs out, not allowing the user to carry on rotating.
I've done a bit of research and I believe it may have something to do with gimbal lock, my lack of knowledge on the subject means I haven't been able to come up with a fix.
Any help is appreciated.
GIF of bugged rotation
I have a label with a lot of text that I want to enable pinch-to-zoom and panning gesture recognizers in. I used the recipes from here and then nested them within each other.
https://developer.xamarin.com/guides/xamarin-forms/user-interface/gestures/pinch/
https://developer.xamarin.com/guides/xamarin-forms/user-interface/gestures/pan/
Problem is, both container objects allow you to move the label completely outside of it's normal bounds anywhere within the top level page view (demonstrated in the pictures below).
Any thoughts on how to implement some limits on these? I'm sure it's just placing some limits on the math in the container code, but I haven't found the right thing to change yet.
As you can see in these images, both the pinch-to-zoom container (without panning) and the pan container (without zooming) allow you to alter the control so it goes outside it's bounds.
Initial Layout:
Pinch-To-Zoom only
Panning only
Pinch and Pan
The links above have the container code, but here it is:
PinchToZoomContainer.cs
public class PinchToZoomContainer : ContentView
{
// Pinch Gesture variables
double currentScale = 1;
double startScale = 1;
double xOffset = 0;
double yOffset = 0;
public PinchToZoomContainer ()
{
var pinchGesture = new PinchGestureRecognizer ();
pinchGesture.PinchUpdated += OnPinchUpdated;
GestureRecognizers.Add (pinchGesture);
}
void OnPinchUpdated (object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started) {
// Store the current scale factor applied to the wrapped user interface element,
// and zero the components for the center point of the translate transform.
startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;
}
if (e.Status == GestureStatus.Running) {
// Calculate the scale factor to be applied.
currentScale += (e.Scale - 1) * startScale;
currentScale = Math.Max (1, currentScale);
// The ScaleOrigin is in relative coordinates to the wrapped user interface element,
// so get the X pixel coordinate.
double renderedX = Content.X + xOffset;
double deltaX = renderedX / Width;
double deltaWidth = Width / (Content.Width * startScale);
double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;
// The ScaleOrigin is in relative coordinates to the wrapped user interface element,
// so get the Y pixel coordinate.
double renderedY = Content.Y + yOffset;
double deltaY = renderedY / Height;
double deltaHeight = Height / (Content.Height * startScale);
double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;
// Calculate the transformed element pixel coordinates.
double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);
// Apply translation based on the change in origin.
Content.TranslationX = targetX.Clamp (-Content.Width * (currentScale - 1), 0);
Content.TranslationY = targetY.Clamp (-Content.Height * (currentScale - 1), 0);
// Apply scale factor
Content.Scale = currentScale;
}
if (e.Status == GestureStatus.Completed) {
// Store the translation delta's of the wrapped user interface element.
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
}
}
PanContainer.cs
public class PanContainer : ContentView
{
double startX, startY;
double x, y;
public PanContainer ()
{
// Set PanGestureRecognizer.TouchPoints to control the
// number of touch points needed to pan
var panGesture = new PanGestureRecognizer ();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add (panGesture);
}
void OnPanUpdated (object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType) {
case GestureStatus.Started:
startX = Content.TranslationX;
startY = Content.TranslationY;
break;
case GestureStatus.Running:
// Translate and ensure we don't pan beyond the wrapped user interface element bounds.
//Content.TranslationX = Math.Max (Math.Min (0, x + e.TotalX), -Math.Abs (Content.Width - App.ScreenWidth));// App.ScreenWidth));
//Content.TranslationY = Math.Max (Math.Min (0, y + e.TotalY), -Math.Abs (Content.Height - App.ScreenHeight)); //App.ScreenHeight));
Content.TranslationX = startX + e.TotalX;
Content.TranslationY = startY + e.TotalY;
break;
case GestureStatus.Completed:
// Store the translation applied during the pan
x = Content.TranslationX;
y = Content.TranslationY;
break;
}
}
}
I imagine, on the PanContainer, my issue is in these lines that I had to comment out:
//Content.TranslationX = Math.Max (Math.Min (0, x + e.TotalX), -Math.Abs (Content.Width - App.ScreenWidth));// App.ScreenWidth));
//Content.TranslationY = Math.Max (Math.Min (0, y + e.TotalY), -Math.Abs (Content.Height - App.ScreenHeight)); //App.ScreenHeight));
I changed these to a more simple version because I can't find App.ScreenWidth or .ScreenHeight properties.
The pinch container, however, is just as it was originally in the recipe and still goes outside the bounds.
There is an IsClippedToBounds property that helped me with this issue.
For example:
<PanContainer IsClippedToBounds="true">
<PanContainer.Content>
<Image x:Name="SomeImage" />
</PanContainer.Content>
</PanContainer>
To get pinch and pan, you can either wrap a pinch element in a pan element or vice versa, or you can create a single class with the functions from both the pinch and pan classes. The latter is probably better.
That alone will probably not work exactly as you expect though because the calculations in the pinch and pan functionality are not aware of each other, so if for example you pinch to zoom in then the pan functionality doesn't know that it can now pan further.
This answer is mostly likely very late for your needs, Chet... but, you can simply wrap the whole thing in a ScrollView (which you will appropriately locate and/or size to your needs). That should work as expected.
<ScrollView Grid.Column="2" VerticalOptions="Start">
<PanContainer>
<PanContainer.Content>
<Image x:Name="SomeImage" Aspect="AspectFit" />
</PanContainer.Content>
</PanContainer>
</ScrollView>
Cheers!
Mike
I am trying to update the current rotation (and sometimes the position) of a CALayer.
What I am trying to in a couple of simple steps:
Store a couple of CALayers in an array, so I can reuse them
Set the anchor point of all CALayers to 0,0.
Draw CALayer objects where the object starts at a position on a circle
The layers are rotated by the same angle as the circle at that position
Update the position and rotation of the CALayer to match new values
Here is a piece of code I have:
lineWidth is the width of a line
self.items is an array containing the CALayer objects
func updateLines() {
var space = 2 * M_PI * Double(circleRadius);
var spaceAvailable = space / (lineWidth)
var visibleItems = [Int]();
var startIndex = items.count - Int(spaceAvailable);
if (startIndex < 0) {
startIndex = 0;
}
for (var i = startIndex; i < self.items.count; i++) {
visibleItems.append(self.items[i]);
}
var circleCenter = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
/* Each line should move up and rotate accordin to this value */
var anglePerLine: CGFloat = (360 / CGFloat(visibleItems.count)).toRadians()
/* Starting position, 270 degrees is on top */
var startAngle: CGFloat = CGFloat(270).toRadians();
/* Lines default rotation, we rotate it to get the right side up */
var lineAngle: CGFloat = CGFloat(180).toRadians();
for (var itemIndex = 0; itemIndex < visibleItems.count; itemIndex++) {
var itemLayer = self.itemLayers[itemIndex];
itemLayer.opacity = 1 - ((0.9 / visibleItems.count) * itemIndex);
/* Calculate start position of layer */
var x = CGFloat(circleRadius) * cos(startAngle) + CGFloat(circleCenter.x);
var y = CGFloat(circleRadius) * sin(startAngle) + CGFloat(circleCenter.y);
var height = CGFloat((arc4random() % 80) + 10);
/* Set position and frame of layer */
itemLayer.frame = CGRectMake(CGFloat(x), CGFloat(y), CGFloat(lineWidth), height);
itemLayer.position = CGPointMake(CGFloat(x), CGFloat(y));
var currentRotation = CGFloat((itemLayer.valueForKeyPath("transform.rotation.z") as NSNumber).floatValue);
var newRotation = lineAngle - currentRotation;
var rotationTransform = CATransform3DRotate(itemLayer.transform, CGFloat(newRotation), 0, 0, 1);
itemLayer.transform = rotationTransform;
lineAngle += anglePerLine;
startAngle += anglePerLine;
}
}
The result of the first run is exactly as I want it to be:
The second run through this code just doesn't update the CALayers correctly and it starts to look like this:
I think it has to do with my code to update the location and transform properties of the CALayer, but whatever I do, it always results in the last picture.
Answered via Twitter: setting frames and transform is mutually exclusive. Happy to help. Finding my login credentials for SO is harder. :D
Found the answer thanks to #iosengineer on Twitter. When setting a position on the CALayer, you do not want to update the frame of the layer, but you want to update the bounds.
Smooth animation FTW
I am using PdfAnnotation.SetContents to set the value of an annotation.If the annotation is of type FreeText, only then this method correctly works and the value gets displayed on the PDF (using PDF Reader).If the type is Widget, the value gets set as content in pdf dictionary but does not get displayed.Is there a way i could set the value of a widget?
I found the solution, In order for the content to get displayed, an Appearance ("AP") Dictionary has to be set.
This could be used for that:
void PdfField::CreateFieldAppearance(PdfMemDocument *memDoc, const PdfString &value)
{
if( !m_pWidget->HasAppearanceStream() )
{
PdfRect pageRect;
PdfPainter painter;
PoDoFo::PdfRect rect = this->GetWidgetAnnotation()->GetRect();
unsigned int width = rect.GetWidth();
unsigned int height = rect.GetHeight();
PdfRect pdfRect(0, 0, width, height);
PdfXObject xObj(pdfRect, memDoc);
painter.SetPage(&xObj);
painter.SetClipRect(pdfRect);
painter.Save();
painter.SetColor(221.0/255.0, 228.0/255.0, 1.0);
painter.FillRect(0, 0, width, height);
painter.Restore();
// make rotation
painter.Save();
/***********************************************************************************/
// Rotation Logic
double angle = this->GetPage()->GetRotation();
if (angle) {
double radAngle = angle * M_PI / 180;
int cosA = (int)cos(radAngle);
int sinA = (int)sin(radAngle);
double translateY = rect.GetWidth(); // The View goes out of the bound, sits on top
painter.SetTransformationMatrix(cosA, sinA, -sinA, cosA, translateY, 0);
}
/***********************************************************************************/
PdfFont *font = memDoc->CreateFont("Helvetica", true, false);
font->SetFontSize(15);
// Do the drawing
painter.SetFont(font);
painter.BeginText(10, 5);
painter.SetStrokeWidth(20);
painter.AddText(value);
painter.EndText();
painter.FinishPage();
// This is very important. Not only does it disable the editing.
// Also it does correct the appearance issue on Adobe Readers.
this->SetReadOnly(true);
// The Stream Object has to be saved to the annotation
PoDoFo::PdfDictionary dict;
dict.AddKey( "N", xObj.GetObject()->Reference() );
this->GetFieldObject()->GetDictionary().AddKey( "AP", dict );
}
}
How do I draw a radial gradient button in BlackBerry? I found "Drawing Radial Gradients" on the BlackBerry support forums. All I am able to implement on my own is a linear gradient.
This is a little tricky. Drawing linear gradients on field backgrounds is easy. Drawing radial gradients on field backgrounds is harder. Doing it on a button is harder still.
First of all, the example you link to does indeed look really bad. The biggest problem with that code is that it uses Graphics.drawArc() to construct the gradient out of concentric circles (lines). This is not at all smooth.
The biggest improvement you need to make over that is to use Graphics.fillArc() instead, which will look much smoother (although there may be a performance impact to this ...).
Your question didn't say anything about how you wanted the button to look when focused, or whether the corners needed to be rounded. That's where some of the difficulty comes in.
If you just extend the RIM ButtonField class, you'll probably have trouble with the default drawing for focus, and edge effects. It's probably necessary to directly extend the base Field class in a new, written-from-scratch, button field. I wouldn't necessarily recommend that you do all this yourself, since buttons require focus handling, click handling, etc. You should probably start with something like the BaseButtonField from the BlackBerry AdvancedUI open source library.
I have prototyped this for you, using that class as a base. (so, you'll need to download and include that source file in your project if you use this).
I created a GradientButtonField subclass:
private class GradientButtonField extends BaseButtonField {
private int startR;
private int startG;
private int startB;
private int endR;
private int endG;
private int endB;
/** the maximum distance from the field's center, in pixels */
private double rMax = -1.0;
private int width;
private int height;
private String label;
private int fontColor;
/**
* Create a gradient button field
* #param startColor the integer Color code to use at the button center
* #param endColor the integer Color code to use at the button edges
* #param label the text to show on the button
* #param fontColor color for label text
*/
public GradientButtonField (int startColor, int endColor, String label, int fontColor) {
// record start and end color R/G/B components, to
// make intermediate math easier
startR = (startColor >> 16) & 0xFF;
startG = (startColor >> 8) & 0xFF;
startB = startColor & 0xFF;
endR = (endColor >> 16) & 0xFF;
endG = (endColor >> 8) & 0xFF;
endB = endColor & 0xFF;
this.label = label;
this.fontColor = fontColor;
}
public String getLabel() {
return label;
}
protected void layout(int w, int h) {
width = Math.min(Display.getWidth(), w);
height = Math.min(Display.getHeight(), h);
if (rMax < 0.0) {
rMax = Math.sqrt((width * width)/4.0 + (height * height)/4.0);
}
setExtent(width, height);
}
private int getColor(double scale, boolean highlighted) {
int r = (int)(scale * (endR - startR)) + startR;
int g = (int)(scale * (endG - startG)) + startG;
int b = (int)(scale * (endB - startB)) + startB;
if (highlighted) {
// just brighten the color up a bit
r = (int)Math.min(255, r * 1.5);
g = (int)Math.min(255, g * 1.5);
b = (int)Math.min(255, b * 1.5);
}
return (65536 * r + 256 * g + b);
}
protected void paint(Graphics graphics) {
int oldColor = graphics.getColor();
// we must loop from the outer edge, in, to draw
// concentric circles of decreasing radius, and
// changing color
for (int radius = (int)rMax; radius >= 0; radius--) {
double scale = ((double)radius) / rMax;
boolean focused = (getVisualState() == Field.VISUAL_STATE_FOCUS);
graphics.setColor(getColor(scale, focused));
int x = width / 2 - radius;
int y = height / 2 - radius;
graphics.fillArc(x, y, 2 * radius, 2 * radius, 0, 360);
}
String text = getLabel();
graphics.setColor(fontColor);
graphics.drawText(text,
(width - getFont().getAdvance(text)) / 2,
(height - getFont().getHeight()) / 2);
// reset graphics object
graphics.setColor(oldColor);
}
}
To use this, the Manager that contains the button will need to constrain the button's size in its sublayout() implementation. Or, you can edit my GradientButtonField class to hardcode a certain size (via getPreferredWidth(), layout(), etc.), or whatever you want.
final Field button1 = new GradientButtonField(Color.DARKGRAY, Color.BLUE,
"Click Me!", Color.WHITE);
final Field button2 = new GradientButtonField(Color.DARKGRAY, Color.BLUE,
"Click Me, Too!", Color.WHITE);
Manager mgr = new Manager(Manager.NO_VERTICAL_SCROLL) {
public int getPreferredHeight() {
return Display.getHeight();
}
public int getPreferredWidth() {
return Display.getWidth();
}
protected void sublayout(int maxWidth, int maxHeight) {
setExtent(getPreferredWidth(), getPreferredHeight());
layoutChild(button1, 160, 80);
setPositionChild(button1, 20, 50);
layoutChild(button2, 120, 60);
setPositionChild(button2, 20, 150);
}
};
button1.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
Dialog.alert("clicked!");
}
});
mgr.add(button1);
mgr.add(button2);
add(mgr);
I did not round the corners, as that's a bit of work. Depending on what kind of backgrounds you're putting these buttons on, it might be easiest to create a PNG mask image (in your favorite drawing program), which is mostly transparent, and then just has filled corners that mask off the corners of the gradient below it. Then, use Graphics.drawBitmap() in the paint() method above, after you've drawn the radial gradient.
For focus highlighting, I just put in some simple code to brighten the colors when the button is focused. Again, you didn't say what you wanted for that, so I just did something simple.
Here's the result of the code above. The bottom button is focused: