If a custom view has several shapes, Is it possible to animate only one of them?
For eg: for one of my application, 2 circles, one inner and another outer are drawn on a custom view. While I tried to animate using scale animation, I see that both the circles gets animated where as I need only one of them to.
One of the solution that occurred to me is to have multiple custom views.
But not sure if it is the right way to do it.
Are there alternate better solution to it?
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.test.customanimation.CustomView
android:id="#+id/circular_progress"
android:layout_width="400dp"
android:layout_height="400dp"
android:layout_gravity="center"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="#+id/scale_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Scale Up"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:id="#+id/scale_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="Scale Down"/>
</android.support.constraint.ConstraintLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private CustomView mCustomView;
private Button mScaleUpBtn;
private Button mScaleDownBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCustomView = findViewById(R.id.circular_progress);
mScaleUpBtn = findViewById(R.id.scale_up);
mScaleUpBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mCustomView.scaleUpAnimation(5000);
}
});
mScaleDownBtn = findViewById(R.id.scale_down);
mScaleDownBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mCustomView.scaleDownAnimation(5000);
}
});
}
}
CustomView.java
public class CustomView extends View {
private Paint OuterCirclePaint,InnerCirclePaint;
float mCircleX,mCircleY,mInnerCircleRadius,mOuterCircleRadius;
public CustomView(Context context) {
super(context);
init();
}
public CustomView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomView(Context context, #Nullable AttributeSet attrs, int
defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public CustomView(Context context, #Nullable AttributeSet attrs, int
defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init(){
OuterCirclePaint = new Paint();
OuterCirclePaint.setColor(Color.GREEN);
OuterCirclePaint.setStrokeWidth(20);
OuterCirclePaint.setStyle(Paint.Style.STROKE);
InnerCirclePaint = new Paint();
InnerCirclePaint.setColor(Color.BLACK);
InnerCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
mCircleX = getWidth()/2;
mCircleY = getHeight()/2;
if(mCircleX < mCircleY) {
mInnerCircleRadius = (getWidth() / 2) - 100;
mOuterCircleRadius = (getWidth() / 2) - 40;
}
else {
mInnerCircleRadius = (getHeight() / 2) - 100;
mOuterCircleRadius= (getHeight() / 2) - 40;
}
canvas.drawCircle(mCircleX,mCircleY,mOuterCircleRadius,OuterCirclePaint);
canvas.drawCircle(mCircleX,mCircleY,mInnerCircleRadius,InnerCirclePaint);
}
public void scaleDownAnimation(int duration){
ScaleAnimation fade_in = new ScaleAnimation(1.0f,0.5f,1.0f,0.5f,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
fade_in.setDuration(duration);
fade_in.setFillAfter(true);
this.startAnimation(fade_in);
}
public void scaleUpAnimation(int duration){
ScaleAnimation fade_out = new ScaleAnimation(0.5f,1.0f,0.5f,1.0f,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
fade_out.setDuration(duration);
fade_out.setFillAfter(true);
this.startAnimation(fade_out);
}
}
You are already overriding onDraw() and providing your own methods to handle the animations. IMO this approach is best for performance, so I'd keep it that way and only switch over to another animation framework, namely Property Animations
In order to redraw only the inner circle during an animation, I'd suggest using ValueAnimator and ValueAnimator.AnimatorUpdateListener for the animations.
Let's introduce some new fields for CustomView
private float scaleFactor = 1f;
private ValueAnimator scaleUpAnimator;
private ValueAnimator scaleDownAnimator;
private ValueAnimator.AnimatorUpdateListener updateListener;
Initialize them as follows
private void initAnimations() {
scaleUpAnimator = ValueAnimator.ofFloat(0.5f, 1.0f);
scaleDownAnimator = ValueAnimator.ofFloat(1.0f, 0.5f);
updateListener = new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFactor = (float)animation.getAnimatedValue();
CustomView.this.invalidate();
}
};
scaleUpAnimator.addUpdateListener(updateListener);
scaleDownAnimator.addUpdateListener(updateListener);
}
Change the line for the inner circle in onDraw()
canvas.drawCircle(mCircleX, mCircleY, mInnerCircleRadius * scaleFactor, innerCirclePaint);
... and start the animations like this
public void scaleDownAnimation(int duration){
scaleDownAnimator.setDuration(duration);
scaleDownAnimator.start();
}
public void scaleUpAnimation(int duration){
scaleUpAnimator.setDuration(duration);
scaleUpAnimator.start();
}
Related
I am trying to create a dummy view from already existing View.
Original Image:
Need to create dummy view like this.
I tried with paint and canvas.
public class MyView extends View {
Paint paint;
Path path;
public MyView(Context context) {
super(context);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.drawRect(30, 50, 200, 350, paint);
// canvas.drawRect(100, 100, 300, 400, paint);
//drawRect(left, top, right, bottom, paint)
}
}
But I cannot draw like this. Because some time image will be circle or Ovel or any shape. So, I need to deduct the existing view and draw new view as same. Can anyone help me to create a dummy view from existing view?
I am trying to do this for shimmer animation only. For facebook shimmer I need to give the view inside the shimmerFramelayout. But My view will be dynamic. So, I need to create a dummy view programmatically for every time. For facebook Shimmer:
<com.facebook.shimmer.ShimmerFrameLayout
android:id="#+id/shimmerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingConstraints">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!--add several shimmer placeholder layout -->
<include layout="#layout/shimmer_placeholder_layout"></include>
<include layout="#layout/shimmer_placeholder_layout"></include>
<include layout="#layout/shimmer_placeholder_layout"></include>
</LinearLayout>
</com.facebook.shimmer.ShimmerFrameLayout>
Here shimmer_placeholder_layout is static view. I need to create dynamic view.
Finally got the solution.
Here I attached the solution for someone will get benefit on this.
MyView class:
public class MyView extends View {
Paint paint;
ViewGroup viewGroup;
Context context;
List<Rect> rectList = new ArrayList<>();
public MyView(Context context, ViewGroup viewGroup) {
super(context);
this.viewGroup = viewGroup;
this.context = context;
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
paint = new Paint();
paint.setColor(context.getResources().getColor(R.color.gray));
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.FILL);
for (int i = 0; i < viewGroup.getChildCount(); ++i) {
View child = viewGroup.getChildAt(i);
Rect rect = new Rect();
int x = (int) child.getX() - dpToPx(20);
int y = (int) child.getY() - dpToPx(20);
rect.left = x;
rect.top = y;
rect.right = x + child.getWidth();
rect.bottom = y + child.getHeight();
rectList.add(rect);
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (Rect rect : rectList) {
canvas.drawRect(rect, paint);
}
}
public static int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
}
My MainActivity:
ConstraintLayout constraintLayout;
ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
constraintLayout = findViewById(R.id.parent_view);
imageView = findViewById(R.id.item_profile_img);
constraintLayout.post(() -> {
ShimmerFrameLayout shimmerFrameLayout = new ShimmerFrameLayout(MainActivity.this);
Shimmer shimmer = new Shimmer.ColorHighlightBuilder()
.setDuration(2000)
.setBaseAlpha(0.9f)
.setHighlightAlpha(0.93f)
.setWidthRatio(1.5f)
.setDirection(Shimmer.Direction.RIGHT_TO_LEFT)
.setAutoStart(true)
.setBaseColor(getColor(android.R.color.darker_gray))
.setBaseColor(getColor(android.R.color.darker_gray))
.setHighlightColor(getColor(android.R.color.white))
.build();
shimmerFrameLayout.setShimmer(shimmer);
shimmerFrameLayout.addView(new MyView(MainActivity.this,constraintLayout));
constraintLayout.addView(shimmerFrameLayout);
shimmerFrameLayout.startShimmer();
});
}
My activity_main.xml:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText,MissingConstraints"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
tools:ignore="HardcodedText,MissingConstraints"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:id="#+id/parent_view">
<ImageView
android:id="#+id/item_profile_img"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/ic_launcher_background"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription,MissingConstraints" />
<TextView
android:id="#+id/item_student_name_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:text="Student name"
android:textStyle="bold"
app:layout_constraintStart_toEndOf="#+id/item_profile_img" />
<TextView
android:id="#+id/item_student_college"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="8dp"
android:text="Student college"
app:layout_constraintStart_toEndOf="#+id/item_profile_img"
app:layout_constraintTop_toBottomOf="#+id/item_student_name_title" />
<TextView
android:id="#+id/item_student_specialization"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="8dp"
android:text="Student specialization"
app:layout_constraintStart_toEndOf="#+id/item_profile_img"
app:layout_constraintTop_toBottomOf="#+id/item_student_college" />
<TextView
android:id="#+id/item_student_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="8dp"
android:text="Student description"
app:layout_constraintTop_toBottomOf="#+id/item_profile_img"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I'm currently struggling with what I believe should be pretty simple.
I have created a LinearLayout in an XML file that i want to link to a CustomComponent that extends LinearLayout, meaning i started backwards.
Normally i create a CustomComponent first and this creates an XML-file linked by a tag, <my.package.CustomComponent> (If I'm not mistaken this is the only way they are linked(?)) and i do stuff in the onDraw(). But in this project i do the layout throughthe XML and not the onDraw().
Linking XML with activity is done by setContentView(R.layout.customView) but I can't really do this in a CustomComponent as i don't have an onCreate() method inherited.
sidenote: In the XML all my imagebuttons has android:onClick=chooseButton but for obvious reason it can't find this method...
Any ideas regarding this problem?
EDIT:
the two files doesn't seem to be linked because in the xml android:onClick="chooseButton" the IDE says: "cannot resolve symbol chooseButton"
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/dial_view_id"
android:layout_width="match_parent"
tools:context=".DialView"
android:orientation="vertical"
android:layout_height="match_parent">
<com.package.CustomView
android:id="#+id/drawingview"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1">
<ImageButton
android:id="#+id/button1"
android:onClick="chooseButton"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="fitCenter"
android:background="#drawable/ic_dialpad_1_blue" />
<ImageButton
android:id="#+id/button2"
android:onClick="chooseButton"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/ic_dialpad_2_blue"
------code repeated below-----/>
CustomView:
public class CustomView extends LinearLayout {
private String mExampleString;
private int mExampleColor = Color.RED;
private float mExampleDimension = 0;
private Drawable mExampleDrawable;
private TextPaint mTextPaint;
private float mTextWidth;
private float mTextHeight;
private ImageButton button_0, button_1, button_2, button_3, button_4, button_5, button_6;
private ImageButton button_7, button_8, button_9, button_star, button_pound;
private boolean clicked = false;
private SparseIntArray drawables = new SparseIntArray();
public DialView(Context context) {
super(context);
}
public DialView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public DialView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs, defStyle);
}
private void init(AttributeSet attrs, int defStyle) {
// Load attributes
final TypedArray a = getContext().obtainStyledAttributes(
attrs, R.styleable.DialView, defStyle, 0);
mExampleString = a.getString(
R.styleable.DialView_exampleString);
mExampleColor = a.getColor(
R.styleable.DialView_exampleColor,
mExampleColor);
// Use getDimensionPixelSize or getDimensionPixelOffset when dealing with
// values that should fall on pixel boundaries.
mExampleDimension = a.getDimension(
R.styleable.DialView_exampleDimension,
mExampleDimension);
if (a.hasValue(R.styleable.DialView_exampleDrawable)) {
mExampleDrawable = a.getDrawable(
R.styleable.DialView_exampleDrawable);
mExampleDrawable.setCallback(this);
}
a.recycle();
// Set up a default TextPaint object
mTextPaint = new TextPaint();
mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextAlign(Paint.Align.LEFT);
// Update TextPaint and text measurements from attributes
invalidateTextPaintAndMeasurements();
}
private void invalidateTextPaintAndMeasurements() {
mTextPaint.setTextSize(mExampleDimension);
mTextPaint.setColor(mExampleColor);
mTextWidth = mTextPaint.measureText(mExampleString);
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
mTextHeight = fontMetrics.bottom;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
public void getButtons(){}
public void chooseButton(View v){}
public void switchBackground(ImageButton button){}
}
I have a custom CircleButton class:
public class CircleButton extends ImageView {
private int radius;
private int x;
private int y;
public CircleButton(Context context) {
super(context);
constructorTask();
}
public CircleButton(Context context, AttributeSet attrs) {
super(context, attrs);
constructorTask();
}
public CircleButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
constructorTask();
}
public CircleButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
constructorTask();
}
private void constructorTask() {
x = 300;
y = 300;
radius = 100;
}
#Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
Log.i("Button Logger","Button Pressed");
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(x, y, radius, GameView.green);
Log.i("Drawing status", "CircleButton Drawing...");
}
}
I have a single activity. This activity contains a relative layout with a single custom view.
Here is the custom view:
public class GameView extends View {
public static Paint green = new Paint();
public GameView(Context context) {
super(context);
green.setARGB(255,0,255,0);
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
green.setARGB(255, 0, 255, 0);
}
public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
green.setARGB(255, 0, 255, 0);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.i("GameView Draw Status","Drawing...");
Main.testButton.invalidate();
invalidate();
}
}
And here is the activity code:
public class Main extends AppCompatActivity {
public static CircleButton testButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testButton = new CircleButton(getApplicationContext());
makeFullScreen();
RelativeLayout screenLayout = (RelativeLayout) findViewById(R.id.screenLayout);
screenLayout.addView(testButton);
}
private void makeFullScreen() {...}
}
For some reason my testButton is not being drawn. Why is it not being drawn?
EDIT ONE: Here is the XML I have.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp"
tools:context="com.example.vroy.customcirclebuttontest.Main"
android:id="#+id/screenLayout">
<com.example.vroy.customcirclebuttontest.GameView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/black"
android:id="#+id/gameScreen" />
</RelativeLayout>
EDIT TWO: I did some further debugging by adding a normal button to the relative layout and it worked fine.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testCircleButton = new CircleButton(getApplicationContext());
makeFullScreen();
testButton = new Button(getApplicationContext());
testButton.setX(100);
testButton.setY(100);
testButton.setText("HELLO WORLD");
RelativeLayout screenLayout = (RelativeLayout) findViewById(R.id.screenLayout);
screenLayout.addView(testCircleButton);
screenLayout.addView(testButton);
Log.i("Button Status","Adding Button To Layout");
}
For some reason by circleButton is not working but a normal button is.
You are not specifying the size of the View (layout_width and layout_height), and thus your view is getting rendered inside a 0px by 0px space and thus invisible.
You can set those programatically using LayoutParams before adding your views to the layout.
For example with absolute size:
testButton.setLayoutParams(new ViewGroup.LayoutParams(100,100));
Although keep in mind the difference between px and dip. You would probably want to set the values using your internal radius attribute instead of harcoding them.
What I am trying to achieve:
measure a container View in my layout, mainContainer, that is defined in the XML
pass the mainContainer's width and height to a different custom View before onDraw() is called
I want to pass the width and height so the custom View knows where to draw canvas.drawBitmap using coordinates
The custom view will be programmatically created from code
How can I pass the measured int width and int height to my custom View before onDraw() is called?
Custom View
public class AvatarView extends ImageView {
private Bitmap body;
private Bitmap hat;
public AvatarView(Context context) {
super(context);
init();
}
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AvatarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
body = BitmapFactory.decodeResource(getResources(), R.drawable.battle_run_char);
hat = BitmapFactory.decodeResource(getResources(), R.drawable.red_cartoon_hat);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(body, x, y, null);
canvas.drawBitmap(hat, x, y, null);
}
}
Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_customize_avatar, container, false);
final RelativeLayout mainContainer = (RelativeLayout) view.findViewById(R.id.main_container);
TwoWayView inventoryList = (TwoWayView) view.findViewById(R.id.inventory);
inventoryList.setAdapter(null);
inventoryList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
}
});
mainContainer.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
// Retrieve the width and height
containerWidth = mainContainer.getWidth();
containerHeight = mainContainer.getHeight();
// Remove global listener
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
mainContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
else
mainContainer.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
return view;
}
XML
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:clickable="true"
android:background="#fff" >
<com.walintukai.lfdate.CustomTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:textStyle="bold"
android:textColor="#fff"
android:textSize="20sp"
android:textAllCaps="true"
android:text="#string/customize_avatar"
android:background="#009BFF" />
<RelativeLayout
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<org.lucasr.twowayview.TwoWayView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/inventory"
style="#style/HorizontalListView"
android:layout_width="match_parent"
android:layout_height="80dp"
android:drawSelectorOnTop="false"
android:background="#f3f3f3" />
</LinearLayout>
What you need to do is add a flag inside your AvatarView that checks if are you going to render this or not in your onDraw method.
sample:
public class AvatarView extends ImageView {
private Bitmap body;
private Bitmap hat;
private int containerHeight;
private int containerWidth;
private boolean isRender = false;
public AvatarView(Context context) {
super(context);
init();
}
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AvatarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setMeasure(int containerWidth, int containerHeight )
{
this.containerHeight = containerHeight;
this.containerWidth = containerWidth;
}
private void init() {
body = BitmapFactory.decodeResource(getResources(), R.drawable.battle_run_char);
hat = BitmapFactory.decodeResource(getResources(), R.drawable.red_cartoon_hat);
}
public void setRender(boolean render)
{
isRender = render;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(isRender )
{
canvas.drawBitmap(body, x, y, null);
canvas.drawBitmap(hat, x, y, null);
}
}
}
Now it wont render when you dont call setRender and set it to true. And just call setMeasure to pass the value.
First you need to call setMeasure and after you set the measure you then call setRender(true) and call invalidate() to call the onDraw method to render the images
I have extended an ImageView and calling a method of ImageView from outside class , inside a Thread. Inside the method I have tried using invalidate postValidate and everything but it never called the onDraw method , is it something to do with the calling method-
public class TestImageView extends ImageView {
public FacePreviewImageView(Context context) {
super(context);
}
public void process(String strImageFilePath) {
//doing some operation
invalidate();
}
#SuppressLint("DrawAllocation")
#Override
protected void onDraw(Canvas canvas) {
Log.i("CAME INSIDE ", ""+faces.total());
if(faces.total()>0){
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setTextSize(20);
String s = "Processed Face";
float textWidth = paint.measureText(s);
canvas.drawText(s, (getWidth() - textWidth) / 2, 20, paint);
CvRect r = new CvRect(cvGetSeqElem(faces, 0));
int x = r.x(), y = r.y(), w = r.width(), h = r.height();
canvas.drawRect(new Rect(x, y, x+w, y+h), paint);
}
super.onDraw(canvas);
}
}
and my calling method looks like -
new Handler().post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
((TestImageView )imageView).process(pictureFile.getAbsolutePath());
}
});
One more point to add-
I tried to add this view directly inside layout file-
<FrameLayout
android:id="#+id/ll2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.5"
android:orientation="horizontal" >
<com.example.defaultfacetracker.TestImageView
android:id="#+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</FrameLayout>
but its throwing exception while launching. SO I finally changed the code to-
<ImageView
android:id="#+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#android:drawable/toast_frame" />
And in a class I am just creating a new instance of TestImageView to work for.
If that is the reason to do something here.
Have you tried to set:
setWillNotDraw(false);
In your constructor?
#Override
public FacePreviewImageView(Context context) {
this(context, null, 0);
}
#Override
public FacePreviewImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
#Override
public FacePreviewImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setWillNotDraw(false);
}
setWillNotDraw(false); doesn't work for me.
I had the same issue, here, and I figured out checking that my child class of ImageView has visibility VISIBILE and not GONE.
If it has GONE value for visibility, onDraw will not be called.