I want to develop my own Accept and Decline buttons for an incoming call. To prevent the call to be accidentally answered or rejected when taking the phone out of the pocket I would like to make a slider style button or something similar. I am, to accept the call is not just to tap on the Accept button. It would be more like sliding the finger from left to right (or opposite) and let the button get wider with the moment. Just like Android does.
Is there any way to make this? Any hint?
I hope to be clear.
How about create an image and slide it to the right (or left) and then send the event to an Activity or any view that you wanna handle the result?
For this, you can created a custom view which implements OnTouchListener :
public class ImageTouchSlider extends RelativeLayout implements View.OnTouchListener {
private Context mContext;
private ImageView mImage;
private int mScreenWidthInPixel;
private int mScreenWidthInDp;
private float mDensity;
private int mPaddingInDp = 15;
private int mPaddingInPixel;
private int mLengthOfSlider;
public interface OnImageSliderChangedListener{
void onChanged();
}
private OnImageSliderChangedListener mOnImageSliderChangedListener;
public ImageTouchSlider(Context context) {
super(context);
mContext = context;
createView();
}
public ImageTouchSlider(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
createView();
}
public ImageTouchSlider(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
createView();
}
public void createView() {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.image_touch_slider, this, true);
mImage = (ImageView) findViewById(R.id.slider_image);
mImage.setOnTouchListener(this);
WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics ();
display.getMetrics(outMetrics);
mDensity = getResources().getDisplayMetrics().density;
float dpWidth = outMetrics.widthPixels / mDensity;
mScreenWidthInPixel = outMetrics.widthPixels;
mScreenWidthInDp = (int) (mScreenWidthInPixel / mDensity);
mLengthOfSlider = (int) (mScreenWidthInDp - mPaddingInDp*2);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
int width = v.getWidth();
float xPos = event.getRawX();
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
// You can add some clicked reaction here.
break;
case MotionEvent.ACTION_MOVE:
if(xPos < (mScreenWidthInPixel - width - mPaddingInDp*mDensity) && xPos > mPaddingInDp*mDensity) {
mOnImageSliderChangedListener.onChanged();
layoutParams.leftMargin = (int) xPos - width / 2;
mImage.setLayoutParams(layoutParams);
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return true;
}
public void setOnImageSliderChangedListener(OnImageSliderChangedListener listener) {
mOnImageSliderChangedListener = listener;
}
} //end of class
image_touch_slider.xml layout :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/slider"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerVertical="true"
android:src="#drawable/your_drawable" />
</RelativeLayout>
You can modify screen width calculation part (my current code is not so clean), and add this view in .xml like this :
<com.your.package.path.ImageTouchSlider
android:id="#+id/slider"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
In your class, you can find this view :
ImageTouchSlider slider = (ImageTouchSlider) findViewById(R.id.slider);
slider.setOnImageSliderChangedListener(new ImageTouchSlider.OnImageSliderChangedListener() {
#Override
public void onChanged() {
// do something what you want here.
}
});
Hope this can help! :)
If you have your own sliding layout then see this code, might be helpful for you.
public class UnlockBar extends RelativeLayout
{
private OnUnlockListener listener = null;
private TextView text_label = null;
private ImageView img_thumb = null;
private int thumbWidth = 0;
boolean sliding = false;
private int sliderPosition = 0;
int initialSliderPosition = 0;
float initialSlidingX = 0;
public UnlockBar(Context context)
{
super(context);
init(context, null);
}
public UnlockBar(Context context, AttributeSet attrs)
{
super(context, attrs);
init(context, attrs);
}
public UnlockBar(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init(context, attrs);
}
public void setOnUnlockListener(OnUnlockListener listener)
{
this.listener = listener;
}
public void reset()
{
final RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) img_thumb.getLayoutParams();
ValueAnimator animator = ValueAnimator.ofInt(params.leftMargin, 0);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator)
{
params.leftMargin = (Integer) valueAnimator.getAnimatedValue();
img_thumb.requestLayout();
}
});
animator.setDuration(300);
animator.start();
text_label.setAlpha(1f);
}
private void init(Context context, AttributeSet attrs)
{
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.unlock_main, this, true);
// Retrieve layout elements
text_label = (TextView) findViewById(R.id.text_label);
img_thumb = (ImageView) findViewById(R.id.img_thumb);
// Get padding
thumbWidth = dpToPx(80); // 60dp + 2*10dp
}
#Override
#SuppressLint("ClickableViewAccessibility")
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
if (event.getX() > sliderPosition && event.getX() < (sliderPosition + thumbWidth))
{
sliding = true;
initialSlidingX = event.getX();
initialSliderPosition = sliderPosition;
}
}
else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_OUTSIDE)
{
if (sliderPosition >= (getMeasuredWidth() - thumbWidth))
{
if (listener != null) listener.onUnlock();
}
else
{
sliding = false;
sliderPosition = 0;
reset();
}
}
else if (event.getAction() == MotionEvent.ACTION_MOVE && sliding)
{
sliderPosition = (int) (initialSliderPosition + (event.getX() - initialSlidingX));
if (sliderPosition <= 0) sliderPosition = 0;
if (sliderPosition >= (getMeasuredWidth() - thumbWidth))
{
sliderPosition = (int) (getMeasuredWidth() - thumbWidth);
}
else
{
int max = (int) (getMeasuredWidth() - thumbWidth);
int progress = (int) (sliderPosition * 100 / (max * 1.0f));
text_label.setAlpha(1f - progress * 0.02f);
}
setMarginLeft(sliderPosition);
}
return true;
}
private void setMarginLeft(int margin)
{
if (img_thumb == null) return;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) img_thumb.getLayoutParams();
params.setMargins(margin, 0, 0, 0);
img_thumb.setLayoutParams(params);
}
private int dpToPx(int dp)
{
float density = getResources().getDisplayMetrics().density;
return Math.round((float)dp * density);
}
public static interface OnUnlockListener {
void onUnlock();
}
}
And just set the listener in main activity
UnlockBar unlock = (UnlockBar) findViewById(R.id.unlock);
// Attach listener
unlock.setOnUnlockListener(new OnUnlockListener() {
#Override
public void onUnlock()
{
Toast.makeText(TestActivity.this, "You've successfully unlocked it !", Toast.LENGTH_LONG).show();
}
});
And draw your own slide_image_layout.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="80dp"
android:layout_width="match_parent"
android:background="#000000"
android:padding="10dp">
<ImageView
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_alignParentLeft="true"
android:src="#drawable/unlock_left"
android:contentDescription="#string/unlock_locked" />
<ImageView
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_alignParentRight="true"
android:src="#drawable/unlock_right"
android:contentDescription="#string/unlock_unlocked" />
<TextView
android:id="#+id/text_label"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:text="#string/unlock_instructions"
android:textColor="#android:color/white"
android:textSize="18sp"
android:textStyle="italic" />
<ImageView
android:id="#+id/img_thumb"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:src="#drawable/unlock_thumb"
android:contentDescription="#string/unlock_thumb" />
</RelativeLayout>
And in your main_layout.xml add this ..
<com.hamondigital.unlock.UnlockBar
android:id="#+id/unlock"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Related
In this below code i want to set center_horizontal as attachmentSlidingLayer view id but layout_gravity and gravity for parent and child view doesn't work correctly and by default gravity is left side
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:slidingLayer="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<io.codetail.widget.RevealFrameLayout <!-- extends from FrameLayout -->
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal">
<com.test.libraries.SlidingLayer <!-- extends from BoundedFrameLayout-->
android:id="#+id/attachmentSlidingLayer"
android:layout_width="match_parent"
android:layout_height="210dp"
android:layout_gravity="center_horizontal"
android:elevation="5dp"
app:bounded_width="450dp"
android:foregroundGravity="center_horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:background="#drawable/sheet_shadow"
android:orientation="vertical"
app:bounded_width="450dp">
</LinearLayout>
</<com.test.libraries.SlidingLayer.SlidingLayer >
</io.codetail.widget.RevealFrameLayout>
</android.support.design.widget.CoordinatorLayout>
BoundedFrameLayout class:
public class BoundedFrameLayout extends FrameLayout {
private final int mBoundedWidth;
private final int mBoundedHeight;
public BoundedFrameLayout(Context context) {
super(context);
mBoundedWidth = 0;
mBoundedHeight = 0;
}
public BoundedFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BoundedView);
mBoundedWidth = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_width, 0);
mBoundedHeight = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_height, 0);
a.recycle();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Adjust width as necessary
int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
if (mBoundedWidth > 0 && mBoundedWidth < measuredWidth) {
int measureMode = MeasureSpec.getMode(widthMeasureSpec);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedWidth, measureMode);
}
// Adjust height as necessary
int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
if (mBoundedHeight > 0 && mBoundedHeight < measuredHeight) {
int measureMode = MeasureSpec.getMode(heightMeasureSpec);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedHeight, measureMode);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
RevealFrameLayout class:
public class RevealFrameLayout extends FrameLayout implements RevealAnimator{
private Path mRevealPath;
private final Rect mTargetBounds = new Rect();
private RevealInfo mRevealInfo;
private boolean mRunning;
private float mRadius;
public RevealFrameLayout(Context context) {
this(context, null);
}
public RevealFrameLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RevealFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mRevealPath = new Path();
}
#Override
public void onRevealAnimationStart() {
mRunning = true;
}
#Override
public void onRevealAnimationEnd() {
mRunning = false;
invalidate(mTargetBounds);
}
#Override
public void onRevealAnimationCancel() {
onRevealAnimationEnd();
}
#Override
public void setRevealRadius(float radius){
mRadius = radius;
mRevealInfo.getTarget().getHitRect(mTargetBounds);
invalidate(mTargetBounds);
}
#Override
public float getRevealRadius(){
return mRadius;
}
#Override
public void attachRevealInfo(RevealInfo info) {
mRevealInfo = info;
}
#Override
public SupportAnimator startReverseAnimation() {
if(mRevealInfo != null && mRevealInfo.hasTarget() && !mRunning) {
return ViewAnimationUtils.createCircularReveal(mRevealInfo.getTarget(),
mRevealInfo.centerX, mRevealInfo.centerY,
mRevealInfo.endRadius, mRevealInfo.startRadius);
}
return null;
}
#Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if(mRunning && child == mRevealInfo.getTarget()){
final int state = canvas.save();
mRevealPath.reset();
mRevealPath.addCircle(mRevealInfo.centerX, mRevealInfo.centerY, mRadius, Path.Direction.CW);
canvas.clipPath(mRevealPath);
boolean isInvalided = super.drawChild(canvas, child, drawingTime);
canvas.restoreToCount(state);
return isInvalided;
}
return super.drawChild(canvas, child, drawingTime);
}
}
I am working on a project where I need to design two vertical sliders as shown in the image below
I had developed code which working fine in a range of 0 to 100.
But I am not sure of how to convert it to 18 to 80
Here I am adding my class and view XML
any help is appreciated.
Following is my Layout
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.RelativeLayout;
import android.widget.TextView;
import wedviser.com.wedviser.R;
/**
* Created by Focaloid on 29-12-2016.
*/
public class RangeBarVerticalAge extends RelativeLayout {
private static final int TOTAL_DIVISION_COUNT = 100;
private static final int MAX_CLICK_DURATION = 200;
public OnRangeBarChangeListener onRangeBarChangeListener;
private int inactiveColor;
private int activeColor;
private double heightParent;
private View viewFilterMain, viewThumbMin, viewThumbMax;
private RelativeLayout relFilterMin, relFilterMax;
private float startYMin, startYMax;
private float movedYMin, movedYMax;
private int initialHeightMin;
private float dTopMin, dTopMax;
private int currentHeightMin, currentHeightMax;
private double resultMin = 0.0;
private double resultMax = 100.0;
private View viewParent;
// private TextView tvFilterMin, tvFilterMax;
private Context context;
private long startClickTime;
private RelativeLayout relativeLayout;
private int minRange = 0, maxRange = 100;
private View viewInActiveTop, viewInActiveBottom;
public RangeBarVerticalAge(Context context) {
super(context);
this.context = context;
initialize(context);
}
public RangeBarVerticalAge(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RangeBarVerticalAge, 0, 0);
System.out.println(a.getIndexCount());
activeColor = a.getColor(R.styleable.RangeBarVerticalAge_activeColor, Color.parseColor("#007FFF"));
inactiveColor = a.getColor(R.styleable.RangeBarVerticalAge_inactiveColor, Color.parseColor("#808080"));
a.recycle();
initialize(context);
}
public RangeBarVerticalAge(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
initialize(context);
}
public static float convertDpToPixel(float dp, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
return dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
private void initialize(Context context) {
inflate(context, R.layout.rangebar_age, this);
onRangeBarChangeListener = (OnRangeBarChangeListener) context;
onRangeBarChangeListener.onRangeBarChangeAge((int) resultMin, (int) resultMax);
relativeLayout = (RelativeLayout) findViewById(R.id.rel_main);
// tvFilterMin = (TextView) findViewById(R.id.tv_filter_min);
//tvFilterMax = (TextView) findViewById(R.id.tv_filter_max);
relFilterMin = (RelativeLayout) findViewById(R.id.rel_filter_min);
relFilterMax = (RelativeLayout) findViewById(R.id.rel_filter_max);
viewThumbMax = findViewById(R.id.oval_thumb_max);
viewThumbMin = findViewById(R.id.oval_thumb_min);
viewFilterMain = findViewById(R.id.filter_main_view);
viewParent = findViewById(R.id.view_filter_parent);
viewInActiveTop = findViewById(R.id.view_inactive_line_top);
viewInActiveBottom = findViewById(R.id.view_inactive_line_bottom);
init();
relFilterMin.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startYMin = event.getRawY();
// startClickTime = Calendar.getInstance().getTimeInMillis();
break;
case MotionEvent.ACTION_UP: {
// long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
// if (clickDuration < MAX_CLICK_DURATION) {
// //Click event triggered
//
// }
break;
}
case MotionEvent.ACTION_MOVE:
movedYMin = event.getRawY() - startYMin;
startYMin = event.getRawY();
if (v.getHeight() + movedYMin <= initialHeightMin || dTopMin + v.getHeight() + movedYMin >= dTopMax) {
currentHeightMin = v.getHeight();
getResultMin();
break;
}
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.height += movedYMin;
v.setLayoutParams(layoutParams);
dTopMin = v.getY();
currentHeightMin = v.getHeight();
getResultMin();
break;
default:
return false;
}
return true;
}
});
relFilterMax.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startYMax = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
movedYMax = event.getRawY() - startYMax;
startYMax = event.getRawY();
if (v.getHeight() - movedYMax <= initialHeightMin || v.getY() + movedYMax <= currentHeightMin + dTopMin) {
currentHeightMax = v.getHeight();
getResultMax();
break;
}
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.height -= movedYMax;
v.setLayoutParams(layoutParams);
dTopMax = v.getY();
currentHeightMax = v.getHeight();
getResultMax();
break;
default:
return false;
}
return true;
}
});
}
private void init() {
// ViewCompat.setElevation(tvFilterMin, 100f);
viewFilterMain.setBackgroundColor(activeColor);
viewInActiveBottom.setBackgroundColor(inactiveColor);
viewInActiveTop.setBackgroundColor(inactiveColor);
initialHeightMin = (int) convertDpToPixel(30, context);
final ViewTreeObserver viewTreeObserver = relativeLayout.getViewTreeObserver();
// if (viewTreeObserver.isAlive())
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
viewParent.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
viewParent.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
dTopMin = relFilterMin.getY();
dTopMax = relFilterMax.getY();
currentHeightMin = relFilterMin.getHeight();
System.out.println("viewParentGetHeight:" + viewParent.getHeight());
heightParent = viewParent.getHeight() - 2 * initialHeightMin;
}
});
}
public void getResultMin() {
//Max
resultMin = Math.floor(100 * (Math.abs(currentHeightMin - initialHeightMin)) / heightParent);
//tvFilterMin.setText((int) resultMin + "");
onRangeBarChangeListener.onRangeBarChangeAge((int) resultMin, (int) resultMax);
}
public void getResultMax() {
resultMax = Math.floor(100 * (Math.abs(currentHeightMax - initialHeightMin)) / heightParent);
resultMax = Math.abs(resultMax - 100);
//tvFilterMax.setText(((int) resultMax + ""));
onRangeBarChangeListener.onRangeBarChangeAge((int) resultMin, (int) resultMax);
}
public int getMinimumProgress() {
return (int) resultMin;
}
public void setMinimumProgress(final int minProgress) {
if (minProgress >= 0 && minProgress < 100 && minProgress < resultMax) {
resultMin = minProgress;
viewParent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
viewParent.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
viewParent.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
currentHeightMin = ((minProgress * (viewParent.getHeight() - 2 * initialHeightMin) / 100) + initialHeightMin);
ViewGroup.LayoutParams layoutParams = relFilterMin.getLayoutParams();
layoutParams.height = currentHeightMin;
relFilterMin.setLayoutParams(layoutParams);
}
});
//tvFilterMin.setText((int) resultMin + "");
onRangeBarChangeListener.onRangeBarChangeAge((int) resultMin, (int) resultMax);
}
}
public int getMaximumProgress() {
return (int) resultMax;
}
public void setMaximumProgress(final int maxProgress) {
if (maxProgress >= 0 && maxProgress <= 100 && maxProgress > resultMin) {
resultMax = maxProgress;
viewParent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
viewParent.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
viewParent.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
currentHeightMax = ((Math.abs(maxProgress - 100) * (viewParent.getHeight() - 2 * initialHeightMin) / 100) + initialHeightMin);
ViewGroup.LayoutParams layoutParams = relFilterMax.getLayoutParams();
layoutParams.height = currentHeightMax;
relFilterMax.setLayoutParams(layoutParams);
}
});
// tvFilterMax.setText((int) resultMax + "");
onRangeBarChangeListener.onRangeBarChangeAge((int) resultMin, (int) resultMax);
}
}
public interface OnRangeBarChangeListener {
void onRangeBarChangeAge(int min, int max);
}
}
Folowing is my XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rel_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"
android:orientation="vertical"
android:animateLayoutChanges="true"
>
<View
android:id="#+id/view_filter_parent"
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#android:color/transparent"
android:clickable="false" />
<View
android:id="#+id/filter_main_view"
android:layout_width="2dp"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_marginBottom="20dp"
android:layout_alignRight="#+id/rel_filter_min"
android:layout_alignEnd="#+id/rel_filter_min"
android:layout_marginRight="11dp"
android:layout_marginEnd="11dp"
android:background="#2196f3" />
<RelativeLayout
android:id="#+id/rel_filter_min"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_gravity="bottom"
>
<RelativeLayout
android:id="#+id/rel_filter_min_text"
android:layout_alignParentBottom="true"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:background="#android:color/transparent"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></RelativeLayout>
<View
android:id="#+id/view_inactive_line_top"
android:layout_width="2dp"
android:layout_height="match_parent"
android:layout_marginTop="5dp"
android:layout_alignLeft="#+id/oval_thumb_min"
android:layout_alignStart="#+id/oval_thumb_min"
android:layout_marginLeft="8.5dp"
android:layout_marginStart="8.5dp"
android:layout_marginBottom="10dp"
android:background="#808080" />
<View
android:id="#+id/oval_thumb_min"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_toRightOf="#+id/rel_filter_min_text"
android:layout_toEndOf="#+id/rel_filter_min_text"
android:layout_centerInParent="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="4dp"
android:background="#drawable/oval_shape"
/>
</RelativeLayout>
<RelativeLayout
android:id="#+id/rel_filter_max"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_alignLeft="#+id/filter_main_view"
android:layout_alignParentBottom="true"
android:layout_alignStart="#+id/filter_main_view"
android:layout_gravity="bottom"
android:layout_marginLeft="-11dp"
android:layout_marginStart="-11dp">
<View
android:id="#+id/view_inactive_line_bottom"
android:layout_width="2dp"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10.5dp"
android:layout_marginStart="10.5dp"
android:layout_marginTop="15dp"
android:background="#808080" />
<View
android:id="#+id/oval_thumb_max"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="#drawable/oval_shape"
/>
</RelativeLayout>
</RelativeLayout>
I'm coding a ring menu that is going to put together several different types of view, which will have all the same size. The thing is that it works perfectly with native views, like ImageView, but when I try to put a custom labeled image view, it simply doesn't appear int the custom ViewGroup. It's also worth mentioning that when this view is declared in the XML file, outside de custom ViewGroup it is shown just fine, but as soon as I put it inside the ViewGroup, or declare it programatically, it vanishes. My guess is that I'm doing something weong inside the onLayout method, but I can't put my finger on it, since all coordinates and view sizes are correct according to the Log.
The XML file for the CompoundView:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true">
<ImageView
android:id="#+id/header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:src="#drawable/ropeiconselector"/>
<TextView
android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="WWWWWWWWWWWW"
android:background="#color/button"
android:layout_marginLeft="-10dp"
android:layout_centerVertical="true"
android:layout_toRightOf="#id/header"
android:padding="8dp"
/>
The code for the CompoundView (I omitted some unimportant methods)
public class CircularLabeledImageView extends RelativeLayout implements View.OnClickListener {
ImageView headerView;
TextView labelView;
boolean isOpen = false;
String[] itemDesc;
int position;
int size;
int maxLabelWidth = 100;
int minLabelWidth = 20;
final Handler timeHandler = new Handler();
Runnable toggleTimer;
public CircularLabeledImageView(Context context) {
super(context);
//EDIT Methhod called
initView(context);
}
public CircularLabeledImageView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public CircularLabeledImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context){
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.expandabletextimageview, this);
headerView = (ImageView) this.findViewById(R.id.header);
labelView = (TextView) this.findViewById(R.id.label);
labelView.setBackgroundResource(R.color.backgroundMenuContents);
headerView.setOnClickListener(this);
itemDesc = new String[]{"Item A","Item B", "Item C","Quantos itens"};
size = itemDesc.length;
toggleTimer = new Runnable() {
#Override
public void run() {
toggle();
}
};
this.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (isOpen) {
toggle();
}
}
});
}
}
The code for the custom ViewGroup
public class RingListMenu extends ViewGroup implements View.OnClickListener {
boolean isOpen = true;
int headerSize= 90;
int childSize= 80;
int radiusInit = 150;
int childInitSize = 80;
int radius = 150;
int padding;
DPoint center = new DPoint();
float startingAngle= 2;
DPoint click0;
DPoint clickIni;
DPoint clickFinal;
final static float SENSIBILITY = 10f;
final static float FRICTION = 0.00001f;
final static float MAXVELOCITY = 0.06f;
final static long TOGGLE_DURATION = 300;
private VelocityTracker vTracker = null;
boolean isScrolling;
ImageView circleView;
OnItemClickListener listener = null;
public RingListMenu(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
if (android.os.Build.VERSION.SDK_INT >= 11)
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
TypedArray at = context.obtainStyledAttributes(attrs,R.styleable.RingListMenu);
childInitSize = childSize = at.getDimensionPixelSize(R.styleable.RingListMenu_childSize, 0);
radiusInit = radius = at.getDimensionPixelSize(R.styleable.RingListMenu_circleRadius, 0);
headerSize = at.getDimensionPixelSize(R.styleable.RingListMenu_headerSize, 0);
padding = at.getDimensionPixelSize(R.styleable.RingListMenu_padding, 0);
}
public RingListMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (android.os.Build.VERSION.SDK_INT >= 11)
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
TypedArray at = context.obtainStyledAttributes(attrs,R.styleable.RingListMenu);
childInitSize = childSize = at.getDimensionPixelSize(R.styleable.RingListMenu_childSize, 0);
radiusInit = radius = at.getDimensionPixelSize(R.styleable.RingListMenu_circleRadius, 0);
headerSize = at.getDimensionPixelSize(R.styleable.RingListMenu_headerSize, 0);
padding = at.getDimensionPixelSize(R.styleable.RingListMenu_padding, 0);
}
public RingListMenu(Context context, AttributeSet attrs) {
super(context, attrs);
if (android.os.Build.VERSION.SDK_INT >= 11)
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
TypedArray at = context.obtainStyledAttributes(attrs, R.styleable.RingListMenu);
childInitSize = childSize = at.getDimensionPixelSize(R.styleable.RingListMenu_childSize, 0);
radiusInit = radius = at.getDimensionPixelSize(R.styleable.RingListMenu_circleRadius, 0);
headerSize = at.getDimensionPixelSize(R.styleable.RingListMenu_headerSize, 0);
padding = at.getDimensionPixelSize(R.styleable.RingListMenu_padding, 0);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Log.d("RingList", "Calling Ring list onLayout" + childSize + " " + radius + " " + headerSize);
float angle = (float) (2*Math.PI)/(getChildCount()-1);
center.x = padding+headerSize/2;
center.y = padding+headerSize/2;
float childX;
float childY;
//radius = (float) (getChildCount()*(minSpacing+2*childSize)/(2*Math.PI));
for (int i = 1; i < getChildCount(); i++) {
View child = getChildAt(i);
childX = (float) (center.x + radius * Math.cos(startingAngle + i * angle));
childY = (float) (center.y + radius * Math.sin(startingAngle + i * angle));
child.layout((int) (childX - childSize / 2), (int) (childY - childSize / 2),
(int) (childX + childSize / 2), (int) (childY + childSize / 2));
}
View header = getChildAt(0);
header.setX(padding);
header.setY(padding);
header.layout(padding, padding, padding + headerSize, padding + headerSize);
}
#Override
public void addView(View child) {
child.setTag(getChildCount());
super.addView(child);
child.setOnClickListener(this);
}
}
And finally, the declaration part:
RingListMenu ring = (RingListMenu) findViewById(R.id.ring);
CircularLabeledImageView ViewA = new CircularLabeledImageView(this);
ring.addView(ViewA);
Hi Stackoverflow.
I've been trying to handle this issue for two days now.
We have a UnswipableViewPager, which is a custom implementation of ViewPager to intercept touch events and stop 'em (and nothing else), and right by it's right side we have a FrameLayout that we want to replace (through a FragmentTransaction) with our fragment. Nothing out of ordinary here if it wasn't for the fact our ViewPager has to shrink to fit the new Fragment. We have a custom implementation of RelativeLayout called ResizableLayout which we use to do that. It works ok with images, mind you, it's when we're loading a slide with a video, through a VideoView, that the issues pop.
This is how it looks from a design perspective. First we have it unshrunk, then we have it shrunk correctly, and last we have what happens whenever I try to load a slide with a VideoView inside it.
The snippet from the XML layout file:
<RelativeLayout
android:id="#+id/content_relative_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipChildren="false"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true">
<br.com.i9algo.taxiadv.v2.views.widgets.ResizableLayout
android:id="#+id/slideshow_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:clickable="true"
android:clipChildren="false"
android:orientation="horizontal"
android:scaleType="fitXY"
layout="#layout/slideshow_item_fragment">
<mypackage.widgets.UnswipableViewPager
android:id="#+id/playlist_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
layout="#layout/slideshow_item_fragment"
android:clipChildren="false"
android:clickable="true"
android:scaleType="fitXY"
/>
</mypackage.widgets.ResizableLayout>
<FrameLayout
android:id="#+id/sidebar_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:clipChildren="false"
android:layout_toEndOf="#+id/slideshow_frame"
android:scaleType="fitXY" />
</RelativeLayout>
Our ResizableLayout class:
public class ResizableLayout extends RelativeLayout {
private int originalHeight = 0;
private int originalWidth = 0;
private int minWidth = 0;
private static final float SLIDE_TOP = 0f;
private static final float SLIDE_BOTTOM = 1f;
private boolean mMinimized = false;
public ResizableLayout(Context context) {
this(context, null, 0);
}
public ResizableLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ResizableLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
if (!isInEditMode()) {
minWidth = getContext().getResources().getDimensionPixelSize(R.dimen.playlist_min_width);
}
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
public boolean smoothSlideTo(#NonNull float slideOffset) {
final int topBound = getPaddingTop();
int x = (int) (slideOffset * (getWidth() - getOriginalWidth()));
int y = (int) (topBound + slideOffset * getVerticalDragRange());
ViewCompat.postInvalidateOnAnimation(this);
return true;
}
public void minimize() {
if (isMinimized())
return;
mMinimized = true;
try {
ResizeAnimation resizeAnimation = new ResizeAnimation(this, minWidth, getOriginalHeight(), false);
resizeAnimation.setDuration(500);
resizeAnimation.setTopMargin(20);
setAnimation(resizeAnimation);
smoothSlideTo(SLIDE_BOTTOM);
requestLayout();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void maximize() {
if (isMaximized())
return;
mMinimized = false;
try {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) getLayoutParams();
params.width = getOriginalWidth();
params.topMargin = 0;
setLayoutParams(params);
measure(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
smoothSlideTo(SLIDE_TOP);
requestLayout();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public int getOriginalHeight() {
if (originalHeight == 0) {
originalHeight = getMeasuredHeight();
}
return originalHeight;
}
public int getOriginalWidth() {
if (originalWidth == 0) {
originalWidth = getMeasuredWidth();
}
return originalWidth;
}
public boolean isMinimized() {
return mMinimized;
}
public boolean isMaximized() {
return !mMinimized;
}
private float getVerticalDragRange() {
return getHeight() - getOriginalHeight();
}
This is ResizeAnimation in case anybody is wondering
public class ResizeAnimation extends Animation {
private final int mOriginalWidth;
private final int mOriginalHeight;
private final int mTargetWidth;
private final int mTargetHeight;
private int topMargin, leftMargin, bottomMargin, rightMargin;
private boolean mDown;
private View mView;
public ResizeAnimation(View view, int targetWidth, int targetHeight, boolean down) {
this.mView = view;
this.mTargetWidth = targetWidth;
this.mTargetHeight = targetHeight;
mOriginalWidth = view.getWidth();
mOriginalHeight = view.getHeight();
this.mDown = down;
}
public void setTopMargin(int value) {
this.topMargin = value;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newWidth = (int) (mOriginalWidth + (mTargetWidth - mOriginalWidth) * interpolatedTime);
int newHeight = (int) (mOriginalHeight + (mTargetHeight - mOriginalHeight) * interpolatedTime);
if (mDown) {
newWidth = mTargetWidth;
newHeight = mTargetHeight;
}
mView.getLayoutParams().width = newWidth;
mView.getLayoutParams().height = newHeight;
try {
((RelativeLayout.LayoutParams) mView.getLayoutParams()).topMargin = topMargin;
((RelativeLayout.LayoutParams) mView.getLayoutParams()).leftMargin = leftMargin;
((RelativeLayout.LayoutParams) mView.getLayoutParams()).bottomMargin = bottomMargin;
((RelativeLayout.LayoutParams) mView.getLayoutParams()).rightMargin = rightMargin;
} catch (Exception e) {
e.printStackTrace();
}
mView.requestLayout();
//mView.invalidate();
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
And this is the method that handles the FragmentTransaction.
#Override
public void showSidebarFragment() {
resizableLayout.minimize();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.sidebar_frame, sidebarFragment, "sidebarFragment");
ft.commit();
mContentRelativeLayout.requestLayout();
sidebarframe.requestLayout();
}
Mind you that Sidebarframe is injected through Butterknife and sidebarFragment is injected through Dagger2 - we use the same instance of the fragment for everything.
I have no clue what's going on. I've tried several ways of bringing the Fragment to front but nothing seems to work. I'd love if anyone could give me a hand either on how to fix the issue or how to achieve the same effect through other means - whatever works.
I have a next problem, which happens in 2 cases:
First case.
1). I have some custom veiw which draw photos on it with different opacity. here is method MyView.onDraw:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.getClipBounds(clipRect);
int i1 = Math.min(testColors.length-1, (int)Math.floor(posX/PHOTO_DISTANCE));
int c1 = testColors[Math.max(0, i1)];
int i2 = Math.min(testColors.length-1, (int)Math.ceil(posX/PHOTO_DISTANCE));
int c2 = testColors[Math.max(0, i2)];
paint.setColor(c1);
float r = (255f/PHOTO_DISTANCE*posX)%255;
paint.setAlpha(255);
if(photoA != null){//bitmap != null
bitmapRect.set(0, 0, photoA.getWidth(), photoA.getHeight());
canvas.drawBitmap(photoA, bitmapRect, clipRect, paint);
}
paint.setAlpha((int)(r));
if(photoB != null){//bitmap != null
bitmapRect.set(0, 0, photoB.getWidth(), photoB.getHeight());
canvas.drawBitmap(photoB, bitmapRect, clipRect, paint);
}
}
testColors - array of colors(int);
photoA, photoB - bitmaps;
i1, i2 - image indexes;
c1, c2 - colors. they are not importatant.
I added this view to FrameView:
viewHolder.myFrame.addView(viewHolder.myView, 0);
And in this FrameView I have some clickable RelativeLayout's:
<com.app.custom.view.ClickableRelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/share_action_container"
app1:pressedStateColor="#color/app_pressed_default"
app1:unpressedStateColor="#color/color_white"
android:background="#color/transparent"
android:layout_centerHorizontal="true">
<RelativeLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/circle_background"
android:id="#+id/share_icon"
android:layout_centerHorizontal="true">
<ImageView
android:id="#+id/img_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:tag="icon"
android:src="#drawable/ic_share"/>
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_below="#id/share_icon"
android:text="Share"
android:layout_marginTop="3dp"
android:shadowColor="#color/text_shadow"
android:shadowDx="#integer/shadowDX"
android:shadowDy="#integer/shadowDY"
android:shadowRadius="#integer/shadowRadius"
android:background="#color/transparent"
android:layout_centerHorizontal="true"
android:textSize="#dimen/icon_text_size"
android:tag="text"
android:textColor="#android:color/white"
android:id="#+id/txt_share_action"/>
</com.app.custom.view.ClickableRelativeLayout>
Here is a Java code of ClickableRelativeLayout:
public class ClickableRelativeLayout extends RelativeLayout implements View.OnTouchListener {
private ViewHolder viewHolder;
private int pressedStateColor;
private int unpressedStateColor;
private final int DEFAULT_PRESSED_STATE_COLOR;
private final int DEFAULT_UNPRESSED_STATE_COLOR;
public ClickableRelativeLayout(Context context) {
super(context);
DEFAULT_PRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_pressed_default);
DEFAULT_UNPRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_blue_without_transparent);
setup();
initColors(context, null);
}
public ClickableRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
DEFAULT_PRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_pressed_default);
DEFAULT_UNPRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_blue_without_transparent);
setup();
initColors(context, attrs);
}
public ClickableRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
DEFAULT_PRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_pressed_default);
DEFAULT_UNPRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_blue_without_transparent);
setup();
initColors(context, attrs);
}
private void setup(){
setOnTouchListener(this);
}
private void initColors(Context context, AttributeSet attrs){
if(attrs != null) {
TypedArray styledAttributes = context.obtainStyledAttributes(attrs, R.styleable.ClickableRelativeLayout);
pressedStateColor = styledAttributes.getColor(R.styleable.ClickableRelativeLayout_pressedStateColor,
DEFAULT_PRESSED_STATE_COLOR);
unpressedStateColor = styledAttributes.getColor(R.styleable.RowLayout_android_verticalSpacing,
DEFAULT_UNPRESSED_STATE_COLOR);
styledAttributes.recycle();
}else{
pressedStateColor = DEFAULT_PRESSED_STATE_COLOR;
unpressedStateColor = DEFAULT_UNPRESSED_STATE_COLOR;
}
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
viewHolder = new ViewHolder(
(TextView) findViewWithTag("text"),
(ImageView) findViewWithTag("icon")
);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
if (hasOnClickListeners()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
select();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
unSelect();
break;
}
}
}
return false;
}
private void select(){
if(isInitializedCorrect()){
final int color = pressedStateColor;
viewHolder.text.setTextColor(color);
ImageHelper.INSTANCE.applyColorFilterToImage(viewHolder.icon.getDrawable(), color);
}
}
private void unSelect(){
if(isInitializedCorrect()){
final int color = unpressedStateColor;
viewHolder.text.setTextColor(color);
viewHolder.icon.setColorFilter(color);
}
}
private boolean isInitializedCorrect(){
return viewHolder != null && viewHolder.icon != null && viewHolder.text != null;
}
private class ViewHolder{
ImageView icon;
TextView text;
public ViewHolder(TextView text, ImageView icon) {
this.text = text;
this.icon = icon;
}
}
}
And when I clicked on this layout, background of MyView shrinks, and sets to this ClickableRelativeLayout:
And Second case.
I have some text view on same frame, it is invisible by default, and when you scrolled 10 photos, I apply AlphaAnimation for this TextView and it draws slowly. Here is a code of alpha animation:
AlphaAnimation animation1 = new AlphaAnimation(0.0f, 1.0f);
animation1.setDuration(1300);
animation1.setFillAfter(true);
//here is my TextView
viewHolder.gotItView.setVisibility(View.VISIBLE);
viewHolder.gotItView.startAnimation(animation1);
And happens the same this. On background of this TextView appears content of MyView