Is it possible to use standart View in custom LinearLayout - android

I would like to add TextView and EditView into my custom LinearLayout programmatically.
But I don't know how.
Something like this (that doesn't work):
<com.custom.FavoritesViewer
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"
android:id="#+id/favoritesViewer">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"/>
</com.custom.FavoritesViewer>
and my custom layout
public class FavoritesViewer extends LinearLayout {
private Bitmap fullImage;
private int canvasWidth;
private int canvasHeight;
private final Paint paint = new Paint();
public FavoritesViewer(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
initializeCanvasSize(context);
}
private void initializeCanvasSize(Context context) {
final Pair<Integer, Integer> screenSize = Utils.getScreenSize(context);
canvasWidth = screenSize.first;
canvasHeight = screenSize.second;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(canvasWidth, canvasHeight / 3);
}
#Override
protected void onDraw(Canvas cvs) {
if (fullImage == null) {
fullImage = Bitmap.createBitmap(canvasWidth, canvasHeight / 3, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(fullImage);
paint.reset();
paint.setColor(Color.parseColor("#AA000000"));
canvas.drawRect(0, 0, canvasWidth, canvasHeight / 3, paint);
}
cvs.drawBitmap(fullImage, 0, 0, null);
}
}
So I have a canvas (like background) and I would like to add some standart Views on top. I cannot add it on onDraw.
Is it any way to add View into custom Layout?
EDITTED
I need to implement some special UI with buttons. I want to wrap this in one component. I draw that UI on canvas and somehow should add buttons (It's enough for me to add simple ImageButton, not to draw an image and emulate button's behaviour). That's why I selected Layout as container and need to add Views programmatically.

As long as you call through to super (probably super.onDraw()), I imagine the parent class will draw the views you add as expected. It looks like you're just overriding onDraw, which would prevent the parent LinearLayout class from rendering it's content (like the TextView).
Try commenting out your onDraw method first, and see if the LinearLayout behaves as expected.
Also, what's the goal of the Custom Layout? There may be a better way to achieve your goal.

Related

Custom view within recyclerview not drawn after scroll

I have a custom view, which draws a concave shape (visualized with red rectangle on screenshot). This custom view is a part of my recycler view element layout, which also contains a plain view with background color (right part).
This is an extract of my custom view (without rotation, but same drawing methods):
public class InvertedCircleView extends View {
private Paint mPaint;
private float mCanvasCenterX;
private float mCenterCircleWidth, mCenterCircleHeight;
public InvertedCircleView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
[...]
mPaint.setStyle(Paint.Style.FILL);
canvas.drawPaint(mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mCenterCircleWidth = canvas.getWidth();
mCenterCircleHeight = canvas.getHeight();
mCanvasCenterX = canvas.getWidth() / 2;
canvas.drawOval(mCanvasCenterX - (mCenterCircleWidth / 2),
-mCenterCircleHeight,
mCanvasCenterX + (mCenterCircleWidth / 2),
mCenterCircleHeight,
mPaint);
}
}
When the recyclerview shows up the first time, everything looks fine. But when i scroll down (or up), the custom view part is not visible on all the new elements.
What i have tested so far:
setItemViewCacheSize -> this helps, but when i scroll up again, it shows the same bad result
notifyDataSetChanged -> this directly results in the "wrong" visualization for all elements
What may be the reason for this behaviour?
Found my mistake:
I used "mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));" in the onDraw-function. But i forgot to reset Xfermode in the end.
I added the line " mPaint.setXfermode(null);" and everything works as expected :)

Only Draw background where Children Views are not?

I'm trying to prevent over-draw in my app, and in one of the root views I'd like to detect the location of my children views, and then draw a background for where they are not. From my understanding, clipping would clip outside of the path, but what I'd really like to do is not draw at certain locations on the screen where the children are. Is there a good way to do this?
EDIT:
So I haven't played with canvas in a while, but I'm looking to do something like this:
public class ContainerView extends FrameLayout {
private final Paint mBackgroundPaint = new Paint();
private final Path mPath = new Path();
public ContainerView(Context context, AttributeSet attrs) {
super(context, attrs);
mBackgroundPaint.setColor(context.getResources().getColor(R.color.default_background));
}
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPaint(mBackgroundPaint);
mPath.reset();
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
mPath.addRect(child.getLeft(), child.getTop(), child.getRight(), child.getBottom(),
Path.Direction.CCW); // What direction do I want?
}
canvas.clipPath(mPath);
}
}
clipPath just wont do what I want though, I don't think. I think that would clip outside the path, and I need to clip inside the path.
You'd probably want to do something like override onLayout and at the end of it:
iterate over all your child views
check if the child is visible/opaque
build up a list of each child's position/size
use that list to do your own background clipping

How to understand where you put your widgets in android layouts programmatically?

I'm currently making a simple game with the surfaceview but I find it hard to position the buttons or texts within the Relative layout programmatically in android. For example, in the sample below Im setting the relativelayouts with texts in a relative layout, and I want to set it to the right side of the screen with few margins to the right. How should I understand where I'm positioning the contents ? And are there some tips on positioning contents programmatically?
RelativeLayout Rs = new RelativeLayout(this);
Rs.setBackgroundResource(R.drawable.btn);
Rs.setGravity(Gravity.CENTER);
Regame.addView(RR,400,150);
Rs.setX(0);
txt= new TextView(this);
I guess it would be sufficient if you accessed the canvas from within the surfaceView.Probably would be more efficient if you used onSizeChange
for the width and height but i guess the canvas getWidth and getHeight would suffice.Also my example is just drawing once the surface is created, you'll have to make your own update logic.Also i am ditching the relative layout but i think this could suffice your needs:
public class GameView extends SurfaceView {
protected SurfaceHolder holder;
public GameView(Context context) {
super(context);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
Canvas c = holder.lockCanvas(null);
onDraw(c);
holder.unlockCanvasAndPost(c);
}
});
}
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(20);
int width=canvas.getWidth();
int height=canvas.getHeight();
//Just for example
int desiredHeight=height/2;
int desiredMargin=10;
String desiredText="Some text";
int textWidth=Math.round(paint.measureText(desiredText));
int desiredWidth=width-textWidth-desiredMargin;
canvas.drawText(desiredText, desiredWidth,desiredHeight, paint);
}
}

Android:Why after override onMeasure() in a custom view, the view's text can't show in RalativeLayout?

I made a custom component that extends View and overrides its onMeasure(), the content of this component is some text, then I add it to a RelativeLayout, but this text can't display, if I comment onMeasure() that been overridden the text shows. What's the reason?
Here is the code:
public class CustomView extends View {
private String text;
private int viewWidth;
private int viewHeight;
private Paint paint;
private FontMetrics fontMetrics;
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, String text) {
this(context, text, 0);
this.text = text;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
updateViewBounds();
}
public CustomView(Context context, String text, int defStyle) {
super(context);
}
private void updateViewBounds(){
viewWidth = (int) paint.measureText(this.text);
fontMetrics = paint.getFontMetrics();
viewHeight = (int)(fontMetrics.descent - fontMetrics.ascent);
}
private String getText() {
return this.text;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(viewWidth, viewHeight);
//setMeasuredDimension(560, 100);even though give a ensured size, it can't //anyway.
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.WHITE);
paint.setTextSize(30);
canvas.drawText(text, 0, 200, paint);
Log.e("content", ""+this.getText());
}
public boolean onTouchEvent (MotionEvent event){
Log.e("Touch", ""+this.getText());
return false;
}
}
Here is the Activity:
public class CustomViewActivity extends Activity {
/** Called when the activity is first created. */
private RelativeLayout contentLayout;
private CustomView view1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
contentLayout = (RelativeLayout)findViewById(R.id.contentLayout);
view1 = new CustomView(this, "You drive me crazy!!!");
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
view1.setLayoutParams(layoutParams);
contentLayout.addView(view1);
}
}
this is the XML file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/contentLayout"
android:layout_width="1024px"
android:layout_height="560px"
android:orientation="vertical" >
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginLeft="126dp"
android:text="Button" />
</RelativeLayout>
You can absolutely set the MeasureSpec to a different size, however, the arguments for onMeasure are misleading. A MeasureSpec is a specially translated int that has to be specifically created by using both a pixel measure and a flag. The correct way to set a specific size it indicated below...
final int desiredHSpec = MeasureSpec.makeMeasureSpec(pixelHeight, MeasureSpec.MODE_CONSTANT);
final int desiredWSpec = MeasureSpec.makeMeasureSpec(pixelWidth, MeasureSpec.MODE_CONSTANT);
setMeasuredDimension(desiredWSpec, desiredHSpec);
The MODE_CONSTANTS must have a value of one of the following:
* AT_MOST - meaning that it is dynamic, but will be clipped if the contents are too large
* EXACTLY - meaning it will be that size no matter how large or small the contents are
* UNSPECIFIED - meaning that it will make whatever decision it makes according to the parameters of the parents, children, device size, etc...
If you do not specify one of these constants, then the Android Layout rendering engine has no idea what to do, and simply hides the object. It must be understood, that as an open platform for so many devices, Google decided to make the layout engine "dynamic and intelligent" to support as many apps as possible on as many platforms as possible. This simply requires the developer to let the device know exactly what it needs.
Note: It sounds like you want EXACTLY, but think carefully about your choice and how many devices you will be supporting. :)

Scale image within custom ImageView

I'm extending ImageView in order to manually scale an image within the view. I want to scale an image to fill the width of the custom view, and then draw it to the canvas, however, I'm unable to get the view width using this.getWidth()
It just returns 0, as the view has not yet been drawn and so has dimensions 0 by 0.
Currently I have the following in my main.xml:
<com.android.myapp.BackgroundView
android:id="#+id/background_view"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:src="#drawable/background"
android:dither="true"
/>
The custom class is as follows:
public class BackgroundView extends ImageView {
private Paint paint;
private Bitmap background;
public BackgroundView(Context context) {
super(context);
paint = new Paint();
loadBitmap();
}
public BackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
loadBitmap();
}
public void loadBitmap() {
BitmapDrawable src = (BitmapDrawable) this.getDrawable();
background = src.getBitmap();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(background, 0, 0, paint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
My Main.java class is:
public class Main extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
I can't use
Bitmap.createScaledBitmap(background, view.getWidth(), view.getHeight(), false)
as the view hasn't yet been drawn, how would I go about scaling the image to fill the view/screen width at this point?
Thanks in advance.
I believe what you want to do could also be achieved by using ImageView directly in conjunction with the scaleType attribute. Either use fitXY or centerCrop, depending on your needs.
But to answer the question, you can only use getWidth() and getHeight() after layout() has been called. So you should be able to use the values inside your onDraw method.
Also you could use another drawBitmap method so you wouldn't have to create a new bitmap in memory.

Categories

Resources