I have popupWindow with some image views, which are created and added progammatically to popup window. Their position is set to bottom line with setY(). But when I use setEndValue to animate with spring, image goes from 0 to setEndValue, not from it's initial position.
How that can be fixed?
public SharePostPopupWindow(View parentView) {
super(MATCH_PARENT, MATCH_PARENT);
this.context = parentView.getContext();
this.parentView = parentView;
AndroidBlaBlaApplication.component(context).inject(this);
setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
FrameLayout container = new FrameLayout(context);
socialViews = new ArrayList<>();
socials = new ArrayList<>();
shadow = new View(context);
shadow.setId(R.id.share_view_shadow);
shadow.setBackgroundColor(Color.BLACK);
shadow.setClickable(true);
shadow.setAlpha(0.5f);
shadow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
bus.post(new ShadowClickedEvent());
spring.setEndValue(initialPosition / 2 - Utils.convertDpToPixel(imageSize, context));
dismiss();
}
});
}
public void show() {
Utils.hideKeyboard(context, getContentView());
createButtons();
SpringSystem springSystem = SpringSystem.create();
spring = springSystem.createSpring();
SpringConfig slowConfig = new SpringConfig(TENSION, DAMPER);
spring.setSpringConfig(slowConfig);
spring.addListener(new SimpleSpringListener() {
#Override
public void onSpringUpdate(Spring spring) {
float value = (float) spring.getCurrentValue();
for (int i = 0; i < socialViews.size(); i++) {
if (i % 2 != 0) {
socialViews.get(i).setY(value);
}
}
}
});
showAtLocation(parentView, Gravity.CENTER_VERTICAL, 0, 0);
getContentView().setAlpha(1f);
}
If you want to force spring animation from certain position, you need to use
spring.setCurrentValue method first.
Related
I have read out many questions but I don't get the answer to mine.
So I am posting this new question.
I am working on a live streaming app. Basically I want to change the surface view size on click event like Whatsapp video calling.
I have two scenarios:-
Scenario 1:- One is relative layout which contains a surface view and there is a frame layout which also contains a surface view and I want to exchange when click event happens but the Click event listener is not working.
XML file
<FrameLayout
android:id="#+id/liveStreaming_videoAndControlsContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/black">
<com.sos.GD_Live.utils.liveUtils.VideoGridContainer
android:id="#+id/liveStreaming_videoContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.sos.GD_Live.utils.liveUtils.VideoGridContainer>
<FrameLayout
android:id="#+id/videoChat_localVideoRender"
android:layout_marginBottom="130dp"
android:layout_marginRight="20dp"
android:layout_width="100dp"
android:onClick="frameclick"
android:visibility="visible"
android:layout_height="150dp"
android:layout_gravity="bottom|right"
/>
Its parent layout is also a frame layout
public class VideoGridContainer extends RelativeLayout implements Runnable {
private static final int MAX_USER = 4;
private static final int STAT_LEFT_MARGIN = 34;
private static final int STAT_TEXT_SIZE = 10;
private SparseArray<ViewGroup> mUserViewList = new SparseArray<>(MAX_USER);
private List<Integer> mUidList = new ArrayList<>(MAX_USER);
private Handler mHandler;
private int mStatMarginBottom;
private VideoViewEventListener mEventListener;
public VideoGridContainer(Context context) {
super(context);
init();
}
public VideoGridContainer(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public VideoGridContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mHandler = new Handler(getContext().getMainLooper());
}
public void addUserVideoSurface(int uid, SurfaceView surface, boolean isLocal) {
if (surface == null) {
return;
}
int id = -1;
if (isLocal) {
if (mUidList.contains(0)) {
mUidList.remove((Integer) 0);
mUserViewList.remove(0);
}
if (mUidList.size() == MAX_USER) {
mUidList.remove(0);
mUserViewList.remove(0);
}
id = 0;
} else {
if (mUidList.contains(uid)) {
mUidList.remove((Integer) uid);
mUserViewList.remove(uid);
}
if (mUidList.size() < MAX_USER) {
id = uid;
}
}
if (id == 0) mUidList.add(0, uid);
else mUidList.add(uid);
if (id != -1) {
mUserViewList.append(uid, createVideoView(surface));
requestGridLayout();
}
}
private ViewGroup createVideoView(SurfaceView surface) {
RelativeLayout layout = new RelativeLayout(getContext());
layout.setId(surface.hashCode());
LayoutParams videoLayoutParams =
new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
layout.addView(surface, videoLayoutParams);
TextView text = new TextView(getContext());
text.setId(layout.hashCode());
LayoutParams textParams =
new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
textParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
textParams.bottomMargin = mStatMarginBottom;
textParams.leftMargin = STAT_LEFT_MARGIN;
text.setTextColor(Color.WHITE);
text.setTextSize(STAT_TEXT_SIZE);
layout.addView(text, textParams);
return layout;
}
public void removeUserVideo(int uid, boolean isLocal) {
if (isLocal && mUidList.contains(0)) {
mUidList.remove((Integer) 0);
mUserViewList.remove(0);
} else if (mUidList.contains(uid)) {
mUidList.remove((Integer) uid);
mUserViewList.remove(uid);
}
requestGridLayout();
if (getChildCount() == 0) {
mHandler.removeCallbacks(this);
}
}
private void requestGridLayout() {
removeAllViews();
layout(mUidList.size());
}
private void layout(int size) {
LayoutParams[] params = getParams(size);
for (int i = 0; i < size; i++) {
addView(mUserViewList.get(mUidList.get(i)), params[i]);
}
}
private LayoutParams[] getParams(int size) {
int width = getMeasuredWidth();
int height = getMeasuredHeight();
LayoutParams[] array =
new LayoutParams[size];
for (int i = 0; i < size; i++) {
if (i == 0) {
array[0] = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
array[0].addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
array[0].addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
} else if (i == 1) {
array[1] = new LayoutParams(width, height / 2);
array[0].height = array[1].height;
array[1].addRule(RelativeLayout.BELOW, mUserViewList.get(mUidList.get(0)).getId());
array[1].addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
} else if (i == 2) {
array[i] = new LayoutParams(width / 2, height / 2);
array[i - 1].width = array[i].width;
array[i].addRule(RelativeLayout.RIGHT_OF, mUserViewList.get(mUidList.get(i - 1)).getId());
array[i].addRule(RelativeLayout.ALIGN_TOP, mUserViewList.get(mUidList.get(i - 1)).getId());
} else if (i == 3) {
array[i] = new LayoutParams(width / 2, height / 2);
array[0].width = width / 2;
array[1].addRule(RelativeLayout.BELOW, 0);
array[1].addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
array[1].addRule(RelativeLayout.RIGHT_OF, mUserViewList.get(mUidList.get(0)).getId());
array[1].addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
array[2].addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
array[2].addRule(RelativeLayout.RIGHT_OF, 0);
array[2].addRule(RelativeLayout.ALIGN_TOP, 0);
array[2].addRule(RelativeLayout.BELOW, mUserViewList.get(mUidList.get(0)).getId());
array[3].addRule(RelativeLayout.BELOW, mUserViewList.get(mUidList.get(1)).getId());
array[3].addRule(RelativeLayout.RIGHT_OF, mUserViewList.get(mUidList.get(2)).getId());
}
}
return array;
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
clearAllVideo();
}
private void clearAllVideo() {
removeAllViews();
mUserViewList.clear();
mUidList.clear();
mHandler.removeCallbacks(this);
}
#Override
public void run() {
}
public void setItemEventHandler(VideoViewEventListener listener) {
this.mEventListener = listener;
}
}
This code where in Java file, when I added surface view for both of the layouts
mVideoLayout = findViewById(R.id.liveStreaming_videoContainer);
mVideoLayout.addUserVideoSurface(0, surface, true);
SurfaceView surface = prepareRtcVideo(remotehost, false);
surface.setZOrderMediaOverlay(true);
mCameraBtn.setVisibility(View.VISIBLE);
remotehostlist.add(remotehost);
surface.setZOrderOnTop(true);
runOnUiThread(() -> {
surface.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Toast.makeText(LiveStreamingActivity.this, "it's good", Toast.LENGTH_SHORT).show();
return true;
}
});
surface.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(LiveStreamingActivity.this, "it's good", Toast.LENGTH_SHORT).show();
}
});
});
mLayoutSmallView.addView(surface);
mLayoutSmallView.setVisibility(View.VISIBLE);
mLayoutSmallView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean b) {
Toast.makeText(LiveStreamingActivity.this, "Focus changed", Toast.LENGTH_SHORT).show();
}
});
mRtcEngine.setupLocalVideo(new VideoCanvas(surface, VideoCanvas.RENDER_MODE_HIDDEN, 0));
mRtcEngine.enableVideo();
I have already tried onclick in XML, ontouchlistener, onfocuschange listener. But no one of them is working for it. Also tried is focusable.
The problem is I am unable to click the frame layout named mLayoutSmallView.
I want to switch the surface views when it is clicked.
How to correctly handle the top and bottom system window inset in android?
Can someone provide example?
I have used android:fitsSystemWindows=”true” in layout but it still does not work.
How to get getSystemWindowInsetBottom and getSystemWindowInsetTop to add padding.
[Example] Image from https://chris.banes.dev/2019/04/12/insets-listeners-to-layouts/
[Example]: https://i.stack.imgur.com/OBdvN.png
My Code `#BindView(R.id.slideViewPager)
ViewPager viewPager;
#BindView(R.id.layoutDots)
LinearLayout dotsLayout;
#BindView(R.id.btn_next)
Button btn_next;
private ImageView[] dots;
private int[] layouts;
private int mCurrentPage;
#Inject
PreferenceUtil preferenceUtil;
Animation animation;
int topPadding, bottomPadding;
View view;
// #BindView(R.id.activity_walkthrough)
RelativeLayout relativeLayout;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addTransparentStatusBar();
Injector.component().inject(this);
relativeLayout = (RelativeLayout) findViewById(R.id.activity_walkthrough);
setContentView(R.layout.activity_walkthrough);
ViewCompat.setOnApplyWindowInsetsListener(view, (OnApplyWindowInsetsListener) (v, insets) -> {
view = relativeLayout.getRootView();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
topPadding = view.getRootWindowInsets().getSystemWindowInsetTop();
bottomPadding = view.getRootWindowInsets().getSystemWindowInsetBottom();
}
return null;
});
layouts = new int[]{
R.layout.fragment_walkthorugh1,
R.layout.fragment_walkthorugh2,
R.layout.fragment_walkthorugh3};
// adding bottom dots
addBottomDots(0);
setupViewPager();
animation = AnimationUtils.loadAnimation(this, R.anim.up);
btn_next.startAnimation(animation);
}
private void addBottomDots(int currentPage) {
if (dotsLayout != null) {
dotsLayout.removeAllViews();
}
dots = new ImageView[layouts.length];
for (int i = 0; i < dots.length; i++) {
dots[i] = new ImageView(this);
dots[i].setPadding(0, 0, 5, 0);
if (i == currentPage) {
dots[i].setImageDrawable(getResources().getDrawable(R.drawable.active_dots));
} else {
dots[i].setImageDrawable(getResources().getDrawable(R.drawable.default_dots));
}
dotsLayout.addView(dots[i]);
}
}
private int getItem(int i) {
return viewPager.getCurrentItem() + i;
}
private void launchHomeScreen() {
preferenceUtil.setFirstTimeLaunch(false);
showBottomSheet();
// startActivity(LoginActivity.class,null);
// finish();
}
public void showBottomSheet() {
BottomSheetFragment addPhotoBottomDialogFragment = new BottomSheetFragment();
addPhotoBottomDialogFragment.show(getSupportFragmentManager(), BottomSheetFragment.TAG);
}
public void addTransparentStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window w = getWindow();
w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
}
private void setupViewPager() {
ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(), 3);
Walkthrough1 walkthrough1 = new Walkthrough1();
Walkthrough2 walkthrough2 = new Walkthrough2();
Walkthrough3 walkthrough3 = new Walkthrough3();
viewPagerAdapter.addFragment(walkthrough1);
viewPagerAdapter.addFragment(walkthrough2);
viewPagerAdapter.addFragment(walkthrough3);
viewPager.setAdapter(viewPagerAdapter);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
addBottomDots(position);
mCurrentPage = position;
// changing the next button text 'NEXT' / 'GOT IT'
if (position == layouts.length - 1) {
btn_next.setText(getString(R.string.start));
} else {
btn_next.setText(getString(R.string.next));
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
#OnClick(R.id.btn_next)
void nextPage() {
Toast.makeText(getApplicationContext(),"Top Padding : " + topPadding + " and bottom Padding " + bottomPadding,Toast.LENGTH_SHORT).show();
mCurrentPage = getItem(+1);
if (mCurrentPage < layouts.length) {
viewPager.setCurrentItem(mCurrentPage);
} else {
launchHomeScreen();
}
}
android:fitsSystemWindows="true" only works for some layout parent and not all... it works for Coordinator layout and Constraint layouts.
You can handle system insets by yourself:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val topPadding = view.rootWindowInsets.systemWindowInsetTop
val bottomPadding = view.rootWindowInsets.systemWindowInsetBottom
}
But you get access to rootWindowInsets only when view is attached to window. It is safe to get rootWindowInsets in following callbacks:
view.addOnAttachStateChangeListener(...)
or
ViewCompat.setOnApplyWindowInsetsListener(...)
Here is the problem I am facing. On a empty relative layout, when touched textview is instantiated at the touched x y position. I got this far correct, but the problem is that when I touch on the empty space near already instantiated view, previous view and currently placed views are overlapped. I tried by the getting the child views of the layout and checking the current view and already placed view using rect data that if they intersect. How to solve this problem?
Here is the code:
public class MainActivity extends AppCompatActivity
{
private int id = 0;
private RelativeLayout root;
private RelativeLayout.LayoutParams params;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_designer);
root = (RelativeLayout) findViewById(R.id.rootlayout);
root.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
instantiateView(v, event);
break;
}
return true;
}
});
}
private void instantiateView(View v, MotionEvent event)
{
int x = (int) event.getX();
int y = (int) event.getY();
TextView bt = new TextView(DesignerActivity.this);
bt.setText("1");
bt.setId(++id);
bt.setBackgroundColor(Color.BLACK);
bt.setTextColor(Color.WHITE);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
showDialog();
}
});
params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(x, y, 0, 0);
bt.setLayoutParams(params);
//((ViewGroup) v).addView(bt);
if(root.getChildCount() <= 0)
{
((ViewGroup) v).addView(bt);
}
else
{
for (int i = 0; i < root.getChildCount(); i++)
{
if (!checkCollision(bt, root.getChildAt(i)))
{
if(bt != root.getChildAt(i))
{
((ViewGroup) v).addView(bt);
}
}
}
}
}
private void showDialog()
{
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.dialog_layout);
Button editBtn = (Button) dialog.findViewById(R.id.button1);
Button deleteBtn = (Button) dialog.findViewById(R.id.button2);
editBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
dialog.dismiss();
}
});
deleteBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
dialog.dismiss();
}
});
dialog.show();
}
private boolean checkCollision(View v1, View v2)
{
Rect r1 = new Rect(v1.getLeft(), v1.getTop(), v1.getRight(), v1.getBottom());
Rect r2 = new Rect(v2.getLeft(), v2.getTop(), v2.getRight(), v2.getBottom());
return r1.intersect(r2);
}
}
You are using Relative Layout that's why your Textviews are overlapping.
If you don't want the overlapping and want to place it next or somewhere else to the overlapped view , it is your decision. Just check if they intersect and take appropriate decision based on your requirement.
Below line is the problem in your code.
Rect r1 = new Rect(v1.getLeft(), v1.getTop(), v1.getRight(), v1.getBottom());
You set the params' Margin does not mean that you will get desired left,top,right, bottom values.You will get these values right after the inflation of your view hierarchy.
You can use this function:
private boolean checkCollision(View v1, View v2)
{
int leftMargin = ((RelativeLayout.LayoutParams) v1.getLayoutParams()).leftMargin;
int topMargin = ((RelativeLayout.LayoutParams) v1.getLayoutParams()).topMargin;
Rect r1 = new Rect(root.getPaddingLeft() + leftMargin, root.getPaddingTop() + topMargin,
root.getPaddingLeft() + leftMargin + v2.getWidth(), root.getPaddingTop() + topMargin + v2.getHeight());
Rect r2 = new Rect(v2.getLeft(), v2.getTop(), v2.getRight(), v2.getBottom());
return r1.intersect(r2);
}
After that use
params.addRule(); according to your requirement where you want to place your overlapping view.
I am using Slider like gmail or Facbook in android this is fine. What i have done is i just created a new activity and given animation to it so it looks like slider. Now what i want is when user click any button in slider a new activity should open and perform task what i specify in it. But i am not getting how to pass click event in slider.
My code
public class PlayAudio extends Activity implements OnCompletionListener,
SeekBar.OnSeekBarChangeListener {
boolean alreadyShowing = false;
private int windowWidth;
private int windowHeight;
private PopupWindow fadePopup;
private Animation ta;
private RelativeLayout baseView;
LayoutInflater inflater;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.player);
Display display = getWindowManager().getDefaultDisplay();
windowWidth = display.getWidth();
windowHeight = display.getHeight();
inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
findViewById(R.id.imageView1).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (!alreadyShowing) {
alreadyShowing = true;
openSlidingMenu();
}
}
});
findViewById(R.id.imageView3).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (!alreadyShowing) {
alreadyShowing = true;
openSlidingMenu();
}
}
});
}
private void openSlidingMenu() {
showFadePopup();
int width = (int) (windowWidth * 0.8f);
translateView((float) (width));
#SuppressWarnings("deprecation")
int height = LayoutParams.FILL_PARENT;
// creating a popup
final View layout = inflater.inflate(R.layout.option_popup_layout,
(ViewGroup) findViewById(R.id.popup_element));
final PopupWindow optionsPopup = new PopupWindow(layout, width, height,
true);
optionsPopup.setBackgroundDrawable(new PaintDrawable());
optionsPopup.showAtLocation(layout, Gravity.NO_GRAVITY, 0, 0);
optionsPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
public void onDismiss() {
// Removing the fade effect
fadePopup.dismiss();
// to clear the previous animation transition in
cleanUp();
// move the view out
translateView(0);
// to clear the latest animation transition out
cleanUp();
// resetting the variable
alreadyShowing = false;
}
});
}
private void showFadePopup() {
final View layout = inflater.inflate(R.layout.fadepopup,
(ViewGroup) findViewById(R.id.fadePopup));
fadePopup = new PopupWindow(layout, windowWidth, windowHeight, false);
fadePopup.showAtLocation(layout, Gravity.NO_GRAVITY, 0, 0);
}
private void translateView(float right) {
ta = new TranslateAnimation(0f, right, 0f, 0f);
ta.setDuration(100);
ta.setFillEnabled(true);
ta.setFillAfter(true);
baseView = (RelativeLayout) findViewById(R.id.Player_Slider);
baseView.startAnimation(ta);
baseView.setVisibility(View.VISIBLE);
}
private void cleanUp() {
if (null != baseView) {
baseView.clearAnimation();
baseView = null;
}
if (null != ta) {
ta.cancel();
ta = null;
}
fadePopup = null;
}
}
Here in click event i am calling openSlidingMenu function which open's new activity option_popup_layout (http://i.share.pho.to/fb125f6f_o.png)
Now what i want is when i click any of the image in option_popup_layout a new activity should open and i want perform some operation over there but i am not getting where i have to use click event to call new activity.
I have tried some piece of code to put click event inside creating function as well as other method too but not getting work.
Please help me to solve this. Thanks in advance.
I have a list of buttons. When I press a button, a View should slide in a downwards motion out of the button, like this:
Start:
Halfway:
End:
How would I go about this? The View that should slide out is bigger than the button, so first hiding the View behind the button and then sliding it downwards causes the View to be visible above the button. That should not happen.
Any ideas or examples on how to approach this?
I believe the simplest approach is to extend Animation class and override applyTransformation() to change the view's height as follows:
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.LinearLayout;
public class MyCustomAnimation extends Animation {
public final static int COLLAPSE = 1;
public final static int EXPAND = 0;
private View mView;
private int mEndHeight;
private int mType;
private LinearLayout.LayoutParams mLayoutParams;
public MyCustomAnimation(View view, int duration, int type) {
setDuration(duration);
mView = view;
mEndHeight = mView.getHeight();
mLayoutParams = ((LinearLayout.LayoutParams) view.getLayoutParams());
mType = type;
if(mType == EXPAND) {
mLayoutParams.height = 0;
} else {
mLayoutParams.height = LayoutParams.WRAP_CONTENT;
}
view.setVisibility(View.VISIBLE);
}
public int getHeight(){
return mView.getHeight();
}
public void setHeight(int height){
mEndHeight = height;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
if(mType == EXPAND) {
mLayoutParams.height = (int)(mEndHeight * interpolatedTime);
} else {
mLayoutParams.height = (int) (mEndHeight * (1 - interpolatedTime));
}
mView.requestLayout();
} else {
if(mType == EXPAND) {
mLayoutParams.height = LayoutParams.WRAP_CONTENT;
mView.requestLayout();
}else{
mView.setVisibility(View.GONE);
}
}
}
}
To use it, set your onclick() as follows:
int height;
#Override
public void onClick(View v) {
if(view2.getVisibility() == View.VISIBLE){
MyCustomAnimation a = new MyCustomAnimation(view2, 1000, MyCustomAnimation.COLLAPSE);
height = a.getHeight();
view2.startAnimation(a);
}else{
MyCustomAnimation a = new MyCustomAnimation(view2, 1000, MyCustomAnimation.EXPAND);
a.setHeight(height);
view2.startAnimation(a);
}
}
Regards.
Use something like:
Animation a = new ScaleAnimation(1, 1, 0, 1, Animation.RELATIVE_TO_SELF, (float) 0.5, Animation.RELATIVE_TO_SELF, (float) 0);
a.setFillAfter(true);
view.setAnimation(a);
a.setDuration(1000);
view.startAnimation(a);
Here is simple example of hand-made animation, that provide what you want. It works in test app, but I'm not sure that there is no bugs:
public class MainActivity extends Activity implements OnClickListener {
private Timer timer;
private TimerTask animationTask;
private View view1;
private View view2;
boolean animating;
boolean increasing = true;
int initHeight = -1;
private LayoutParams params;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timer = new Timer();
view1 = findViewById(R.id.view1);// clickable view
view1.setOnClickListener(this);
view2 = findViewById(R.id.view2);// animated view
params = view2.getLayoutParams();
}
#Override
protected void onDestroy() {
super.onDestroy();
timer.cancel();
}
#Override
public void onClick(View v) {
Toast.makeText(this, "start animating...", Toast.LENGTH_SHORT).show();
animationTask = new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (animationFinished()) {
animating = false;
cancel();//canceling animating task
return;
}
params.height += increasing ? 1 : -1;
view2.setLayoutParams(params);
}
});
}
private boolean animationFinished() {
int viewHeight = view2.getHeight();
if (increasing && viewHeight >= initHeight) {
return true;
}
if (!increasing && viewHeight <= 0) {
return true;
}
return false;
}
};
//if we already animating - we just change direction of animation
increasing = !increasing;
if (!animating) {
animating = true;
int height = view2.getHeight();
params.height = height;
view2.setLayoutParams(params);//change param "height" from "wrap_conent" to real height
if (initHeight < 0) {//height of view - we setup it only once
initHeight = height;
}
timer.schedule(animationTask, 0, 10);//changing repeat time here will fasten or slow down animation
}
}
}
Maybe you can set the height to 0 and gradually increase the height. But then you will have the problem that you have to be sure your text is aligned at the bottom of the view. And also to know what the maximal height of the view should be.
use a sliding list adapter so much easier than messing around with animations
https://github.com/tjerkw/Android-SlideExpandableListView
Simply pass android:animateLayoutChanges to LinearLayout that holds all the views, you will achieve your desired result.
I would do it like that. First the layout for the whole collapsible panel component: (pseudo xml)
RelativeLayout (id=panel, clip)
LinearLayout (id=content, alignParentBottom=true)
LinearLayout (id=handle, above=content)
This should ensure that the content is always below the handle.
Then when you need to collapse:
Animate the top margin of content from 0 to -content.height
Animate the height of the panel from current to current-content.height