I'm using the PdfTron SDK and i'm trying to draw annotation after the user doing zoom in, the annotation need to be in the side of the book (the third pic) but when we do zoom in it's drawing in the center of the book (pic 1 and 2).
Example with zoom (the wrong state):
Example without zoom (the right state):
right now i'm using the function convPagePtToScreenPt but it's drawing the annotation properly just if the user doesn't making zoom in.
Does somebody knows in which function is suppose to use?
This is my code :
public synchronized void drawAnnotation(AnnotationData annotationData){
if (annotationData == null) {
return;
}
AnnotationType annotationType = annotationData.getType();
if (annotationType == null) {
return;
}
ToolManager.Tool tool = mToolManager.createTool(ToolManager.e_text_annot_create, null);
if (tool instanceof StickyNoteCreate) {
StickyNoteCreate annotStickyCreate = (StickyNoteCreate) tool;
Point point;
double[] pts;
double[] ptsForScreenSize = {0, 0};
int orientation = mContext.getResources().getConfiguration().orientation;
if (mPDFView != null) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
ptsForScreenSize = mPDFView.convScreenPtToPagePt((double) BookReader.SCREEN_WIDTH, (double) BookReader.SCREEN_HEIGHT, annotationData.getPage());
} else {
ptsForScreenSize = mPDFView.convScreenPtToPagePt((double) BookReader.SCREEN_HEIGHT, (double) BookReader.SCREEN_WIDTH, annotationData.getPage());
if (!TextUtils.isEmpty(annotationData.getStartLoc()) && !TextUtils.isEmpty(annotationData.getEndLoc()) && mPDFView != null) {
//if we have an annotation for text
pts = mPDFView.convPagePtToScreenPt(annotationData.getStartX(), annotationData.getStartY(), annotationData.getPage());
} else {
//if we have an annotation for Page
pts = new double[]{0, 0};
}
ptsForScreenSize = mPDFView.convPagePtToScreenPt(ptsForScreenSize[0] - INT_ANNO_PADDING, ptsForScreenSize[1], annotationData.getPage());
final AnnotationData noteTextHighlight = new AnnotationData(annotationData);
//we don't need to set UniqueId for this highlight annotation
noteTextHighlight.setUniqueId(null);
highlightSelectedText(noteTextHighlight);
double marginY = BookReader.SCREEN_HEIGHT * 0.015;
point = new Point(ptsForScreenSize[0], pts[1] + marginY);
annotStickyCreate.createNoteIconOnPage(annotationData, point);
}
}
}
}
public void createNoteIconOnPage(AnnotationData annotationData, Point noteIconPoint) {
KsLog.d("IsBookReaderAviliable","createNoteIconOnPage : " + BookReader.isBookReaderVisible());
if(BookReader.isBookReaderVisible()){
try {
mPDFView.docLock(true);
PDFDoc pdfDoc = mPDFView.getDoc();
double[] pts = mPDFView.convScreenPtToPagePt(noteIconPoint.x, noteIconPoint.y, annotationData.getPage());
Point p = new Point(pts[0], pts[1]);
com.pdftron.pdf.annots.Text text = com.pdftron.pdf.annots.Text.create(pdfDoc, p);
text.setUniqueID(annotationData.getUniqueId());
//creating the annotation appearance - icon
// Let's create an appearance for the annotation using an image
ElementBuilder builder = new ElementBuilder();
ElementWriter writer = new ElementWriter();
writer.begin(pdfDoc);
Image image = Image.create(pdfDoc, annotationData.getDrawable());
int w = image.getImageWidth(), h = image.getImageHeight();
Element element = builder.createImage(image, 0, 0, w, h);
writer.writePlacedElement(element);
writer.writeElement(builder.createTextBegin(Font.create(pdfDoc, Font.e_times_roman), 12));
writer.writeElement(element);
writer.writeElement(builder.createTextEnd());
Obj appearance = writer.end();
appearance.putRect("BBox", 0.1, 0.1, w, h);
text.setAppearance(appearance);
/*
The left icons spouse to be bigger the the regular icons
*/
if (annotationData.getType() == AnnotationData.AnnotationType.LINK && (annotationData.getShard() == AnnotationData.LEFT_LINK_A || annotationData.getShard() == AnnotationData.LEFT_LINK_B)) {
text.setRect(new Rect(pts[0], pts[1], pts[0] + 30, pts[1] + 30));
}
if (annotationData.getType() == AnnotationData.AnnotationType.NOTE) {
text.setContents(AnnotationData.NOTE_TYPE_CONTENTS);
} else if (annotationData.getType() == AnnotationData.AnnotationType.LINK) {
text.setContents(AnnotationData.LINK_TYPE_CONTENTS);
}
KsLog.d("createNoteIconOnPage","getPage() " + annotationData.getPage());
Page page = pdfDoc.getPage(annotationData.getPage());
if (page != null) {
page.annotPushBack(text);
}
mAnnotPushedBack = true;
mAnnot = text;
mAnnotPageNum = annotationData.getPage();
KsLog.d("createNoteIconOnPage","mDownPageNum " + mAnnotPageNum);
buildAnnotBBox();
mPDFView.update(mAnnot, mAnnotPageNum);
raiseAnnotationAddedEvent(mAnnot, mAnnotPageNum);
} catch (Exception ex) {
Log.e(PDFTronReader.TAG, ex.toString());
mNextToolMode = ToolManager.e_pan;
} finally {
mPDFView.docUnlock();
}
mPDFView.waitForRendering();
}
}
The following code will place an annotation on the right side of any page, 1 inch from the top.
Matrix2D mtx = page.getDefaultMatrix(true).inverse();
double x1 = page.getPageWidth() - 25; // this is the width as the a user sees it (rotated). 20 is the width of a Text annotation
double y1 = 72; // not clear how you decide the vertical placement. In this example, this 1 inch from the top as the user views the page. If you have the value from the bottom, switch the boolean value argument in GetDefaultMatrix
mtx.mult(ref x1, ref y1);
com.pdftron.pdf.Annots.Text txt = com.pdftron.pdf.Text.create(doc, new Point(x1, y1));
page.annotPushBack(txt);
Regarding your code, there appeared to be confusion over Screen and Page coordinates. For example, for ptsForScreenSize on one line of you pass in the results of ConvScreenPtToPagePt, and in another line, you pass in the results of ConvPagePtToScreenPt.
Related
In my application, I am using the below code to create a short cut.
public void createShortcut(Intent intent) {
Intent.ShortcutIconResource iconResource = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
Bitmap icon = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
String shortcutLabel = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
Intent shortIntent = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
if (icon == null) {
if (iconResource != null) {
Resources resources = null;
try {
resources = pm.getResourcesForApplication(iconResource.packageName);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
if (resources != null) {
int id = resources.getIdentifier(iconResource.resourceName, null, null);
if (resources.getDrawable(id) instanceof StateListDrawable) {
Drawable d = (resources.getDrawable(id)).getCurrent();
icon = ((BitmapDrawable) d).getBitmap();
} else
icon = ((BitmapDrawable) resources.getDrawable(id)).getBitmap();
}
}
}
if (shortcutLabel != null && shortIntent != null && icon != null) {
ShortcutSerializableData objectData = AppSharedPref.getInstance().getShortcutSerializableData();
if (objectData == null) {
objectData = new ShortcutSerializableData();
Log.e(TAG, "Serialized data not found");
}
if (objectData.apps == null) {
objectData.apps = new ArrayList();
Log.e(TAG, "Serialized app not found");
}
ShortcutPac pacToAdd = new ShortcutPac();
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
if (x >= (width - 250)) {
y = y + 150;
x = 40;
}
pacToAdd.x = x;
pacToAdd.y = y;
pacToAdd.URI = shortIntent.toUri(0);
pacToAdd.label = shortcutLabel;
pacToAdd.icon = icon;
x = x + 250;
if (HomeActivity.activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
pacToAdd.landscape = true;
else
pacToAdd.landscape = false;
pacToAdd.cacheIcon();
objectData.apps.add(pacToAdd);
pacToAdd.addToHome(this, homeView);
AppSharedPref.getInstance().setShortcutSerializableData(objectData);
}
}
And above code is working and creating short cuts as expected. My question is can change the size of short cut icons? I mean by above code I am getting the size of the icon (for example 50x50) then I am getting the same size of the short cut icon on 7 and 10-inch tablets as well. What I want is to change the size of short cut icons for tablets. I want to show tablets shortcut icon bigger than usual as it is creating for cellphones.
NOTE: In settings of Android OS, if I select display option and from there I can increase the size of icons and texts. But the same thing I want, I want to change the size if short cut icons programmatically. Is it possible? Any help would be highly appreciated.
Icon display size is launcher dependent. Luckily you cannot enforce different size user wants.
I'm trying to draw annotation and in 80% of the time the annotation draw properly but sometimes the annotation is cut in the middle and after i do zoom in and do zoom out the annotation is drawing completely.
this is the code where i draw the annotation:
public void createNoteIconOnPage(AnnotationData annotationData, Point noteIconPoint) {
try {
mPDFView.docLock(true);
PDFDoc pdfDoc = mPDFView.getDoc();
double[] pts = mPDFView.convScreenPtToPagePt(noteIconPoint.x, noteIconPoint.y, annotationData.getPage());
Point p = new Point(pts[0], pts[1]);
com.pdftron.pdf.annots.Text text = com.pdftron.pdf.annots.Text.create(pdfDoc, p);
text.setUniqueID(annotationData.getUniqueId());
//creating the annotation appearance - icon
// Let's create an appearance for the annotation using an image
ElementBuilder builder = new ElementBuilder();
ElementWriter writer = new ElementWriter();
writer.begin(pdfDoc);
Bitmap imageBitmap = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888);
imageBitmap.eraseColor(Color.RED);
Image image = Image.create(mPDFView.getDoc(), imageBitmap);
// Image image = Image.create(pdfDoc, annotationData.getDrawable());
int w = image.getImageWidth(), h = image.getImageHeight();
Element element = builder.createImage(image, 0, 0, w, h);
writer.writePlacedElement(element);
writer.writeElement(builder.createTextBegin(Font.create(pdfDoc, Font.e_times_roman), 12));
writer.writeElement(element);
writer.writeElement(builder.createTextEnd());
Obj appearance = writer.end();
appearance.putRect("BBox", 0.1, 0.1, w, h);
text.setAppearance(appearance);
/*
The left icons spouse to be bigger the the regular icons
*/
if(annotationData.getType() == AnnotationData.AnnotationType.LINK && (annotationData.getShard() == AnnotationData.LEFT_LINK_A || annotationData.getShard() == AnnotationData.LEFT_LINK_B)){
text.setRect(new Rect(pts[0],pts[1],pts[0] + 30,pts[1] + 30));
}
if (annotationData.getType() == AnnotationData.AnnotationType.NOTE) {
text.setContents(AnnotationData.NOTE_TYPE_CONTENTS);
} else if (annotationData.getType() == AnnotationData.AnnotationType.LINK) {
text.setContents(AnnotationData.LINK_TYPE_CONTENTS);
}
Page page = pdfDoc.getPage(annotationData.getPage());
if (page != null) {
page.annotPushBack(text);
}
mAnnotPushedBack = true;
mAnnot = text;
mAnnotPageNum = mDownPageNum;
buildAnnotBBox();
mPDFView.update(mAnnot, mAnnotPageNum);
raiseAnnotationAddedEvent(mAnnot, mAnnotPageNum);
} catch (Exception ex) {
Log.e(PDFTronReader.TAG, ex.toString());
mNextToolMode = ToolManager.e_pan;
} finally {
mPDFView.docUnlock();
}
mPDFView.waitForRendering();
}
and this is how it's look:
as you can see, we have 3 annotations in the left size (3 red squares) and the first one is cut in the middle
does somebody knows why it's happen?
thanks you all.
I think there is a discrepancy between what annotationData.getPage() returns and what mAnnotPageNum is.
I would consolidate this code around one of those two variables. That is, use one or the other. I suspect 20% of the time they are not the same number.
Furthermore, Text annots only have a position, as their size is fixed. They don't scale the same as normal annotations. So I would comment out the call to buildAnnotBBox.
Other things I would change.
As mentioned above, the size is fixed. So remove the following line
text.setRect(new Rect(pts[0],pts[1],pts[0] + 30,pts[1] + 30));
You set the BBox origin at 0.1, when this should be 0 based on your custom appearance.
I have made a sketch in processing using saitoobjloader and controlP5 librarys, and it works just fine, and after that i have exported as an android app to import it in eclipse. I have runned it then on my phone, from eclipse, and it works, except that, everything is black and white.I have tried model.disableMaterial(), model.disableTexture() and it does not work, I have seted for android 2.3.3, 4.2.2, 4.4 and it also don't work...stil black and white. I have tried primitive debug by disabeling everything i can one by one: the animation, the boject loaded, screen orientation and stil black and white. Idon't have any permisions aded, and the only change i have made is for screen orientation in manifes aplication: Debuggable --> null, Screen orientation --> unspecified, Config changes --> orientation.
Below you can see my code from eclipse:
package processing.test.my_cnc_obj_with_gui_mooving_animation;
import processing.core.*;
import android.content.res.Configuration;
import saito.objloader.*;
import controlP5.*;
public class My_cnc_obj_with_GUI_mooving_animation extends PApplet {
OBJModel model;
ControlP5 sb;
float rotX;
float rotY;
float zoom = 1;
float translateX;
float translateY;
float k;
int i;
float initlength = 250;
int initlengthX = 150;
int initlengthY = 150;
int initlengthZ = 80;
float moveIndex;
float AXA_X;
float AXA_Y;
float AXA_Z;
public void setup() {
model = new OBJModel(this, "CNC colorat pentru processing.obj");
model.scale(400);
model.translateToCenter();
//model.disableTexture();
model.disableMaterial();
//model.disableDebug();
controlereGUI();
noStroke();
}
public void draw() {
background(50, 34, 32);
lights();
// fill(255,0,255);
pushMatrix();
translate(width/2 - 50, height/2, 0);
rotateX(rotY);
rotateY(rotX);
model.draw();
model.disableMaterial();
popMatrix();
animation();
}
public void mouseDragged()
{
rotX += (mouseX - pmouseX) * 0.01f;
rotY -= (mouseY - pmouseY) * 0.01f;
}
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
int orientation = newConfig.orientation;
model.disableMaterial();
//Something strange happened... bail out!
if(orientation == Configuration.ORIENTATION_UNDEFINED)
return;
orientation = Configuration.ORIENTATION_PORTRAIT;
if(orientation == Configuration.ORIENTATION_LANDSCAPE) {
//Landscape config
}
if(orientation == Configuration.ORIENTATION_PORTRAIT) {
//Portrait config
}
}
/*public void mouseWheel(MouseEvent e) {
translateX = translateX-e.getAmount()*(mouseX)/100;
translateY = translateY-e.getAmount()*(mouseY)/100;
zoom += e.getAmount() / 100;
model.scale(zoom);
}*/
public void controlereGUI() {
sb = new ControlP5(this);
sb.getTab("default")
//.activateTab("Assisted_controll")
//.activateEvent(true)
.setHeight(40)
.setLabel("Assisted controll")
.setId(3)
;
sb.getTab("Manual_controll")
//.activateTab("Manual_controll")
//.activateEvent(true)
.setHeight(40)
.setLabel("Manual controll")
.setId(1)
;
sb.addTab("Settings")
//.activateTab("Settings")
.setHeight(40)
.setWidth(60)
.setLabel("Settings")
.setId(2)
.setColorBackground(color(0, 160, 100))
//.activateEvent(true)
.setColorLabel(color(255))
.setColorActive(color(255, 128, 0))
;
sb.addSlider("AXA_X")
.setPosition(10, 70)
//.setWidth(300)
.setSize(300, 30)
.setRange(initlength, 0)
//.setValue(128)
.setSliderMode(Slider.FLEXIBLE)
;
sb.addSlider("AXA_Y")
.setPosition(10, 110)
//.setWidth(300)
.setSize(300, 30)
.setRange(initlengthY, -initlengthY)
//.setValue(128)
.setSliderMode(Slider.FLEXIBLE)
.setColorForeground(0xffFC0000)
.setColorBackground(color(150, 0, 0))
;
sb.addSlider("AXA_Z")
.setPosition(10, 150)
//.setWidth(300)
.setSize(300, 30)
.setRange(initlengthZ + 120, 70)
//.setValue(128)
.setSliderMode(Slider.FLEXIBLE)
.setColorForeground(0xff0BFC00)
.setColorBackground(color(100, 150, 0))
;
sb.addButton("Start_movement")
.setBroadcast(false)
.setValue(128)
.setPosition(120, height-160)
//.setImages(imgs)
.setSize(90, 50)
.setCaptionLabel("Start movement")
.setColorBackground(color(100, 150, 0))
//.setVisible(false)
.setBroadcast(true)
;
sb.addButton("Stop_movement")
.setValue(128)
.setPosition(120, height-100)
//.setImages(imgs)
.setSize(90, 50)
.setCaptionLabel("Stop movement")
.setColorBackground(color(150, 0, 0))
//.setVisible(false)
;
}
public void animation() {
for (int i = 0; i < model.getVertexCount () - 6090; i++) {
PVector orgv = model.getVertex(i);
PVector tmpv = new PVector();
tmpv.x = orgv.x;
tmpv.y = orgv.y;
tmpv.z = orgv.z + (k * AXA_Y);
model.setVertex(i, tmpv);
}
if ((AXA_Y != 0)) {
if (moveIndex < AXA_Y)
moveIndex ++;
else
if (moveIndex > AXA_Y)
moveIndex --;
else
k = 0;
k = 1;
} else {
moveIndex = AXA_Y;
k = 0;
}
}
public int sketchWidth() { return 800; }
public int sketchHeight() { return 700; }
public String sketchRenderer() { return P3D; }
}
I don'tknow why is stil black and white.
Thanks in advance.
Solved.
It seems that i must use a combination of use of material (not disable it) and after drawing the model to stop the lights. So, it should be like in the code above, with this modifications:
public void setup() {
model = new OBJModel(this, "CNC colorat pentru processing.obj");
model.scale(400);
model.translateToCenter();
controlereGUI();
noStroke();
}
public void draw() {
background(50, 34, 32);
lights();
// fill(255,0,255);
pushMatrix();
translate(width/2 - 50, height/2, 0);
rotateX(rotY);
rotateY(rotX);
model.draw();
popMatrix();
noLights();
animation();
}
However, it seems that the 3D model remains still black and white even if is coloured. The 3D model was modified with Blender v2.71 (imported as .wrl file and exported as .obj with .mtl file). The .wrl file has been initial colored and when it was imported in Blender everything was ok, the model was colored. It seems that processing can't get the material. The debug shows: Material 'Shape.1687' not defined, ..., Material 'Shape.001' not defined,
Material 'Shape' not defined
I don't know where the problem is: inside saitoobjloader or the .obj and .mtl files....
Solved the second problem too. The problem is in file's name "CNC colorat pentru processing".
It seems that saito's objloader parser does not read spaces caracter (" ") in files name, so when i am making a new obj file (in blender or any other), i should have save it with the name "CNC_colorat_pentru_processing", or any other name that does not contain space caracter.
I use PDFJet-Open-Source library to construct a pdf. So, I have couple of questions:
1) How can I place the multiline text inside Cell?
Problem description: Currently I faced with problem that I can't place the multiline text inside Cell object. I tried set text like "text1 \n text2..." but it does not have any effect. Unfortunatelly, open source version does not have TextColumn and Paragraph classes.
2) What is the CompositeTextLine and how to use it?
Problem description: Perhaps I have wrong imagination, but I tried to do the following:
...
CompositeTextLine ctl = new CompositTextLine(0,0);
ctl.addComponent(new TextLine(f1,"MyText1"));
ctl.addComponent(new TextLine(f1,"MyText2"));
ctl.addComponent(new TextLine(f1,"MyText3"));
Cell cell = new Cell(f1);
cell.setCompositeTextLine(ctl);
...
I expected to see several multiple lines in the Cell but I observed nothing. Moreover, if I add the line table.wrapAroundCellText(), I've got NullPointerException. If I call ctl.drawOn(page), I just observe: "MyText1 MyText2 MyText3" without line breaking.
UPDATE: I discovered the TextBox class, so that, if I write:
TextBox textbox = new TextBox(f1);
textbox.setText("First Line \n Second Line");
textbox.drawOn(page);
it will construct what I want:
First Line
Second Line
But still I am interested with the possibility of (1) and description of (2) and some of them variations, like to "How to set TextBox (or image etc.) inside Cell, not only single line?"
And last one, could anyone, please, refer me to the realization of "text justification" algorithm in Java or C++.
I can across the same problem, and I ended up extending Cell, and using WordUtils from apache commons lang3:
public class MultilineCell extends Cell {
private final int characterCount;
public MultilineCell(Font font, String content, int characterCount) {
super(font, content);
this.characterCount = characterCount;
}
#Override
public String getText() {
return WrapUtil.wrap(super.getText(), this.characterCount);
}
#Override
public float getHeight() {
float height = this.font.getBodyHeight();
String text = getText();
if (text != null) {
String[] wrappedTexts = text.split(System.getProperty("line.separator"));
if (wrappedTexts.length > 1) {
return (height * wrappedTexts.length) + this.top_padding + this.bottom_padding;
}
}
return height + this.top_padding + this.bottom_padding;
}
#Override
protected void paint(Page page, float x, float y, float w, float h) throws Exception {
page.setPenColor(this.getPenColor());
page.setPenWidth(this.lineWidth);
drawBorders(page, x, y, w, h);
drawText(page, x, y, w);
}
private void drawBorders(
Page page,
float x,
float y,
float cell_w,
float cell_h) throws Exception {
if (getBorder(Border.TOP) &&
getBorder(Border.BOTTOM) &&
getBorder(Border.LEFT) &&
getBorder(Border.RIGHT)) {
page.drawRect(x, y, cell_w, cell_h);
}
else {
if (getBorder(Border.TOP)) {
page.moveTo(x, y);
page.lineTo(x + cell_w, y);
page.strokePath();
}
if (getBorder(Border.BOTTOM)) {
page.moveTo(x, y + cell_h);
page.lineTo(x + cell_w, y + cell_h);
page.strokePath();
}
if (getBorder(Border.LEFT)) {
page.moveTo(x, y);
page.lineTo(x, y + cell_h);
page.strokePath();
}
if (getBorder(Border.RIGHT)) {
page.moveTo(x + cell_w, y);
page.lineTo(x + cell_w, y + cell_h);
page.strokePath();
}
}
}
private void drawText(
Page page,
float x,
float y,
float cell_w) throws IOException {
String wrappedText = WrapUtil.wrap(super.getText(), this.characterCount);
String[] lines = wrappedText.split(System.getProperty("line.separator"));
float x_text = x + this.left_padding;
float y_text = y + this.font.getAscent() + this.top_padding;
for (String line : lines) {
page.drawString(this.font, line, x_text, y_text);
y_text += this.font.getBodyHeight();
}
}
}
You can instantiate and add the MultilineCell as you would with a Cell:
List<Cell> rowCells = new ArrayList<Cell>();
rowCells.add(new MultilineCell(font, c.getString(reasonIdx), 42));
I know that extension is not a nice solution, and copying drawBorders() is even worse, but in this case, it is the only solution if you don't want to fork PDFJet.
This however breaks autoAdjustColumnWidths: the width is calculated on the whole text, instead of the longest line. So if you intend to use this method, either subclass Table, fork PDFJet, or extract just this method (the only downside of the latter is that I couldn't work around the cell padding though):
/**
* Auto adjusts the widths of all columns so that they are just wide enough to hold the text without truncation.
*/
private static void autoAdjustColumnWidths(List<List<Cell>> tableData) {
// Find the maximum text width for each column
float[] max_col_widths = new float[tableData.get(0).size()];
for (int i = 0; i < tableData.size(); i++) {
List<Cell> row = tableData.get(i);
for (int j = 0; j < row.size(); j++) {
Cell cell = row.get(j);
if (cell.getColSpan() == 1) {
float cellWidth = 0f;
if (cell.getImage() != null) {
cellWidth = cell.getImage().getWidth();
}
if (cell.getText() != null) {
// Is this a multiline cell? If so, measure the widest line
if (cell.getText().contains(MultilineCell.NEW_LINE)) {
String[] lines = cell.getText().split(MultilineCell.NEW_LINE);
for (String line : lines) {
if (cell.getFont().stringWidth(cell.getFallbackFont(), line) > cellWidth) {
cellWidth = cell.getFont().stringWidth(cell.getFallbackFont(), line);
}
}
}
// Standard (single-line) cell, measure whole text
else {
if (cell.getFont().stringWidth(cell.getFallbackFont(), cell.getText()) > cellWidth) {
cellWidth = cell.getFont().stringWidth(cell.getFallbackFont(), cell.getText());
}
}
}
cell.setWidth(cellWidth + 2f /*cell.left_padding*/ + 2f/*cell.right_padding*/);
if (max_col_widths[j] == 0f ||
cell.getWidth() > max_col_widths[j]) {
max_col_widths[j] = cell.getWidth();
}
}
}
}
for (int i = 0; i < tableData.size(); i++) {
List<Cell> row = tableData.get(i);
for (int j = 0; j < row.size(); j++) {
Cell cell = row.get(j);
cell.setWidth(max_col_widths[j]);
}
}
}
PDFJet is a funny library, btw: protected fields, every other method throws Exception, and the classes are definitely not designed for extension, even if there're not final.
There is a tricky solution for that:
As suggested before split your input into several lines (using for example using WordUtils from apache commons lang3)
String wrappedText = WrapUtil.wrap(super.getText(), this.characterCount);
String[] lines = wrappedText.split(System.getProperty("line.separator"));
After you have your lines, add as many rows as lines into your table with those separate lines.
To simulate "multiline cell" call function removeLineBetweenRows providing index of those added rows. It will look like a one big cell.
When I write Android apps, I love the Toast feature. Is there a way to get this kind of set and forget popup message in iPhone development using MonoTouch (C# .NET)?
MonoTouch Toast Version here. Inspired by Android.
To call it,
ToastView t = new ToastView ("Email Sent", 1000);
t.Show ();
Enum File:
public enum ToastGravity
{
Top = 0,
Bottom = 1,
Center = 2
}
ToastSettings File:
using System;
using System.Drawing;
using MonoTouch.UIKit;
namespace General
{
public class ToastSettings
{
public ToastSettings ()
{
this.Duration = 500;
this.Gravity = ToastGravity.Center;
}
public int Duration
{
get;
set;
}
public double DurationSeconds
{
get { return (double) Duration/1000 ;}
}
public ToastGravity Gravity
{
get;
set;
}
public PointF Position
{
get;
set;
}
}
}
Main Toast Class:
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Drawing;
using MonoTouch.ObjCRuntime;
namespace General
{
public class ToastView : NSObject
{
ToastSettings theSettings = new ToastSettings ();
private string text = null;
UIView view;
public ToastView (string Text, int durationMilliseonds)
{
text = Text;
theSettings.Duration = durationMilliseonds;
}
int offsetLeft = 0;
int offsetTop = 0;
public ToastView SetGravity (ToastGravity gravity, int OffSetLeft, int OffSetTop)
{
theSettings.Gravity = gravity;
offsetLeft = OffSetLeft;
offsetTop = OffSetTop;
return this;
}
public ToastView SetPosition (PointF Position)
{
theSettings.Position = Position;
return this;
}
public void Show ()
{
UIButton v = UIButton.FromType (UIButtonType.Custom);
view = v;
UIFont font = UIFont.SystemFontOfSize (16);
SizeF textSize = view.StringSize (text, font, new SizeF (280, 60));
UILabel label = new UILabel (new RectangleF (0, 0, textSize.Width + 5, textSize.Height + 5));
label.BackgroundColor = UIColor.Clear;
label.TextColor = UIColor.White;
label.Font = font;
label.Text = text;
label.Lines = 0;
label.ShadowColor = UIColor.DarkGray;
label.ShadowOffset = new SizeF (1, 1);
v.Frame = new RectangleF (0, 0, textSize.Width + 10, textSize.Height + 10);
label.Center = new PointF (v.Frame.Size.Width / 2, v.Frame.Height / 2);
v.AddSubview (label);
v.BackgroundColor = UIColor.FromRGBA (0, 0, 0, 0.7f);
v.Layer.CornerRadius = 5;
UIWindow window = UIApplication.SharedApplication.Windows[0];
PointF point = new PointF (window.Frame.Size.Width / 2, window.Frame.Size.Height / 2);
if (theSettings.Gravity == ToastGravity.Top)
{
point = new PointF (window.Frame.Size.Width / 2, 45);
}
else if (theSettings.Gravity == ToastGravity.Bottom)
{
point = new PointF (window.Frame.Size.Width / 2, window.Frame.Size.Height - 45);
}
else if (theSettings.Gravity == ToastGravity.Center)
{
point = new PointF (window.Frame.Size.Width / 2, window.Frame.Size.Height / 2);
}
else
{
point = theSettings.Position;
}
point = new PointF (point.X + offsetLeft, point.Y + offsetTop);
v.Center = point;
window.AddSubview (v);
v.AllTouchEvents += delegate { HideToast (null); };
NSTimer.CreateScheduledTimer (theSettings.DurationSeconds, HideToast);
}
void HideToast ()
{
UIView.BeginAnimations ("");
view.Alpha = 0;
UIView.CommitAnimations ();
}
void RemoveToast ()
{
view.RemoveFromSuperview ();
}
}
}
Check this out:
https://github.com/ecstasy2/toast-notifications-ios
Edit: The project has moved to github so i update the link.
Here's my version: http://github.com/scalessec/toast
I think it's simpler to use because it's implemented as a obj-c category, thereby adding the makeToast methods to any instance of UIView. eg:
[self.view makeToast:#"This is some message as toast."
duration:3.0
position:#"bottom"];
Are you looking for something like UIAlertView?
You can use this link for objective-c code for Toast
http://code.google.com/p/toast-notifications-ios/source/browse/trunk/
While this link for its usage
http://code.google.com/p/toast-notifications-ios/wiki/HowToUse
which could be like any one of the below samples
[[iToast makeText:NSLocalizedString(#"The activity has been successfully saved.", #"")] show];
[[[iToast makeText:NSLocalizedString(#"The activity has been successfully saved.", #"")]
setGravity:iToastGravityBottom] show];
[[[[iToast makeText:NSLocalizedString(#"Something to display a very long time", #"")]
etGravity:iToastGravityBottom] setDuration:iToastDurationLong] show];
You might be after Local Notifications, pretty sure they allow you to set a time, I think in epoch time to be fired off. Don't think there is a way to hide them though. I might be misunderstanding your question though cause I'm unfamiliar with Toast.
Just You can use the following code with uilabel and uianimation to get toast like in android.
It does two works one is toast task and it increases the height of the label according to the text length with wordwrap IOS 7 later link here
CGRect initialFrame = CGRectMake(20, self.view.frame.size.height/2,300, 40);
NSString *message=#"Toast in Iphone as in Android";
UILabel *flashLabel=[[UILabel alloc] initWithFrame:initialFrame];
flashLabel.font=[UIFont fontWithName:#"Optima-Italic" size:12.0];
flashLabel.backgroundColor=[UIColor whiteColor];
flashLabel.layer.cornerRadius=3.0f;
flashLabel.numberOfLines=0;
flashLabel.textAlignment=NSTextAlignmentCenter;
CGSize maxSize = CGSizeMake(flashLabel.frame.size.width, MAXFLOAT);
CGRect labelRect = [message boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:flashLabel.font} context:nil];
//adjust the label the the new height.
CGRect newFrame = flashLabel.frame;
newFrame.size.height = labelRect.size.height;
flashLabel.frame = newFrame;
flashLabel.text=message;
[self.view addSubview:flashLabel];
flashLabel.alpha=1.0;
self.view.userInteractionEnabled=FALSE;
[UIView animateWithDuration:13.0 animations:^
{
flashLabel.alpha=0.0f;
}
completion:^(BOOL finished)
{
self.view.userInteractionEnabled=TRUE;
[flashLabel removeFromSuperview];
}];
I modified John's answer as follows:
Toast.h
#interface Toast : NSObject
+ (void)toast:(NSString *)message
:(UIView *) view
:(int)delay;
#end
Toast.m
#import "Toast.h"
#interface Toast ()
#end
#implementation Toast
+ (void)toast:(NSString *)message
:(UIView *) view
:(int)delay
{
CGRect initialFrame = CGRectMake(10, view.frame.size.height/2, 300, 40);
UILabel *flashLabel=[[UILabel alloc] initWithFrame:initialFrame];
flashLabel.font=[UIFont fontWithName:#"Optima-Italic" size:19.0];
flashLabel.backgroundColor=[UIColor whiteColor];
flashLabel.layer.cornerRadius=9.0f;
flashLabel.clipsToBounds = YES;
flashLabel.numberOfLines=3;
flashLabel.textAlignment=NSTextAlignmentCenter;
CGSize maxSize = CGSizeMake(flashLabel.frame.size.width, MAXFLOAT);
CGRect labelRect = [message boundingRectWithSize:maxSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:flashLabel.font}
context:nil];
//adjust the label the the new height.
CGRect newFrame = flashLabel.frame;
newFrame.size.height = labelRect.size.height * 2;
flashLabel.frame = newFrame;
flashLabel.text=message;
[view addSubview:flashLabel];
flashLabel.alpha=1.0;
view.userInteractionEnabled=FALSE;
[UIView animateWithDuration:delay animations:^
{
flashLabel.alpha=0.0f;
}
completion:^(BOOL finished)
{
view.userInteractionEnabled=TRUE;
[flashLabel removeFromSuperview];
}];
}
#end
I have added a little modification to the toast class that handles rotation of the display.
public void Show ()
{
UIButton v = UIButton.FromType (UIButtonType.Custom);
view = v;
UIFont font = UIFont.SystemFontOfSize (16);
SizeF textSize = view.StringSize (text, font, new SizeF (280, 60));
UILabel label = new UILabel (new RectangleF (0, 0, textSize.Width + 5, textSize.Height + 5));
label.BackgroundColor = UIColor.Clear;
label.TextColor = UIColor.White;
label.Font = font;
label.Text = text;
label.Lines = 0;
label.ShadowColor = UIColor.DarkGray;
label.ShadowOffset = new SizeF (1, 1);
v.Frame = new RectangleF (0, 0, textSize.Width + 10, textSize.Height + 10);
label.Center = new PointF (v.Frame.Size.Width / 2, v.Frame.Height / 2);
v.AddSubview (label);
v.BackgroundColor = UIColor.FromRGBA (0, 0, 0, 0.7f);
v.Layer.CornerRadius = 5;
UIWindow window = UIApplication.SharedApplication.Windows[0];
PointF point = new PointF (window.Frame.Size.Width / 2, window.Frame.Size.Height / 2);
if (theSettings.Gravity == ToastGravity.Top)
{
point = new PointF (window.Frame.Size.Width / 2, 45);
}
else if (theSettings.Gravity == ToastGravity.Bottom)
{
point = new PointF (window.Frame.Size.Width / 2, window.Frame.Size.Height - 45);
}
else if (theSettings.Gravity == ToastGravity.Center)
{
point = new PointF (window.Frame.Size.Width / 2, window.Frame.Size.Height / 2);
}
else
{
point = theSettings.Position;
}
point = new PointF (point.X + offsetLeft, point.Y + offsetTop);
v.Center = point;
//handle screen rotation
float orientation=0;
switch(UIApplication.SharedApplication.StatusBarOrientation)
{
case UIInterfaceOrientation.LandscapeLeft:
orientation=-90;
break;
case UIInterfaceOrientation.LandscapeRight:
orientation=90;
break;
case UIInterfaceOrientation.PortraitUpsideDown:
orientation=180;
break;
}
v.Transform=CGAffineTransform.MakeRotation ((float)(orientation / 180f * Math.Pi));
window.AddSubview (v);
v.AllTouchEvents += delegate { HideToast (); };
NSTimer.CreateScheduledTimer (theSettings.DurationSeconds, HideToast);
}
You could try my open source library TSMessages: https://github.com/toursprung/TSMessages
It's really easy to use and looks beautiful on iOS 5/6 and on iOS 7 as well.
I really like MonoTouch solution proposed by Bahai.
The following is not a substitution. Is just a ready-to-go one method the worked for me.
private async Task ShowToast(string message, UIAlertView toast = null)
{
if (null == toast)
{
toast = new UIAlertView(null, message, null, null, null);
toast.Show();
await Task.Delay(2000);
await ShowToast(message, toast);
return;
}
UIView.BeginAnimations("");
toast.Alpha = 0;
UIView.CommitAnimations();
toast.DismissWithClickedButtonIndex(0, true);
}
If the method is called from a background thread (not the main UI thread) then BeginInvokeOnMainThread is required which means just call it like this.
BeginInvokeOnMainThread(() =>
{
ShowToast(message);
});
I created a new repo on github with a class to do iOS toast-style alerts. I didn't like the one on code.google.com, it didn't rotate properly and wasn't pretty.
https://github.com/esilverberg/ios-toast
Enjoy folks.