How to resize drawable/Imagespan in a textview/spannable string - kotlin

I'm trying to add some images to a textview, and found out how to do that simple enough using Spannable String. Works fine, however, if I want to resize the image (either smaller than original, or larger than original), I can't seem to get it to resize.
There's some other similar questions that seem to answer this, however, trying to convert them to Kotlin, I'm unable to get anything to work.
How to display image in Android's TextView?
Reduce ImageSpan height and width
This is what I have at this point:
// build images/text together
val is1 = ImageSpan (this, android.R.drawable.ic_menu_compass)
val is2 = ImageSpan (this, android.R.drawable.ic_menu_compass)
//is2.drawable.setBounds(500,500,1000,1000)
is2.drawable.setBounds(0,0,txtInfo.lineHeight*4,txtInfo.lineHeight*4)
val s = SpannableStringBuilder()
.append("Test line 1")
.append("\n")
.append(" ", is1, 0)
.append("\n")
.append("Test line 2")
.append("\n")
.append(" ", is2, 0)
.append("\n")
.append("Test line 3")
txtInfo.text = s
but both options using setBounds don't seem to result in any change. Ie the 2 images of the compass appear exact same size.
How to resize these images (either to fixed size or otherwise) in Kotlin ?

Related

mpandroidchart the dot's color doesn't change in scatter chart

I'm using MPandroidchart to draw scatter chart.
I want to make a scatter chart that has a base line.
If value over the base line, in my case 0.2, its color change to red.
If not, it color is blue.
This is the codes i did.
if (d>=0.5)
{
colors.add(getBaseContext().getResources().getColor(R.color.color_red));
} else
{
colors.add(getBaseContext().getResources().getColor(R.color.color_blue));
}
value1.add(new Entry(k,d));
But it didn't change dot's color, but change squre's color next to label
I have tried
1)
if(index == specificIndex) colors.add(Color);
else colors.add(NormalColor);
2)
ArrayList<Integer> color = new ArrayList<>();
if (YOUR_CONDITION) {
color.add(ColorTemplate.rgb("#f8bf94"));
yVals1.add(new Entry(VALUE, COUNTER));
} else {
color.add(ColorTemplate.rgb("#e0e0e0"));
yVals1.add(new Entry(VALUE, COUNTER));
}
set1.setColors(color);
3)
color.add(Color.RED);
color.add(context.getResources().getColor(R.color.your_defined_color_in_colors_xml));
dataSet.setCircleColors(color);
But it didn't work.
How can i solve this?
After spending hours with this same issue, I have realized that it is the result of a bug in the MPAndroidChart project.
Basically, in the ScatterChartRenderer, the colors array is being treated such that only even colors are being applied to data points. For each Entry i, the color is set to colors[i / 2] meaning that the same color will be applied to two different entries due to integer division. This results in only half of the colors array being used.
To resolve this issue quickly, my solution was to add each entry to the DataSet twice. This means two points are drawn on top of each other, but both have the proper color set.
I am submitting a pull request to hopefully fix this issue in the next release, but for now this quick hack should work.

iText - PDFAppearence issue

We're using iText to put a text inside a signature placeholder in a PDF. We use a code snippet similar to this to define the Signature Appearence
PdfStamper stp = PdfStamper.createSignature(inputReader, os, '\0', tempFile2, true);
sap = stp.getSignatureAppearance();
sap.setVisibleSignature(placeholder);
sap.setRenderingMode(PdfSignatureAppearance.RenderingMode.DESCRIPTION);
sap.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
Calendar cal = Calendar.getInstance();
sap.setSignDate(cal);
sap.setLayer2Text(text+"\n"+cal.getTime().toString());
sap.setReason(text+"\n"+cal.getTime().toString()); `
Everything works fine, but the signature text does not fill all the signature placeholder area as expected by us, but the area filled seems to have an height that is approximately the 70% of the available space.
As a result, sometimes especially if the length of the signature text is quite big, the signature text does not fit in the placeholder and the text is striped away.
Example of filled Signature:
I looked into the PdfSignatureAppearence class and I found this code snippet in the getApperance() method that is responsible of this behaviour and is invoked when
sap.setRenderingMode(PdfSignatureAppearance.RenderingMode.DESCRIPTION);
is being called
else {
dataRect = new Rectangle(
MARGIN,
MARGIN,
rect.getWidth() - MARGIN,
rect.getHeight() * (1 - TOP_SECTION) - MARGIN);
}
I don't get the reason for that, because I expect that the text could use all the available placeholder height, with the proper margin.
Is there any way to bypass this behaviour?
We are using iText 5.4.2, but also newer version contains same code snippet so I expect that the behaviour will be same.
As #JJ. already commented,
TOP_SECTION is connected with acro6layers rendering and the code [determining the datarect in pure DESCRIPTION mode] does not take into account the value of the acro6layer flag.
Unless one wants to fix this in the iText 5 code itself, the easiest way to make one's description use the whole signature space is to construct the layer 2 appearance oneself.
To do so one merely has to retrieve a PdfTemplate from PdfSignatureAppearance.getLayer(2) and fill it as desired after one has called PdfSignatureAppearance.setVisibleSignature. The PdfSignatureAppearance remembers that you already have retrieved the layer 2 and doesn't change it anymore.
For the case at hand we essentially copy the PdfSignatureAppearance.getAppearance code for generating layer 2 in pure DESCRIPTION mode, merely correcting the code determining the datarect:
PdfSignatureAppearance appearance = ...;
[...]
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
PdfTemplate layer2 = appearance.getLayer(2);
String text = "We're using iText to put a text inside a signature placeholder in a PDF. "
+ "We use a code snippet similar to this to define the Signature Appearence.\n"
+ "Everything works fine, but the signature text does not fill all the signature "
+ "placeholder area as expected by us, but the area filled seems to have an height "
+ "that is approximately the 70% of the available space.\n"
+ "As a result, sometimes especially if the length of the signature text is quite "
+ "big, the signature text does not fit in the placeholder and the text is striped "
+ "away.";
Font font = new Font();
float size = font.getSize();
final float MARGIN = 2;
Rectangle dataRect = new Rectangle(
MARGIN,
MARGIN,
appearance.getRect().getWidth() - MARGIN,
appearance.getRect().getHeight() - MARGIN);
if (size <= 0) {
Rectangle sr = new Rectangle(dataRect.getWidth(), dataRect.getHeight());
size = ColumnText.fitText(font, text, sr, 12, appearance.getRunDirection());
}
ColumnText ct = new ColumnText(layer2);
ct.setRunDirection(appearance.getRunDirection());
ct.setSimpleColumn(new Phrase(text, font), dataRect.getLeft(), dataRect.getBottom(), dataRect.getRight(), dataRect.getTop(), size, Element.ALIGN_LEFT);
ct.go();
(CreateSignature.java test signWithCustomLayer2)
(As description text I used some paragraphs from the question body.)
The result:
By adapting the MARGIN value in the code above, one can even use more are. As that can result in the text touching the border, though, that might not be really beautiful.
As an aside:
if the length of the signature text is quite big, the signature text does not fit in the placeholder and the text is striped away.
If you initialize the size variable above with a non-positive value, the code in the if (size <= 0) block will calculate a font size which allows all of the text to fit into the signature rectangle. This does happen in the code above as new Font() returns a font with a size of UNDEFINED which is a constant -1.

Windows XAML: LineCount in TextBlock?

I have a Text Block that I write on a Canvas. Since it is on a Canvas, I manually specify x-coord and y-coord.
My problem is, my y-coord is dependent on the LineCount of the wrapping on my TextBlock (due to limited width).
For example, the text "ADD Bananas" is written as:
ADD
Bananas
which has 2 line count.
Depending on the line count, I do something.
Right now, I am using this to determine the TextWidth and then do calculations from there. However, there are still some outliers (ex. instead of supposed to be 3 lines calculated, 2 in actual visual):
private double stringWidth(string s, double fontSize)
{
if(s==" ")
s = "\u00A0"; //this line wasn't required in silverlight but is now
TextBlock t = new TextBlock()
{
FontSize = fontSize,
Text = s
};
t.Measure(new Size(double.MaxValue, double.MaxValue)); //this line wasn't required in silverlight but is now
return t.ActualWidth;
}
Is there a best way to do this in Windows App Xaml?

ios-charts How to invalidate/redraw after setting data

See Updates At Bottom (4/30/2015)
I'm implementing a Pie Chart in Swift for iOS using ios-charts, and have chosen to customize the legend. Of note, the chart is displayed within a cell of a UICollectionView. The problem is that on first display, the custom legend content is not being displayed. Instead, I get legend content generated from the data.
If I scroll the view off-screen, and then scroll it back onto the screen, the proper custom legend is displayed. So, I'm guessing that I need to force a redraw/relayout/re-something after setting my custom legend. I haven't figured out how to do that. Does anyone have an idea? Am I completely missing something? Thanks!
Chart on initial display - data-generated (wrong) legend
Chart after scrolling off and back onto the screen - (proper legend)
Here's my code for drawing this chart:
func initChart(pieChart: PieChartView) {
numFormatter.maximumFractionDigits = 0
pieChart.backgroundColor = UIColor.whiteColor()
pieChart.usePercentValuesEnabled = false
pieChart.drawHoleEnabled = true
pieChart.holeTransparent = true
pieChart.descriptionText = ""
pieChart.centerText = "30%\nComplete"
pieChart.data = getMyData()
// Setting custom legend info, called AFTER setting data
pieChart.legend.position = ChartLegend.ChartLegendPosition.LeftOfChartCenter
pieChart.legend.colors = [clrGreenDk, clrGold, clrBlue]
pieChart.legend.labels = ["Complete","Enrolled","Future"]
pieChart.legend.enabled = true
}
func getMyData() -> ChartData {
var xVals = ["Q201","R202","S203","T204","U205", "V206"]
var courses: [ChartDataEntry] = []
courses.append(ChartDataEntry(value: 3, xIndex: 0))
courses.append(ChartDataEntry(value: 3, xIndex: 1))
courses.append(ChartDataEntry(value: 4, xIndex: 2))
courses.append(ChartDataEntry(value: 4, xIndex: 3))
courses.append(ChartDataEntry(value: 3, xIndex: 4))
courses.append(ChartDataEntry(value: 3, xIndex: 5))
let dsColors = [clrGreenDk, clrGreenDk, clrBlue, clrBlue, clrGold, clrGold]
let pcds = PieChartDataSet(yVals: courses, label: "")
pcds.sliceSpace = CGFloat(4)
pcds.colors = dsColors
pcds.valueFont = labelFont!
pcds.valueFormatter = numFormatter
pcds.valueTextColor = UIColor.whiteColor()
return ChartData(xVals: xVals, dataSet: pcds)
}
Update 4/30/2015
Based on discussion with author of MPAndroidChart (on which ios-charts is based), it appears there is not a point in the chart display lifecycle where one can override the legend on "first draw". Basically, the chart is rendered when it is created, no matter what. If you set data on the chart, the chart uses that data to create the legend and then renders. It isn't possible to change the legend between the point of setting data, and the point of chart rendering.
setNeedsDisplay()
Potentially, one can wait for the chart to render, update the legend, and then call chart.setNeedsDisplay() to signal the chart to redraw. Sadly, there's a timing problem with this. If you call this method immediately after rendering the chart, it either doesn't fire or (more likely) it fires too soon and is effectively ignored. In my code, placing this call within viewDidLoad or viewDidAppear had no effect. However...
Building the same chart in Java for Android (using MPAndroidChart) results in the same issue. After messing around for a bit, I noted that if I called the chart.invalidate() after a delay (using Handler.postDelayed()), it would fire properly. It turns out a similar approach works for ios-charts on iOS.
If one uses GCD to delay the call to setNeedsDisplay(), for even a few milliseconds after the rendering, it seems to do the trick. I've added the following code immediately after initializing the chart's view in my ViewController ("cell" is the UICollectionViewCell containing the chart view):
delay(0.05) {
cell.pieChartView.legend.colors = [self.clrGreenDk, self.clrGold, self.clrBlue]
cell.pieChartView.legend.labels = ["Complete","Enrolled","Future"]
// Re-calc legend dimensions for proper position (Added 5/2/2015)
cell.pieChartView.legend.calculateDimensions(cell.pieChartView.labelFont!)
cell.pieChartView.setNeedsDisplay()
}
Using the awesome "delay" method from this SO post: https://stackoverflow.com/a/24318861
Obviously, this is a nasty hack, but it seems to do the trick. I'm not sure I like the idea of using this hack in production, though.
For any Android folk who stumble on this post:
The following code achieves the same effect using MPAndroidChart:
// Inside onCreate()
pie = (PieChart) findViewById(R.id.chart1);
configPieChart(pie);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
String[] legLabels = new String[]{"Complete","Enrolled","Future"};
ArrayList<Integer> legColors = new ArrayList<Integer>();
legColors.add(blue);
legColors.add(gold);
legColors.add(green);
pie.getLegend().setPosition(Legend.LegendPosition.LEFT_OF_CHART_CENTER);
pie.getLegend().setColors(legColors);
pie.getLegend().setLabels(legLabels);
pie.invalidate();
}
}, 20);
I am the author of ios-charts, and we're working on features for customizing the legend data, without those "hacks".
In the latest commits to ios-charts, you can already see extraLabels and extraColors properties that add extra lines to the legend, and a setLegend function that allows you to set a custom data entirely.
This will soon be added to the Android version as well.
Enjoy :-)

Add flat amount to canvas size

I want to have some automated process (either action or script) that will copy selection(assumes something has already been selected), place in new canvas, increase canvas size by exactly 10 pixels in height & width, then save it to the desktop.
I'm currently using an action and it works correctly with the exception of the 10 pixels part. I can do something like 10% by using the percentage adjustment in the canvas size menu, but I can't figure out how to do exactly 10 pixels. During the recording, if I just increase the canvas size by 10 pixels it'll record that exact amount (say it was 100x100, it records that I resized canvas to 110x100). So when I play that action on a selection that's of size 50x50 it resizes it to 110x110.... So the problem is that the action records the literal value of the canvas resize and not the add 10 pixels part...
Any ideas here?
This can be scripted as well, but if you've already got an action set up, try modifying your action to do the following:
paste the selection into new document larger than you expect to ever require
expand the selection by 10 px
crop the document to the selection
save
Or, to script it you can tweak the following sample. It assumes you have already copied your image to the clipboard:
#target photoshop
app.preferences.rulerUnits = Units.PIXELS;
app.preferences.typeUnits = TypeUnits.PIXELS;
var doc = app.documents.add('1000px');
var lyr = doc.artLayers.add();
doc.activeLayer = lyr;
doc.paste ();
var bnds = lyr.bounds;
var unitsToAdd = new UnitValue(10, 'px');
bnds[0] = bnds[0] - unitsToAdd;
bnds[1] = bnds[1] - unitsToAdd;
bnds[2] = bnds[2] + unitsToAdd;
bnds[3] = bnds[3] + unitsToAdd;
doc.crop(bnds) ;
doc.saveAs(new File('/c/temp/temp.psd'));