I want to circular reveal animation for recycler view items. I put the following code in the adapter class but it doesn't work. please help me.
public void anim(final CustomViewHolder customViewHolder) {
// get the center for the clipping circle
int centerX = (customViewHolder.imageView.getLeft() + customViewHolder.imageView.getRight()) / 2;
int centerY = (customViewHolder.imageView.getTop() + customViewHolder.imageView.getBottom()) / 2;
int startRadius = 0;
// get the final radius for the clipping circle
int endRadius = Math.max(customViewHolder.imageView.getWidth(), customViewHolder.imageView.getHeight());
// create the animator for this view (the start radius is zero)
Animator anim =
null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
anim = ViewAnimationUtils.createCircularReveal(customViewHolder.rv,
centerX, centerY, startRadius, endRadius);
anim.setDuration(1000);
// make the view invisible when the animation is done
anim.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
customViewHolder.rv.setVisibility(View.VISIBLE);
anim.start();
}
}
Related
It's my first question here, sorry for the mistakes.
In my app I have an animated ImageView. If somebody click on it, it moves to random coordinates.
It is necessary that at the moment when the ImageView overcomes a certain distance (set initially) a Toast appears.
My problem is that the Toast appears many times regardless of whether the ImageView has covered a given distance or not.
Need your advice how can I fix it.
Thank you in advance!
private final int MAX_LENGTH = 420;
private int xRand, yRand;
private int xStart, yStart;
private View unlimitePlayView;
private ImageView circle;
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
unlimitePlayView = inflater.inflate(R.layout.fragment_tournament, container, false);
circle = unlimitePlayView.findViewById(R.id.circle);
circle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
xStart = (int) circle.getX();
yStart = (int) circle.getY();
xRand = new Random().nextInt(deviceWidth - circle.getWidth());
yRand = new Random().nextInt(deviceHeight - circle.getHeight());
Path path = new Path();
path.moveTo(xStart, yStart);
path.lineTo(xRand, yRand);
animCircle = ObjectAnimator.ofFloat(circle, "x", "y", path);
animCircle.setDuration(1000);
animCircle.start();
animCircle.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float currentX = (float) valueAnimator.getAnimatedValue("x");
float currentY = (float) valueAnimator.getAnimatedValue("y");
int currentLength = (int) Math.sqrt(Math.pow(Math.abs(currentX - xStart), 2) + Math.pow(Math.abs(currentY - yStart), 2));
if (currentLength > MAX_LENGTH) {
Toast.makeText(getActivity(), "DONE", Toast.LENGTH_SHORT).show();
}
}
}
}
}
}
Well written question! It is because currentLength > MAX_LENGTH is true not only the first time. If it was true once, it will be true every call of onAnimationUpdate().
Remember the toast was shown before and prevent it afterwards. For instance:
animCircle.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
private boolean wasFired = false;
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float currentX = (float) valueAnimator.getAnimatedValue("x");
float currentY = (float) valueAnimator.getAnimatedValue("y");
int currentLength = (int) Math.sqrt(Math.pow(currentX - xStart, 2) + Math.pow(currentY - yStart, 2));
if (currentLength > MAX_LENGTH && !wasFired) {
Toast.makeText(getActivity(), "DONE", Toast.LENGTH_SHORT).show();
wasFired = true;
}
}
}
Another small improvement: I removed abs(), since the square of a negative number is always positive.
I am working on a video player app. But when I am scaling for video zoom, So this app is not cropping in the center in some devices but this code working fine on other devices.
please help me. Or give me any suggestions. Thank you
here is my code
final static float move = 200;
float ratio = 1.0f;
int hasDist;
float baseRatio;
int position = -1;
VideoView videoView;
Uri uri;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video__player_);
videoView = findViewById(R.id.videoView);
position = getIntent().getIntExtra("position", -1);
String path = videoList.get(position).getPath();
uri = Uri.parse(path);
videoView.setVideoPath(path);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getPointerCount()==2){
int action = event.getAction();
int mainAction = action&MotionEvent.ACTION_MASK;
if (mainAction ==MotionEvent.ACTION_POINTER_DOWN){
hasDist=getDistion(event);
baseRatio = ratio;
}else {
float scale = (getDistion(event)-hasDist)/move;
float fatcher = (float)Math.pow(2,scale);
ratio = Math.min(1024.0f,Math.max(0.0f,baseRatio*fatcher));
videoView.setScaleX(ratio);
videoView.setScaleY(ratio);
}
}
return true;
}
private int getDistion(MotionEvent event) {
int dx = (int) (event.getX(0) - event.getX(1));
int dy = (int) (event.getY(0) - event.getY(1));
return (int) (Math.sqrt(dx * dx + dy * dy));
}
}
I'm trying to draw a scrollable timeline. I implement singleLine custom view for drawing a line between circle ImageView's of recycler view:
public class SingleLine extends View {
WeakReference<Context> ctx;
Paint paint;
PointF pointA, pointB;
private int height_custom;
public SingleLine(Context context) {
super(context);
ctx = new WeakReference<>(context);
init();
}
public SingleLine(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
ctx = new WeakReference<>(context);
init();
}
public void init() {
paint = new Paint();
pointA = new PointF();
pointB = new PointF();
paint.setStrokeWidth(10);
paint.setColor(ctx.get().getResources().getColor(R.color.green));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(pointA.x, pointA.y, pointB.x, pointB.y, paint);
invalidate();
}
public PointF getPointA() {return pointA;}
public void setPointA(PointF pointA) {this.pointA = pointA;}
public PointF getPointB() {return pointB;}
public void setPointB(PointF pointB) {this.pointB = pointB;}
}
And in onBindViewHolder() method of my adapter, I use an interface for measuring x/y coordinates of first and last visible view of recyclerview:
#Override
public void onBindViewHolder(#NonNull final TaskViewHolder holder, final int position) {
Tasks tasks = datalist_tasks.get(position);
String hour = "" + tasks.getHour() + ":" + tasks.getMinute();
holder.tv_clock.setText(hour);
holder.tv_title.setText(tasks.getTitle());
holder.tv_comment.setText(tasks.getComment());
holder.itemView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
holder.itemView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
else
holder.itemView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
if (iOnMeasureCustomView != null)
iOnMeasureCustomView.onMeasure(holder.iv_status, position);
}
});
}
And I implement that interface in my activity like below:
LinearLayoutManager layoutManager1 = new LinearLayoutManager(_C.get(), RecyclerView.VERTICAL, false);
rv_tasks.setLayoutManager(layoutManager1);
tasksAdapter.setiOnMeasureCustomView(new IOnMeasureCustomView() {
#Override
public void onMeasure(ImageView iv_status, int position) {
int[] screen = new int[2];
iv_status.getLocationOnScreen(screen);
int width = (int) ((iv_status.getWidth() / 2) + convertDpToPixel(8));
if (position == layoutManager1.findFirstCompletelyVisibleItemPosition()) {
pointA.set(iv_status.getX() + width, iv_status.getY() + convertDpToPixel(8));
}
else if (position == layoutManager1.findLastCompletelyVisibleItemPosition()) {
pointB.set(iv_status.getX() + width, screen[1] - convertDpToPixel(40));
singleLine.setPointA(pointA);
singleLine.setPointB(pointB);
singleLine.invalidate();
}
}
});
And also I implement addOnScrollListener() for my recyclerview and write this code snippet (I don't know that if this implementation is correct or no):
rv_tasks.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
PointF a = singleLine.getPointA();
PointF b = singleLine.getPointB();
if (dy > 0) {
a.y -= dy;
b.y -= dy;
singleLine.setPointA(a);
singleLine.setPointB(b);
singleLine.invalidate();
} else {
a.y += Math.abs(dy);
b.y += Math.abs(dy);
singleLine.setPointA(a);
singleLine.setPointB(b);
singleLine.invalidate();
}
}
});
My problem is when I scroll in activity, like the gif below, my singleLine is something like cutting off imageView and the end x/y of line become the x/y of end of the screen.
Questios
How can I set x/y of the line to prevent this?
And also I need some help with drawing this line with animation. How can I draw this line with animation that starts when the activity started?
I have this fade in function
private void fadeIn() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(ButtonA, "alpha", 0f, 1f);
objectAnimator.setDuration(2000L);
objectAnimator.addListener(new AnimatorListenerAdapter() {
});
objectAnimator.start();
}
and right now the only target is ButtonA, i have 3 more buttons (ButtonB, ButtonC ....) is there anyway i can target all four without writing this codesnippet 4 times over?
try this
private static void fadeIn(long duration, final View... views) {
if (views == null) return;
final ValueAnimator va = ValueAnimator.ofFloat(0, 1);
va.setDuration(duration);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animator) {
final float alpha = (float) animator.getAnimatedValue();
for (View view : views) view.setAlpha(alpha);
}
});
va.start();
}
how to use:
// first argument duration and then pass any number of views
fadeIn(2000, buttonA, buttonB, buttonC);
I have some custom view with onTouchEvent where I'm setting mX and mY .
mx=event.getX();
my=event.getY();
this is for getting the drawing path of touch event - working great, and I can
see the coordinates in my text view which is defined in the main activity.
I want to use this 2 attributes in my Main activity layout
for setting the background color
for example
if (mx > 1000 && my > 100 ){
set color
}
but it seems that mx and my are not getting any values
what i tried is
custom_view paintview = (custom_view) findViewById(R.id.custum_view_id)
float mx =paintview.getmx();
float my =paintview.getmy();
maybe i didn't defined the getmx correctly in custom view ?
public float getmx(){
return mx;
}
i'm new in Java and android so be easy with me :)
adding MainActiviy.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Drawing - custom view
drawView = (Drawing) findViewById(R.id.drawing);
findCoordinates();
TextView Coordinates = (TextView) findViewById(R.id.CNcoordinates);
//Coordinates - message with coordinates
paintView.setTextView(Coordinates);
}
private Drawing drawView;
public void findCoordinates() {
Drawing paintView = (Drawing) findViewById(R.id.drawing);
float xX = drawView.getmX();
float yY = drawView.getmY();
int nColor = Color.BLUE;
View buttonmove1 = findViewById(R.id.layoutMove);
if (Math.abs(xX) > 1000 && Math.abs(yY) > 1000) {
buttonmove1.setBackgroundColor(nColor);
}
}
the coordinates come from:
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mX = event.getX();
mY = event.getY();
View buttonmove = findViewById(R.id.drawing);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(mX, mY);
if(myCoordinates!=null){
myCoordinates.setText(":" + mX + " , " + ":" + mY);
}
break;
public void setTextView(TextView tv){
myCoordinates = tv;
}
Use interface or callback after finishing your touchEvent. you have to re-call your
findCoordinates()
so it will update your UI respect to new values.
i succeed to use OnViewTouchListener as a callback:
adding the method in custom view:
private OnViewTouchListener OnViewTouchListener;
public interface OnViewTouchListener {
public void onViewTouched (float x, float y, boolean touched);
}
public void setOnViewTouchListener (OnViewTouchListener listener){
OnViewTouchListener = listener;
}