Skip to content

Instantly share code, notes, and snippets.

@scabilbao
Created June 9, 2014 08:48
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save scabilbao/4a1be92a79abd38ac5c0 to your computer and use it in GitHub Desktop.
Save scabilbao/4a1be92a79abd38ac5c0 to your computer and use it in GitHub Desktop.
Android Floating View
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright Grupo SCA 2014 (@SCA_Consultores)
Licensed under the GPL General Public License, Version 3.0 (the "License"),
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.gnu.org/licenses/gpl.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Website: http://www.gruposca.com
Contact: Grupo SCA <hello@gruposca.com>
-->
<resources>
<declare-styleable name="FloatingView">
<attr name="scrollableView" format="reference|integer" />
</declare-styleable>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright Grupo SCA 2014 (@SCA_Consultores)
Licensed under the GPL General Public License, Version 3.0 (the "License"),
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.gnu.org/licenses/gpl.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Website: http://www.gruposca.com
Contact: Grupo SCA <hello@gruposca.com>
-->
<resources>
<dimen name="floating_view_size">150dp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright Grupo SCA 2014 (@SCA_Consultores)
Licensed under the GPL General Public License, Version 3.0 (the "License"),
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.gnu.org/licenses/gpl.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Website: http://www.gruposca.com
Contact: Grupo SCA <hello@gruposca.com>
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:state_pressed="false" android:drawable="@drawable/floating_view_normal" />
<item android:state_enabled="true" android:state_pressed="true" android:drawable="@drawable/floating_view_pressed" />
</selector>
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright Grupo SCA 2014 (@SCA_Consultores)
Licensed under the GPL General Public License, Version 3.0 (the "License"),
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.gnu.org/licenses/gpl.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Website: http://www.gruposca.com
Contact: Grupo SCA <hello@gruposca.com>
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:fillBefore="true">
<objectAnimator
android:valueFrom="-30"
android:valueTo="@dimen/floating_view_size"
android:propertyName="translationY"
android:interpolator="@android:interpolator/decelerate_cubic"
android:duration="@integer/floating_view_anim_duration" />
</set>
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright Grupo SCA 2014 (@SCA_Consultores)
Licensed under the GPL General Public License, Version 3.0 (the "License"),
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.gnu.org/licenses/gpl.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Website: http://www.gruposca.com
Contact: Grupo SCA <hello@gruposca.com>
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:fillBefore="true">
<objectAnimator
android:valueFrom="@dimen/floating_view_size"
android:valueTo="-30"
android:propertyName="translationY"
android:interpolator="@android:interpolator/decelerate_cubic"
android:duration="@integer/floating_view_anim_duration" />
</set>
/**
Copyright Grupo SCA 2014 (@SCA_Consultores)
Licensed under the GPL General Public License, Version 3.0 (the "License"),
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.gnu.org/licenses/gpl.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Website: http://www.gruposca.com
Contact: Grupo SCA <hello@gruposca.com>
*/
package com.gruposca.android.innovaapps.ui.views;
import com.gruposca.android.innovaapps.R;
import com.gruposca.android.innovaapps.helpers.ExceptionsHelper;
import com.gruposca.android.innovaapps.helpers.LogsHelper;
import android.animation.Animator.AnimatorListener;
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
public class FloatingView extends FrameLayout implements OnScrollListener {
public interface OnFloatingViewChange {
void onShow(FloatingView view);
void onHide(FloatingView view);
}
private int mLastShowedItem = 0;
private int mScrollableViewId;
private AbsListView mScrollableView;
private boolean mShoweb = false;
private OnFloatingViewChange mListener;
private OnScrollListener mScrollListener;
public FloatingView(Context context) { super(context); }
public FloatingView(Context context, AttributeSet attrs) { super(context, attrs); initializeAttributes(attrs); }
public FloatingView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initializeAttributes(attrs); }
private AnimatorListener mHidenAnimatorListener = new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) { }
@Override
public void onAnimationRepeat(Animator animation) { }
@Override
public void onAnimationEnd(Animator animation) {
if (mListener != null)
mListener.onHide(FloatingView.this);
}
@Override
public void onAnimationCancel(Animator animation) { }
};
private AnimatorListener mShowedAnimatorListener = new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) { }
@Override
public void onAnimationRepeat(Animator animation) { }
@Override
public void onAnimationEnd(Animator animation) {
if (mListener != null)
mListener.onShow(FloatingView.this);
}
@Override
public void onAnimationCancel(Animator animation) { }
};
public void setOnScrollListener(OnScrollListener listener) { mScrollListener = listener; }
public void setOnFloatingViewChange(OnFloatingViewChange listener) { mListener = listener; }
/**
* Set the scrollable view linked to the FloatingView.
*/
public void setScrollableView(AbsListView scrollableView) { mScrollableView = scrollableView; }
/**
* Set the scrollable view ID linked to the FloatingView.
*/
public void setScrollableViewId(int id) { mScrollableViewId = id; }
/**
* Returns true or false if the view is showed.
*/
public boolean isShown() { return mShoweb; }
@Override
protected void onAttachedToWindow() {
initializeView();
showView(); //Display the View.
}
@Override
protected Parcelable onSaveInstanceState() {
Bundle savedState = new Bundle();
try {
savedState.putParcelable("instanceState", super.onSaveInstanceState());
if (mScrollableView != null)
savedState.putInt("scrollabeViewId", mScrollableView.getId());
else
savedState.putInt("scrollabeViewId", 0);
} catch (Exception e) {
ExceptionsHelper.manage(getContext(), e);
}
return savedState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
try {
if (state instanceof Bundle) {
Bundle bundle = (Bundle)state;
mScrollableViewId = bundle.getInt("scrollabeViewId");
state = bundle.getParcelable("instanceState");
configureScrollabeView();
}
super.onRestoreInstanceState(state);
} catch (Exception e) {
ExceptionsHelper.manage(getContext(), e);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem > mLastShowedItem) {
hideView();
} else if (firstVisibleItem < mLastShowedItem) {
showView();
}
mLastShowedItem = firstVisibleItem;
if (mScrollListener != null)
mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) { if (mScrollListener != null) mScrollListener.onScrollStateChanged(view, scrollState); }
/**
* Initialize view properties.
*/
private void initializeView() {
if (getParent() instanceof RelativeLayout) {
RelativeLayout.LayoutParams paramns = (RelativeLayout.LayoutParams)getLayoutParams();
paramns.addRule(RelativeLayout.CENTER_HORIZONTAL);
paramns.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
setClickable(true);
configureScrollabeView();
} else {
LogsHelper.log("The parent view of FloatingView not is a RelativeLayout, please put this view inside of RelativeLayout.");
}
}
/**
* Configure the listeners of the linked Scrollable view.
*/
private void configureScrollabeView() {
if (mScrollableView == null) {
if (mScrollableViewId != 0) {
View scrollableView = ((RelativeLayout)getParent()).findViewById(mScrollableViewId);
if (scrollableView instanceof AbsListView) {
mScrollableView = (AbsListView)scrollableView;
} else {
LogsHelper.log("The ScrollableView linked to this view it's not instance of AbsListView.");
}
}
}
if (mScrollableView != null) {
if (mScrollableView.getId() == View.NO_ID)
LogsHelper.log("The ScrollableView linked to this view does not have set the ID attribute.");
mScrollableView.setOnScrollListener(this);
}
}
/**
* Initialize custom attributes.
*/
private void initializeAttributes(AttributeSet attrs) {
if (attrs != null) {
TypedArray customChartParameters = getContext().obtainStyledAttributes(attrs, R.styleable.FloatingView);
if (customChartParameters != null) {
mScrollableViewId = customChartParameters.getInt(R.styleable.FloatingView_scrollableView, 0);
customChartParameters.recycle();
}
}
}
/**
* Execute the animation and show the view on the screen.
*/
public void showView() {
if (!isShown()) {
mShoweb = true;
AnimatorSet animatorSet = (AnimatorSet)AnimatorInflater.loadAnimator(getContext(), R.anim.floating_view_show);
animatorSet.setTarget(this);
animatorSet.addListener(mShowedAnimatorListener);
animatorSet.start();
}
}
/**
* Execute the animation and hide the view.
*/
public void hideView() {
if (isShown()) {
mShoweb = false;
AnimatorSet animatorSet = (AnimatorSet)AnimatorInflater.loadAnimator(getContext(), R.anim.floating_view_hide);
animatorSet.setTarget(this);
animatorSet.addListener(mHidenAnimatorListener);
animatorSet.start();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright Grupo SCA 2014 (@SCA_Consultores)
Licensed under the GPL General Public License, Version 3.0 (the "License"),
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.gnu.org/licenses/gpl.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Website: http://www.gruposca.com
Contact: Grupo SCA <hello@gruposca.com>
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="none"
android:drawSelectorOnTop="true"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:scrollbars="none" />
<com.gruposca.android.innovaapps.ui.views.FloatingView
style="@style/floating_view"
android:id="@+id/Halls:Floating" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright Grupo SCA 2014 (@SCA_Consultores)
Licensed under the GPL General Public License, Version 3.0 (the "License"),
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.gnu.org/licenses/gpl.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Website: http://www.gruposca.com
Contact: Grupo SCA <hello@gruposca.com>
-->
<resources>
<style name="floating_view">
<item name="android:layout_width">@dimen/floating_view_size</item>
<item name="android:layout_height">@dimen/floating_view_size</item>
<item name="android:background">@drawable/float_view_selector</item>
</style>
</resources>
@MiguelCatalan
Copy link

Un detallito sin mucha importancia, falta la dimensión de:

@integer/floating_view_anim_duration

@luiszacheu
Copy link

How use this component in my listview?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment