I created a activity with 9 grey blocks on background using the following code:
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(5);
canvas.drawLine(width/3, 0, width/3, height, paint);
canvas.drawLine((2*width)/3, 0, (2*width)/3, height, paint);
canvas.drawLine(0, height/3, width, height/3, paint);
canvas.drawLine(0, (2*height/3), width , (2*height)/3, paint);
Log.d("game","in draw");
ImageView imageView = new ImageView(this);
imageView.setImageBitmap(bitmap);
layout = new RelativeLayout(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
layout.setId(1);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
layout.addView(imageView, params);
layout.setBackgroundColor(Color.BLACK);
Log.d("game","before content view");
// Show this layout in our activity.
setContentView(layout);
So i have created an layout purely by code.
Now I want to link this layout with an xml file such that any change in that file or in the code will be also seen in the activity. How to do so.
You can if class extend from Activity,ListActivity,...etc.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
You can change or add layout to code:
setContentView(R.layout.activity_main); //activity_main is Layout you can change it
Related
I have a TextView which contains dynamic text (of varying length). In order to enable smooth pinch and zoom, I would like to convert this TextView to an ImageView and display that ImageView instead of the TextView. So I tried to set up the TextView programmcially like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song_view);
String text = getIntent().getStringExtra(SongbookListFragment.SONG_TEXT_ARGS);
song_textview = new AppCompatTextView(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
song_textview.setLayoutParams(layoutParams);
song_textview.setPadding(PADDING,PADDING,PADDING,PADDING);
song_textview.setText(Html.fromHtml(text));
song_textview.setTextColor(Color.BLACK);
song_textview.setBackgroundColor(Color.TRANSPARENT);
song_textview.setHorizontallyScrolling(true);
song_textview.setTextSize(16);
}
My song_view.xml uses the zoomable PhotoView which extends ImageView:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<com.github.chrisbanes.photoview.PhotoView
android:id="#+id/imageview_songtext"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</ScrollView>
Now in onWindowFocusChanged method of the activity, I convert the TextView to a Bitmap and display it within the PhotoView like this:
#Override
public void onWindowFocusChanged(boolean hasFocus){
super.onWindowFocusChanged(hasFocus);
int width = this.getWindow().getDecorView().getWidth();
int height = this.getWindow().getDecorView().getHeight();
Bitmap bitmapHolder = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmapHolder);
if (song_textview != null) {
song_textview.layout(0, 0, width, height);
song_textview.draw(c);
PhotoView songPhotoView = findViewById(R.id.imageview_songtext);
songPhotoView.setImageBitmap(bitmapHolder);
}
}
This works well except that I do not know how to set the height of the Bitmap within onWindowFocusChanged. If I use this.getWindow().getDecorView().getHeight() like in my code sample above, the length of the text is cut because this.getWindow().getDecorView().getHeight() returns the screen height and not the actual height of the TextView. Of course, the TextView is not added to the layout which is why there is no measured height. So how can I get the full length of the TextView to display it in my Bitmap?
Just call below setText method.
public void setText(String text){
Paint paint = new Paint();
paint.setTextSize(30);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
Rect result = new Rect();
paint.getTextBounds(text, 0, text.length(), result);
int width= result.width();
//background color red
int color=Color.RED;
Bitmap img=drawText(text, width, color);
songPhotoView.setImageBitmap(img);
//background transparent
int colorT=Color.TRANSPARENT;
Bitmap img1=drawText(text,width,colorT);
songPhotoView.setImageBitmap(img1);
}
public Bitmap drawText(String text, int textWidth, int color) {
// Get text dimensions
TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
textPaint.setStyle(Paint.Style.FILL);
textPaint.setColor(Color.parseColor("#ff00ff"));
textPaint.setTextSize(30);
StaticLayout mTextLayout = new StaticLayout(text, textPaint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
// Create bitmap and canvas to draw to
Bitmap b = Bitmap.createBitmap(textWidth, mTextLayout.getHeight(), Bitmap.Config.ARGB_4444);
Canvas c = new Canvas(b);
// Draw background
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setColor(color);
c.drawPaint(paint);
// Draw text
c.save();
c.translate(0, 0);
mTextLayout.draw(c);
c.restore();
return b;
}
I need to create a canvas in which i have add two images as BITMAP and a TEXTVIEW at the bottom right with multiple line.
Here is my code which i have tried -
drawnBitmap = Bitmap.createBitmap(1000, 1500, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(drawnBitmap);
canvas.drawColor(getResources().getColor(R.color.creamColor));
// JUST CHANGE TO DIFFERENT Bitmaps and coordinates .
canvas.drawBitmap(b, 0, 0, null);
canvas.drawBitmap(b2, 630, 250, null);
//for more images :
// canvas.drawBitmap(b3, 0, 0, null);
// canvas.drawBitmap(b4, 0, 0, null);
/*Draw text*/
//TextPaint paintText=new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
Paint paintText = new Paint(Paint.ANTI_ALIAS_FLAG);
paintText.setColor(Color.BLACK);
paintText.setTextAlign(Paint.Align.CENTER);
paintText.setTextSize(50);
Typeface tf;
tf = Typeface.createFromAsset(getAssets(), "HelveticaNeueLTStd-Lt.otf");
paintText.setTypeface(tf);
RelativeLayout layout = new RelativeLayout(this);
layout.setBackgroundColor(Color.GREEN);
layout.setDrawingCacheEnabled(true);
TextView textView = new TextView(this);
textView.setVisibility(View.VISIBLE);
textView.setText(INNERTEXT);
textView.setTextSize(30);
textView.setWidth(300);
textView.setTextColor(Color.BLACK);
textView.setTypeface(tf);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
layout.setLayoutParams(params);
textView.setGravity(Gravity.CENTER);
layout.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
layout.addView(textView);
layout.measure(canvas.getWidth(), canvas.getHeight());
layout.layout(0, 0, canvas.getWidth(), canvas.getHeight());
// To place the text view somewhere specific:
// canvas.translate(500, 750);
canvas.drawBitmap(layout.getDrawingCache(), 500, 750, null);
// layout.draw(canvas);
I have divided the canvas into 4 equal parts, but the textview inside the 4. part is not centered.
how can I display a programmatically created ImageView on top of a previously created View Canvas? I tried using bringToFront(), but without success.
Code:
RelativeLayout root = findViewById(R.id.layout);
ImageView img = new ImageView(GameGuessActivity.context);
img.setImageResource(R.drawable.image);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height);
params.leftMargin = x;
params.topMargin = y;
root.addView(img, params);
img.bringToFront();
The Image is being displayed, but underneath the canvas, which I don't want.
You have to redraw your imageview on canvas:
pcanvas = new Canvas();
pcanvas.setBitmap(bitmap); // drawXY will result on that Bitmap
pcanvas.drawBitmap(bitmap, 0, 0, null);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
image.draw(pcanvas);
img.bringToFront();
img.invalidate();
img.draw(pcanvas);
I have a simple activity with a green background and I am trying to provide a red overlay with a transparent circular area. Here is the effect I am trying to accomplish:
Expected Image
With the code I have found on the internet, this is what I see:
Result of code
What appears to be happening is PorterDuff applies itself to all views in the activity instead of the one that I distinctly tell it to. Many of the posts on Stack have been about masking a bitmap with another bitmap and I am trying to mask an part of a view with a programmatically created circular shape. Here is the code I am attempting to use:
public class ClippingTestActivity extends Activity {
private Paint mPaint;
ClippingView ddd;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.test);
View v = new View(this.getBaseContext());
v.setBackgroundColor(Color.GREEN);
this.addContentView(v, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
ClippingView r = new ClippingView(this.getBaseContext());
r.setBackgroundColor(Color.RED);
this.addContentView(r, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
}
}
public class ClippingView extends View {
Paint paint = new Paint();
Path path = new Path();
public ClippingView(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw( canvas );
paint.setColor(Color.TRANSPARENT);
paint.setStyle(Style.FILL);
paint.setXfermode( new PorterDuffXfermode( Mode.CLEAR ) );
int cx = 200;
int cy = 200;
int radius = 50;
canvas.drawCircle( cx, cy, radius, paint );
}
}
with the layout xml file being as such
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.appspot.scruffapp"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:background="#ff0000">
</RelativeLayout>
Does anyone know how to accomplish the effect?
Okay. With the help of a friend I figured it out. Turns out I needed to create a new canvas that was empty and pass that around from function to function and draw the canvas on a new view which gets added later. This is the code that worked for me:
Bitmap circle = DrawView.makeCircle(drawable);
Bitmap overlayBg = DrawView.makeOverlayBg(canvas.getWidth(),canvas.getHeight());
Bitmap finalImage = Bitmap.createBitmap(canvas.getWidth(),canvas.getHeight(), Bitmap.Config.ARGB_8888);
final android.graphics.Canvas tmpCanvas = new android.graphics.Canvas(finalImage);
tmpCanvas.drawBitmap(overlayBg, 0, 0, null);
final android.graphics.Paint paint = new android.graphics.Paint();
paint.setXfermode(new android.graphics.PorterDuffXfermode(Mode.DST_OUT));
tmpCanvas.drawBitmap(circle, cx - radius, cy - radius, paint);
canvas.drawBitmap(finalImage, 0, 0, null);
I'm successfully converting a ViewGroup (RelativeLayout) into Bitmap using a Canvas. However, when the draw happens I only see the ViewGroup with its background drawable and not its children (two TextViews) who should be laid out within the RelativeLayout using rules like FILL_PARENT.
The RelativeLayout is created using the following static function:
public static RelativeLayout createProgrammeView(Context context, int width, int height, String title, String time) {
RelativeLayout.LayoutParams params;
// Layout Root View (RelativeLayout)
RelativeLayout rlv = new RelativeLayout(context);
params = new RelativeLayout.LayoutParams(width, height);
rlv.setLayoutParams(params);
rlv.setPadding(3, 3, 3, 3);
rlv.setBackgroundResource(R.drawable.background);
// Layout Title
TextView tv = new TextView(context);
params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
tv.setId(R.id.title);
tv.setLayoutParams(params);
tv.setGravity(Gravity.CENTER_VERTICAL);
tv.setSingleLine(true);
tv.setEllipsize(TruncateAt.END);
tv.setTextColor(Color.parseColor("#fff"));
tv.setTextSize(11);
tv.setText(title);
rlv.addView(tv);
// Layout Start Time
tv = new TextView(context);
params = new RelativeLayout.LayoutParams(16, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, R.id.title);
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
params.setMargins(0, 4, 0, 0);
tv.setId(R.id.time);
tv.setLayoutParams(params);
tv.setGravity(Gravity.CENTER_VERTICAL);
tv.setSingleLine(true);
tv.setEllipsize(null);
tv.setTextColor(Color.parseColor("#fff"));
tv.setTextSize(10);
tv.setText(time);
rlv.addView(tv);
}
return rlv;
}
I then use the following to turn the RelativeLayout into a Bitmap:
public static Bitmap loadBitmapFromView(RelativeLayout v) {
Bitmap b = Bitmap.createBitmap(v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(b);
v.draw(c);
return b;
}
As expected this gives me a nice Bitmap in the dimensions that I require with the background drawable, but the children are not in the bitmap. I call these functions quite a lot to build a large image which then gets drawn onto a custom view in my activity.
This is the loop which calls the static function:
public static void renderViews(final Context context) {
largeBitmap = Bitmap.createBitmap(largeWidth, largeHeight, Bitmap.Config.RGB_565);
Canvas largeCanvas = new Canvas(largeBitmap);
for (int i = 0; i < items.size(); i++) {
int leftMargin = ...SOME CALCULATIONS...;
RelativeLayout newView = createProgrammeView(context, width, rowHeight, "Title", "21:00");
Bitmap newViewBitmap = loadBitmapFromView(newView);
largeCanvas.drawBitmap(newViewBitmap, leftMargin, 0, new Paint());
}
myCustomView.invalidate();
}
My custom view overrides the onDraw() function:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(largeBitmap, 0, 0, null);
}
From what I can see I believe this is because Android doesn't call a measure() on the child Views. I have tried calling this manually, but this doesn't solve the problem.
So, I guess what I would like to know is, how can I achieve converting a RelativeLayout with children into a Bitmap and get Android to measure the children so they respect their relative layout rules.
Many thanks to anyone who can help me work this out.
Rob
The problem is that you did not measure and layout the container. You must call v.measure(widthSpec, heightSpec) and then v.layout(left, top, right, bottom) before drawing can work. The first method will make sure the view knows how big you want it to be, and the second method will ensure the children are positioned properly.
In your case you would do:
v.measure(MeasureSpec.makeMeasureSpec(v.getLayoutParams().width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(v.getLayoutParams().height, MeasureSpec.EXACTLY));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.RGB_565);
Canvas c = new Canvas(b);
v.draw(c);
Solution that based on DisplayMetrics for the Layouts could be useful as well. In order not to repeat - look here .