Android create a marquee text - java

I'm developing a news application, I want to use a breaking news banner at the bottom of the layout.
The layout is :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="bottom">
<com.example.test.ScrollTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20dp"
android:background="#00ff00"
android:id="#+id/scrolltext">
</com.example.test.ScrollTextView>
</LinearLayout>
And the Java code is :
package com.example.test;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Color;
import android.os.Build;
import android.os.Handler;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.TranslateAnimation;
import android.widget.*;
import java.util.Map;
public class Newstest extends Activity
{
TextView label1;
#Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.news);
ScrollTextView scrolltext=(ScrollTextView) findViewById(R.id.scrolltext);
scrolltext.setText("dddddddddddddddddddddddddddddddddd sajd asjd lksdddddddddddddddddddddddddddddddddd sajd asjd lksdddddddddddddddddddddddddddddddddd sajd asjd lksdddddddddddddddddddddddddddddddddd sajd asjd lks");
scrolltext.setTextColor(Color.BLACK);
scrolltext.startScroll();
}
}
I'm using a ScrollTextView class :
package com.example.test;
import android.content.Context;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.animation.LinearInterpolator;
import android.widget.Scroller;
import android.widget.TextView;
public class ScrollTextView extends TextView {
// scrolling feature
private Scroller mSlr;
// milliseconds for a round of scrolling
private int mRndDuration = 10000;
// the X offset when paused
private int mXPaused = 0;
// whether it's being paused
private boolean mPaused = true;
/*
* constructor
*/
public ScrollTextView(Context context) {
this(context, null);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}
/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}
/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}
/**
* begin to scroll the text from the original position
*/
public void startScroll() {
// begin from the very right side
mXPaused = -1 * getWidth();
// assume it's paused
mPaused = true;
resumeScroll();
}
/**
* resume the scroll from the pausing point
*/
public void resumeScroll() {
if (!mPaused)
return;
// Do not know why it would not scroll sometimes
// if setHorizontallyScrolling is called in constructor.
setHorizontallyScrolling(true);
// use LinearInterpolator for steady scrolling
mSlr = new Scroller(this.getContext(), new LinearInterpolator());
setScroller(mSlr);
int scrollingLen = calculateScrollingLen();
int distance = scrollingLen - (getWidth() + mXPaused);
int duration = (new Double(mRndDuration * distance * 1.00000
/ scrollingLen)).intValue();
setVisibility(VISIBLE);
mSlr.startScroll(mXPaused,0, distance, 0, duration);
invalidate();
mPaused = false;
}
/**
* calculate the scrolling length of the text in pixel
*
* #return the scrolling length in pixels
*/
private int calculateScrollingLen() {
TextPaint tp = getPaint();
Rect rect = new Rect();
String strTxt = getText().toString();
tp.getTextBounds(strTxt, 0, strTxt.length(), rect);
int scrollingLen = rect.width() + getWidth();
rect = null;
return scrollingLen;
}
/**
* pause scrolling the text
*/
public void pauseScroll() {
if (null == mSlr)
return;
if (mPaused)
return;
mPaused = true;
// abortAnimation sets the current X to be the final X,
// and sets isFinished to be true
// so current position shall be saved
mXPaused = mSlr.getCurrX();
mSlr.abortAnimation();
}
#Override
/*
* override the computeScroll to restart scrolling when finished so as that
* the text is scrolled forever
*/
public void computeScroll() {
super.computeScroll();
if (null == mSlr) return;
if (mSlr.isFinished() && (!mPaused)) {
this.startScroll();
}
}
public int getRndDuration() {
return mRndDuration;
}
public void setRndDuration(int duration) {
this.mRndDuration = duration;
}
public boolean isPaused() {
return mPaused;
}
}
What I want is that the text will scroll from left to right, the opposite of what the class does. I tried changing parameters in the line mSlr.startScroll(mXPaused,0, distance, 0, duration); but the scrolling direction remains the same. Any help please

Have you tried marquee attribute? This should scroll text that doesn't fit the view
<TextView
android:layout_width="10dip"
android:layout_height="wrap_content"
android:text="FooBar FooBar FooBar FooBar"
android:singleLine="true"
android:ellipsize="marquee" />
http://developer.android.com/reference/android/widget/TextView.html#attr_android:ellipsize
From looking at the API docs:
http://developer.android.com/reference/android/widget/Scroller.html#startScroll(int, int, int, int)
Seems you can pass it negative numbers to scroll the opposite way, so try:
mSlr.startScroll(mXPaused, 0, -distance, 0, duration);

Marquee attribute only works for focused views, so use this view instead of textview beside android:ellipsize="marquee":
public class TextViewMarquee extends TextView
{
public TextViewMarquee(Context context, AttributeSet attrs)
{
super(context, attrs, R.attr.marqueeStyle);
}
public TextViewMarquee(Context context, AttributeSet attrs, int style)
{
super(context, attrs, style);
}
#Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect)
{
if(focused) super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
#Override
public void onWindowFocusChanged(boolean focused)
{
if(focused) super.onWindowFocusChanged(focused);
}
#Override
public boolean isFocused()
{
return true;
}
}

Related

PullToRefreshListView leaves space on top

I am using PullToRefreshListView to provide data reload when pulling the listview.
But my problem is that after refreshing, the layout leaves a space on top of the listview. See the image below:
I want to remove the space on top. I tried setting the view to View.GONE but it still leaves a small space in it.
Here's the code for the PullToRefreshListView.java:
package com.markupartist.android.widget;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
public class PullToRefreshListView extends ListView implements OnScrollListener {
private static final int TAP_TO_REFRESH = 1;
private static final int PULL_TO_REFRESH = 2;
private static final int RELEASE_TO_REFRESH = 3;
private static final int REFRESHING = 4;
private static final String TAG = "PullToRefreshListView";
private OnRefreshListener mOnRefreshListener;
/**
* Listener that will receive notifications every time the list scrolls.
*/
private OnScrollListener mOnScrollListener;
private LayoutInflater mInflater;
private RelativeLayout mRefreshView;
private TextView mRefreshViewText;
private ImageView mRefreshViewImage;
private ProgressBar mRefreshViewProgress;
private TextView mRefreshViewLastUpdated;
private int mCurrentScrollState;
private int mRefreshState;
private RotateAnimation mFlipAnimation;
private RotateAnimation mReverseFlipAnimation;
private int mRefreshViewHeight;
private int mRefreshOriginalTopPadding;
private int mLastMotionY;
private boolean mBounceHack;
public PullToRefreshListView(Context context) {
super(context);
init(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
// Load all of the animations we need in code rather than through XML
mFlipAnimation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mFlipAnimation.setInterpolator(new LinearInterpolator());
mFlipAnimation.setDuration(250);
mFlipAnimation.setFillAfter(true);
mReverseFlipAnimation = new RotateAnimation(-180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
mReverseFlipAnimation.setDuration(250);
mReverseFlipAnimation.setFillAfter(true);
mInflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mRefreshView = (RelativeLayout) mInflater.inflate(
R.layout.pull_to_refresh_header, this, false);
mRefreshViewText =
(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);
mRefreshViewImage =
(ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);
mRefreshViewProgress =
(ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);
mRefreshViewLastUpdated =
(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);
mRefreshViewImage.setMinimumHeight(50);
mRefreshView.setOnClickListener(new OnClickRefreshListener());
mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();
mRefreshState = TAP_TO_REFRESH;
addHeaderView(mRefreshView);
super.setOnScrollListener(this);
measureView(mRefreshView);
mRefreshViewHeight = mRefreshView.getMeasuredHeight();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setSelection(1);
}
#Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
setSelection(1);
}
/**
* Set the listener that will receive notifications every time the list
* scrolls.
*
* #param l The scroll listener.
*/
#Override
public void setOnScrollListener(OnScrollListener l) {
mOnScrollListener = l;
}
/**
* Register a callback to be invoked when this list should be refreshed.
*
* #param onRefreshListener The callback to run.
*/
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
mOnRefreshListener = onRefreshListener;
}
/**
* Set a text to represent when the list was last updated.
* #param lastUpdated Last updated at.
*/
public void setLastUpdated(CharSequence lastUpdated) {
if (lastUpdated != null) {
mRefreshViewLastUpdated.setVisibility(View.VISIBLE);
mRefreshViewLastUpdated.setText(lastUpdated);
} else {
mRefreshViewLastUpdated.setVisibility(View.GONE);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
final int y = (int) event.getY();
mBounceHack = false;
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (!isVerticalScrollBarEnabled()) {
setVerticalScrollBarEnabled(true);
}
if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
if ((mRefreshView.getBottom() >= mRefreshViewHeight
|| mRefreshView.getTop() >= 0)
&& mRefreshState == RELEASE_TO_REFRESH) {
// Initiate the refresh
mRefreshState = REFRESHING;
prepareForRefresh();
onRefresh();
} else if (mRefreshView.getBottom() < mRefreshViewHeight
|| mRefreshView.getTop() <= 0) {
// Abort refresh and scroll down below the refresh view
resetHeader();
setSelection(1);
}
}
break;
case MotionEvent.ACTION_DOWN:
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
applyHeaderPadding(event);
break;
}
return super.onTouchEvent(event);
}
private void applyHeaderPadding(MotionEvent ev) {
// getHistorySize has been available since API 1
int pointerCount = ev.getHistorySize();
for (int p = 0; p < pointerCount; p++) {
if (mRefreshState == RELEASE_TO_REFRESH) {
if (isVerticalFadingEdgeEnabled()) {
setVerticalScrollBarEnabled(false);
}
int historicalY = (int) ev.getHistoricalY(p);
// Calculate the padding to apply, we divide by 1.7 to
// simulate a more resistant effect during pull.
int topPadding = (int) (((historicalY - mLastMotionY)
- mRefreshViewHeight) / 1.7);
mRefreshView.setPadding(
mRefreshView.getPaddingLeft(),
topPadding,
mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
}
}
/**
* Sets the header padding back to original size.
*/
private void resetHeaderPadding() {
Log.i("top padding", "" + mRefreshOriginalTopPadding);
mRefreshView.setPadding(
mRefreshView.getPaddingLeft(),
0,
mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
/**
* Resets the header to the original state.
*/
private void resetHeader() {
if (mRefreshState != TAP_TO_REFRESH) {
mRefreshState = TAP_TO_REFRESH;
resetHeaderPadding();
// Set refresh view text to the pull label
//mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);
//mRefreshViewText.setVisibility(View.GONE);
// Replace refresh drawable with arrow drawable
mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);
// Clear the full rotation animation
mRefreshViewImage.clearAnimation();
// Hide progress bar and arrow.
mRefreshViewImage.setVisibility(View.GONE);
mRefreshViewProgress.setVisibility(View.GONE);
//this.setSelectionAfterHeaderView();
}
}
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0,
0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// When the refresh view is completely visible, change the text to say
// "Release to refresh..." and flip the arrow drawable.
if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL
&& mRefreshState != REFRESHING) {
if (firstVisibleItem == 0) {
mRefreshViewImage.setVisibility(View.VISIBLE);
if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20
|| mRefreshView.getTop() >= 0)
&& mRefreshState != RELEASE_TO_REFRESH) {
mRefreshViewText.setText(R.string.pull_to_refresh_release_label);
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mFlipAnimation);
mRefreshState = RELEASE_TO_REFRESH;
} else if (mRefreshView.getBottom() < mRefreshViewHeight + 20
&& mRefreshState != PULL_TO_REFRESH) {
mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);
if (mRefreshState != TAP_TO_REFRESH) {
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mReverseFlipAnimation);
}
mRefreshState = PULL_TO_REFRESH;
}
} else {
mRefreshViewImage.setVisibility(View.GONE);
resetHeader();
}
} else if (mCurrentScrollState == SCROLL_STATE_FLING
&& firstVisibleItem == 0
&& mRefreshState != REFRESHING) {
Log.i("I am here", "");
setSelection(1);
mBounceHack = true;
} else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) {
setSelection(1);
}
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem,
visibleItemCount, totalItemCount);
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
mCurrentScrollState = scrollState;
if (mCurrentScrollState == SCROLL_STATE_IDLE) {
mBounceHack = false;
}
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(view, scrollState);
}
}
public void prepareForRefresh() {
resetHeaderPadding();
mRefreshViewImage.setVisibility(View.GONE);
// We need this hack, otherwise it will keep the previous drawable.
mRefreshViewImage.setImageDrawable(null);
mRefreshViewProgress.setVisibility(View.VISIBLE);
// Set refresh view text to the refreshing label
mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);
mRefreshState = REFRESHING;
}
public void onRefresh() {
Log.d(TAG, "onRefresh");
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefresh();
}
}
/**
* Resets the list to a normal state after a refresh.
* #param lastUpdated Last updated at.
*/
public void onRefreshComplete(CharSequence lastUpdated) {
setLastUpdated(lastUpdated);
onRefreshComplete();
}
/**
* Resets the list to a normal state after a refresh.
*/
public void onRefreshComplete() {
Log.d(TAG, "onRefreshComplete");
resetHeader();
// If refresh view is visible when loading completes, scroll down to
// the next item.
if (getFirstVisiblePosition() == 0) {
invalidateViews();
setSelection(1);
}
resetHeader();
}
/**
* Invoked when the refresh view is clicked on. This is mainly used when
* there's only a few items in the list and it's not possible to drag the
* list.
*/
private class OnClickRefreshListener implements OnClickListener {
#Override
public void onClick(View v) {
if (mRefreshState != REFRESHING) {
prepareForRefresh();
onRefresh();
}
}
}
/**
* Interface definition for a callback to be invoked when list should be
* refreshed.
*/
public interface OnRefreshListener {
/**
* Called when the list should be refreshed.
* <p>
* A call to {#link PullToRefreshListView #onRefreshComplete()} is
* expected to indicate that the refresh has completed.
*/
public void onRefresh();
}
}
I would suggest you to Just disable listview onrefresh listener and
use android.support.v4.widget.SwipeRefreshLayout instead of pull to refresh listview . It is very easy to use.
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/refreshLater"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
***Place Your listview here***
</android.support.v4.widget.SwipeRefreshLayout >
you can set refresh listener on it like this:
public SwipeRefreshLayout swipeRefreshLayout;
swipeRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.refreshLater);
swipeRefreshLayout.setOnRefreshListener(this);
you can do needed code in the below override method:
#Override
public void onRefresh()
{
swipeRefreshLayout.setRefreshing(false);
}

Vertical SeekBar Android, how to update the slider position with SetProgress()

I know I'm not the first one having issue with a VerticalSlider on android but even though I recall struggling to make it work in the first place this is the first time that I have a partially working setProgress().
So here is the thing.
The blue line that represents the slider is properly updated but the tiny "button" that is supposed to moved as well does not move at all. (see images)
The blue line is moving according to to the values I send, but the "button" is not. It is moving a little, but not at all following the blue line---which is right. (If you have better terms for "button" and blue-line, feel free to edit. Progress line maybe?)
So this is the code I have for the vertical slider:
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.SeekBar;
public class VerticalSeekBar extends SeekBar {
public VerticalSeekBar(Context context) {
super(context);
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas canvas) {
canvas.rotate(-90);
canvas.translate(-getHeight(), 0);
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled())
return false;
boolean result = false;
if (event.getAction() != MotionEvent.ACTION_MOVE) {
// Prevent duplicate haptic feedback events (due to
// setProgress() below)
boolean hf = isHapticFeedbackEnabled();
setHapticFeedbackEnabled(false); {
// This is required for OnSeekBarChangeListener.on{Start,Stop}TrackingTouch()
result = super.onTouchEvent(event);
} setHapticFeedbackEnabled(hf);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
// Vertical scrolling
setProgress(getMax() - (int)(getMax() * event.getY()/getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
result = true;
break;
}
return result;
}
public void customSetProgress(int progress) {
setProgress(progress);
onSizeChanged(getWidth(), getHeight(), 0, 0);
}
}
And this how I'm updating the slider:
float value = //... Get the value here from other computations
// We need to use int for the slider
final int step = 1;
final int max = (int)MAXPRECISION * 100;
final int min = (int)MINPRECISION * 100;
final double initialPosition = (double)max ;
final int valueInt = (int) (value * 100) ;
final VerticalSeekBar sliderPrecision = (VerticalSeekBar)findViewById(R.id.verticalSliderPrecision);
sliderPrecision.setProgress(valueInt);
sliderPrecision.setMax( (max - min) / step ); //To make sure it is updated as seen in some SO post.
I am pretty confident that my VerticalSlider class is good as I have been able to use it properly years ago. So there is surely something wrong with the rest of the code, but I can't find what that may be.
As for the images here they are:
So I found out that this is solved by calling onSizeChanged(getWidth(), getHeight(), 0, 0);
So I have created an updated VerticalSeekBar that works just fine now.
I do hope it will help other people struggling with them.
Here is the updated class:
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.SeekBar;
public class VerticalSeekBar extends SeekBar {
public VerticalSeekBar(Context context) {
super(context);
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas canvas) {
canvas.rotate(-90);
canvas.translate(-getHeight(), 0);
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled())
return false;
boolean result = false;
if (event.getAction() != MotionEvent.ACTION_MOVE) {
// Prevent duplicate haptic feedback events (due to
// setProgress() below)
boolean hf = isHapticFeedbackEnabled();
setHapticFeedbackEnabled(false); {
// This is required for OnSeekBarChangeListener.on{Start,Stop}TrackingTouch()
result = super.onTouchEvent(event);
} setHapticFeedbackEnabled(hf);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
// Vertical scrolling
setProgress(getMax() - (int)(getMax() * event.getY()/getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
result = true;
break;
}
return result;
}
public void customSetProgress(int progress) {
setProgress(progress);
onSizeChanged(getWidth(), getHeight(), 0, 0);
}
}

Setting width of SeekBar to make "swipe to unlock" effect

I am attempting to make a swipe to unlock feature using a SeekBar. The look I am aiming for is shown here:
This is composed of two images, a background, and a button. I put both the background and the SeekBar in a FrameLayout so that the SeekBar should sit on top of the background.
Like so:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Testing 123..." />
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content" >
<ImageView
android:id="#+id/ImageView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:src="#drawable/unlockback" />
<SeekBar
android:id="#+id/myseek"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:max="100"
android:progressDrawable="#android:color/transparent"
android:thumb="#drawable/unlockbut" />
</FrameLayout>
</LinearLayout>
Unfortunately the end result looks like this (in eclipse):
I seem to be unable to make the SeekBar match the size of the FrameLayout. You can see the size of the Seekbar represented by a thin blue frame in the image above. The frame has two small solid blue squares which you can grab with the mouse pointer for resizing. But if I use my mouse pointer to drag the little blue square to match the full width of the FrameView, then as soon as I let go of the mouse, the square pings back to its original (too small) size.
What can I do to fix this?.. If I can achieve swipe to unlock in a fundamentally different way, then I'm interested in that too.
As I promised I will see what I can do. I have not used your images and used android graphics to do the drawing as that makes the whole thing more customizable and and scalable. If you do insist in drawing your images, use canvas.drawBitmap... it's pretty simple. The main logic can stay the same.
I may come back and add some fancy animations and visual effects, but for now I left some commented out code to play with shaders and gradients as I am a bit short on time at the moment.
Let's get to it... First crate attrs.xml in /resources/ and add this to it.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SlideToUnlock">
<attr name="sliderColor" format="color"/>
<attr name="cancelOnYExit" format="boolean"/>
<attr name="slideToUnlockText" format="string"/>
<attr name="slideToUnlockTextColor" format="color"/>
<attr name="slideToUnlockBackgroundColor" format="color"/>
<attr name="cornerRadiusX" format="dimension"/>
<attr name="cornerRadiusY" format="dimension"/>
</declare-styleable>
</resources>
And then SlideToUnlock.java
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.EmbossMaskFilter;
import android.graphics.MaskFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Typeface;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by ksenchy on 29.4.2015.
*/
public class SlideToUnlock extends View {
public interface OnSlideToUnlockEventListener {
public void onSlideToUnlockCanceled();
public void onSlideToUnlockDone();
}
private int measuredWidth, measuredHeight;
private float density;
private OnSlideToUnlockEventListener externalListener;
private Paint mBackgroundPaint, mTextPaint, mSliderPaint;
private float rx, ry; // Corner radius
private Path mRoundedRectPath;
private String text = "Unlock →";
float x;
float event_x, event_y;
float radius;
float X_MIN, X_MAX;
private boolean ignoreTouchEvents;
// Do we cancel when the Y coordinate leaves the view?
private boolean cancelOnYExit;
private boolean useDefaultCornerRadiusX, useDefaultCornerRadiusY;
/**
* Default values *
*/
int backgroundColor = 0xFF807B7B;
int textColor = 0xFFFFFFFF;
int sliderColor = 0xAA404040;
public SlideToUnlock(Context context) {
super(context);
init(context, null, 0);
}
public SlideToUnlock(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public SlideToUnlock(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
public OnSlideToUnlockEventListener getExternalListener() {
return externalListener;
}
public void setExternalListener(OnSlideToUnlockEventListener externalListener) {
this.externalListener = externalListener;
}
private void init(Context context, AttributeSet attrs, int style) {
Resources res = getResources();
density = res.getDisplayMetrics().density;
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.SlideToUnlock, style, 0);
String tmp = a.getString(R.styleable.SlideToUnlock_slideToUnlockText);
text = TextUtils.isEmpty(tmp) ? text : tmp;
rx = a.getDimension(R.styleable.SlideToUnlock_cornerRadiusX, rx);
useDefaultCornerRadiusX = rx == 0;
ry = a.getDimension(R.styleable.SlideToUnlock_cornerRadiusX, ry);
useDefaultCornerRadiusY = ry == 0;
backgroundColor = a.getColor(R.styleable.SlideToUnlock_slideToUnlockBackgroundColor, backgroundColor);
textColor = a.getColor(R.styleable.SlideToUnlock_slideToUnlockTextColor, textColor);
sliderColor = a.getColor(R.styleable.SlideToUnlock_sliderColor, sliderColor);
cancelOnYExit = a.getBoolean(R.styleable.SlideToUnlock_cancelOnYExit, false);
a.recycle();
mRoundedRectPath = new Path();
mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBackgroundPaint.setStyle(Paint.Style.FILL);
mBackgroundPaint.setColor(backgroundColor);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setColor(textColor);
mTextPaint.setTypeface(Typeface.create("Roboto-Thin", Typeface.NORMAL));
mSliderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mSliderPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mSliderPaint.setColor(sliderColor);
mSliderPaint.setStrokeWidth(2 * density);
if (!isInEditMode()) {
// Edit mode does not support shadow layers
// mSliderPaint.setShadowLayer(10.0f, 0.0f, 2.0f, 0xFF000000);
//mSliderPaint.setMaskFilter(new EmbossMaskFilter(new float[]{1, 1, 1}, 0.4f, 10, 8.2f));
float[] direction = new float[]{0.0f, -1.0f, 0.5f};
MaskFilter filter = new EmbossMaskFilter(direction, 0.8f, 15f, 1f);
mSliderPaint.setMaskFilter(filter);
//mSliderPaint.setShader(new LinearGradient(8f, 80f, 30f, 20f, Color.RED,Color.WHITE, Shader.TileMode.MIRROR));
//mSliderPaint.setShader(new RadialGradient(8f, 80f, 90f, Color.RED,Color.WHITE, Shader.TileMode.MIRROR));
//mSliderPaint.setShader(new SweepGradient(80, 80, Color.RED, Color.WHITE));
//mSliderPaint.setMaskFilter(new BlurMaskFilter(15, BlurMaskFilter.Blur.OUTER));
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
if (useDefaultCornerRadiusX) {
rx = measuredHeight * 0.52f;
}
if (useDefaultCornerRadiusY) {
ry = measuredHeight * 0.52f;
}
mTextPaint.setTextSize(measuredHeight / 3.0f);
radius = measuredHeight * 0.45f;
X_MIN = 1.2f * radius;
X_MAX = measuredWidth - X_MIN;
x = X_MIN;
setMeasuredDimension(measuredWidth, measuredHeight);
}
private void drawRoundRect(Canvas c) {
mRoundedRectPath.reset();
mRoundedRectPath.moveTo(rx, 0);
mRoundedRectPath.lineTo(measuredWidth - rx, 0);
mRoundedRectPath.quadTo(measuredWidth, 0, measuredWidth, ry);
mRoundedRectPath.lineTo(measuredWidth, measuredHeight - ry);
mRoundedRectPath.quadTo(measuredWidth, measuredHeight, measuredWidth - rx, measuredHeight);
mRoundedRectPath.lineTo(rx, measuredHeight);
mRoundedRectPath.quadTo(0, measuredHeight, 0, measuredHeight - ry);
mRoundedRectPath.lineTo(0, ry);
mRoundedRectPath.quadTo(0, 0, rx, 0);
c.drawPath(mRoundedRectPath, mBackgroundPaint);
}
#SuppressLint("NewApi")
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (measuredHeight <= 0 || measuredWidth <= 0) {
// There is not much we can draw :/
return;
}
if (Build.VERSION.SDK_INT >= 21) {
canvas.drawRoundRect(0, 0, measuredWidth, measuredHeight, rx, ry, mBackgroundPaint);
}
else {
drawRoundRect(canvas);
}
// Draw the text in center
float xPos = ((measuredWidth - mTextPaint.measureText(text)) / 2.0f);
float yPos = (measuredHeight / 2.0f);
float titleHeight = Math.abs(mTextPaint.descent() + mTextPaint.ascent());
yPos += titleHeight / 2.0f;
canvas.drawText(text, xPos, yPos, mTextPaint);
canvas.drawCircle(x, measuredHeight * 0.5f, radius, mSliderPaint);
}
private void onCancel() {
reset();
if (externalListener != null) {
externalListener.onSlideToUnlockCanceled();
}
}
private void onUnlock() {
if (externalListener != null) {
externalListener.onSlideToUnlockDone();
}
}
private void reset() {
x = X_MIN;
invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
ignoreTouchEvents = false;
reset();
return true;
case MotionEvent.ACTION_DOWN:
// Is within the circle??
event_x = event.getX(0);
event_y = event.getY(0);
double squareRadius = radius * radius;
double squaredXDistance = (event_x - X_MIN) * (event_x - X_MIN);
double squaredYDistance = (event_y - measuredHeight / 2) * (event_y - measuredHeight / 2);
if (squaredXDistance + squaredYDistance > squareRadius) {
// User touched outside the button, ignore his touch
ignoreTouchEvents = true;
}
return true;
case MotionEvent.ACTION_CANCEL:
ignoreTouchEvents = true;
onCancel();
case MotionEvent.ACTION_MOVE:
if (!ignoreTouchEvents) {
event_x = event.getX(0);
if (cancelOnYExit) {
event_y = event.getY(0);
if (event_y < 0 || event_y > measuredHeight) {
ignoreTouchEvents = true;
onCancel();
}
}
x = event_x > X_MAX ? X_MAX : event_x < X_MIN ? X_MIN : event_x;
if (event_x >= X_MAX) {
ignoreTouchEvents = true;
onUnlock();
}
invalidate();
}
return true;
default:
return super.onTouchEvent(event);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF000000">
<your.package.SlideToUnlock
android:id="#+id/slideToUnlock"
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_centerInParent="true"/>
<your.package.SlideToUnlock
android:id="#+id/slideToUnlock2"
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_below="#+id/slideToUnlock"
android:layout_centerInParent="true"
android:layout_marginTop="50dp"
app:cancelOnYExit="true"
app:slideToUnlockBackgroundColor="#808080"
app:slideToUnlockText="Slide to unlock"
app:slideToUnlockTextColor="#03A9F4"
app:sliderColor="#AAFFE97F"/>
</RelativeLayout>
MainActivity.java
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity implements SlideToUnlock.OnSlideToUnlockEventListener {
private SlideToUnlock slideToUnlockView, slideToUnlockView2;
private Toast toast;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
slideToUnlockView = (SlideToUnlock) findViewById(R.id.slideToUnlock);
slideToUnlockView.setExternalListener(this);
slideToUnlockView2 = (SlideToUnlock) findViewById(R.id.slideToUnlock2);
slideToUnlockView2.setExternalListener(this);
}
private void showToast(String text) {
if (toast != null) {
toast.cancel();
}
toast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
toast.show();
}
#Override
public void onSlideToUnlockCanceled() {
showToast("Canceled");
}
#Override
public void onSlideToUnlockDone() {
showToast("Unlocked");
}
}
You can download the whole project here. Enjoy :)
This is the final result.
Here are the libraries that may helps you.
https://github.com/Ghedeon/SlideToUnlockProject

Button subclass onClick not responding

I am trying to create a subclass of Button. The code is as below
package com.comnet.bookshelf;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Button;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
public class myButton extends Button implements OnClickListener{
Paint mainPaint;
int colorArray[];
int colorArrayAlt[];
boolean touch=false;
Rect bound;
public myButton(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
mainPaint=new Paint();
bound=new Rect();
defaultColorIndexArray();
}
public myButton(Context context, AttributeSet attrs)
{
super(context, attrs);
mainPaint=new Paint();
bound=new Rect();
defaultColorIndexArray();
}
public myButton(Context context)
{
super(context);
mainPaint=new Paint();
bound=new Rect();
defaultColorIndexArray();
}
private void defaultColorIndexArray(){
colorArray=new int[]{
0xFFd28181, //1
0xFFd48787, //2
0xFFd68d8d, //3
0xFFd89292, //4
0xFFda9898, //5
0xFFdc9e9e, //6
0XFFdea2a2, //7
0XFFe0a8a8, //8
0xFFe2adad, //9
0XFFe3b1b1, //10
0XFFe4b4b4, //11
0XFFe6b9b9, //12
0XFFe7bdbd, //13
0XFFe9c0c0, //14
0XFFeac3c3, //15
0XFFebc6c6, //16
0XFFebc7c7, //17
0XFFecc9c9, //18
0XFFeccaca, //19
0XFFeccaca, //20
0XFFeccbcb, //21
0XFFeccbcb //22
};
colorArrayAlt=new int[]{
0XFFeccbcb, //22
0XFFeccbcb, //21
0XFFeccaca, //20
0XFFeccaca, //19
0XFFecc9c9, //18
0XFFebc7c7, //17
0XFFebc6c6, //16
0XFFeac3c3, //15
0XFFe9c0c0, //14
0XFFe7bdbd, //13
0XFFe6b9b9, //12
0XFFe4b4b4, //11
0XFFe3b1b1, //10
0xFFe2adad, //9
0XFFe0a8a8, //8
0XFFdea2a2, //7
0xFFdc9e9e, //6
0xFFda9898, //5
0xFFd89292, //4
0xFFd68d8d, //3
0xFFd48787, //2
0xFFd28181 //1
};
}
public void setButtonColorIndexArray(int carray[], int carray_alt[]){
}
#Override
protected void onDraw(Canvas canvasObject) {
super.onDraw(canvasObject);
int draw_color[];
if(touch==false)
draw_color=colorArray;
else
draw_color=colorArrayAlt;
int width=canvasObject.getWidth();
int height=canvasObject.getHeight();
double colorcount=44;
double divheight=height;
double f=colorcount/divheight;
double step=0;
for(int i=0;i<height;i++,step+=f){
int next=(int) Math.round(step);
if(next>43) next=43;
else if(next<0)next=0;
if(next<22){
mainPaint.setColor(draw_color[next]);
canvasObject.drawLine(0, i, width, i, mainPaint);
}
else{
mainPaint.setColor(draw_color[43-next]);
canvasObject.drawLine(0, i, width, i, mainPaint);
}
//int color=;
mainPaint.setColor(getCurrentTextColor());
String str=this.getText().toString();
//mainPaint.setColor(Color.WHITE);
mainPaint.setStyle(Style.FILL);
//canvasObject.drawPaint(mainPaint);
mainPaint.setColor(Color.BLACK);
mainPaint.setTextSize(20);
mainPaint.getTextBounds(str, 0, str.length(), bound);
int x=(width-(bound.right-bound.left))/2;
int y=(height+(bound.bottom-bound.top))/2;
canvasObject.drawText(str, x, y, mainPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent ev){
if(ev.getAction()==MotionEvent.ACTION_DOWN){
//Log.i("Click", "ACTION_DOWN");
touch=true;
this.invalidate();
}
else if(ev.getAction()==MotionEvent.ACTION_UP){
touch=false;
this.invalidate();
}
return true;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("Clicked", "Clicked");
}
}
Everything but one is working as I expected.
onClick is not responding at all. The code is as below:
((myButton)inflatedLayout.findViewById(R.id.DeleteButton)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
DeleteTheEntireBook();
}
});
The button with default class is working fine
If you have any further question, let me know.
The problem is You have overridden onTouchEvent.
Mark these words:
You should return false in your OnTouchListener then your OnClickListener will be also handled.
So you might think, I will just do my thing there and return false so I can receive clicks too. If you do so, it will work, but you wont be subscribed to other upcoming touch events (ACTION_MOVE, ACTION_UP) Therefore only option is to return true there, but then you wont receive any click events as we said previously.
So you need to perform the click manually in the ACTION_UP with performClick()
Tested and working code :
#Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// Log.i("Click", "ACTION_DOWN");
touch = true;
this.invalidate();
} else if (ev.getAction() == MotionEvent.ACTION_UP) {
touch = false;
this.invalidate();
// KEY LINE
performClick();
}
return true;
}
Hope it helps ツ
in the constructor, add the onClickListener,
and no need to ((myButton)inflatedLayout.findViewB...
public myButton(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
mainPaint=new Paint();
bound=new Rect();
defaultColorIndexArray();
setOnClickListener(this);
}
then the overridden onClick in myButton class should be called once the button is clicked.
View.OnClickListener :Interface definition for a callback to be invoked when a view is clicked.
Can you use this Code:
((myButton)inflatedLayout.findViewById(R.id.DeleteButton)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DeleteTheEntireBook();
}
});

Caused by: java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to com.slidingmenu.lib.SlidingMenu

I've just read all questions about this problem at stackoverflow and some forums, but still have no solution. I tried to remove R.java, clear the cache, edit .xml but nothing helps.
Error text:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.easyten.app/com.easyten.app.EasyTenActivity}:
java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to com.slidingmenu.lib.SlidingMenu ...
Caused by: java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to com.slidingmenu.lib.SlidingMenu
at com.slidingmenu.lib.app.SlidingActivityHelper.onCreate(SlidingActivityHelper.java:32)
This is the code:
slidingmenumain.xml
<?xml version="1.0" encoding="utf-8"?>
<com.slidingmenu.lib.SlidingMenu xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/slidingmenumain"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
SlidingActivityHelper.java
package com.slidingmenu.lib.app;
import android.app.Activity;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import com.slidingmenu.lib.R;
import com.slidingmenu.lib.SlidingMenu;
public class SlidingActivityHelper {
private Activity mActivity;
private SlidingMenu mSlidingMenu;
private View mViewAbove;
private View mViewBehind;
private boolean mBroadcasting = false;
private boolean mOnPostCreateCalled = false;
private boolean mEnableSlide = true;
public SlidingActivityHelper(Activity activity) {
mActivity = activity;
}
public void onCreate(Bundle savedInstanceState) {
mSlidingMenu = (SlidingMenu) LayoutInflater.from(mActivity).inflate(R.layout.slidingmenumain, null);
}
...other code
}
32 line of SlidingActivityHelper.java is mSlidingMenu = (SlidingMenu) LayoutInflater.from(mActivity).inflate(R.layout.slidingmenumain, null);
SlidingMenu.java
package com.slidingmenu.lib;
import java.lang.reflect.Method;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import com.slidingmenu.lib.CustomViewAbove.OnPageChangeListener;
public class SlidingMenu extends RelativeLayout {
public static final int TOUCHMODE_MARGIN = 0;
public static final int TOUCHMODE_FULLSCREEN = 1;
private CustomViewAbove mViewAbove;
private CustomViewBehind mViewBehind;
private OnOpenListener mOpenListener;
private OnCloseListener mCloseListener;
//private boolean mSlidingEnabled;
public static void attachSlidingMenu(Activity activity, SlidingMenu sm, boolean slidingTitle) {
if (sm.getParent() != null)
throw new IllegalStateException("SlidingMenu cannot be attached to another view when" +
" calling the static method attachSlidingMenu");
if (slidingTitle) {
// get the window background
TypedArray a = activity.getTheme().obtainStyledAttributes(new int[] {android.R.attr.windowBackground});
int background = a.getResourceId(0, 0);
// move everything into the SlidingMenu
ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();
ViewGroup decorChild = (ViewGroup) decor.getChildAt(0);
decor.removeAllViews();
// save ActionBar themes that have transparent assets
decorChild.setBackgroundResource(background);
sm.setContent(decorChild);
decor.addView(sm);
} else {
// take the above view out of
ViewGroup content = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
View above = content.getChildAt(0);
content.removeAllViews();
sm.setContent(above);
content.addView(sm, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
}
public interface OnOpenListener {
public void onOpen();
}
public interface OnOpenedListener {
public void onOpened();
}
public interface OnCloseListener {
public void onClose();
}
public interface OnClosedListener {
public void onClosed();
}
public interface CanvasTransformer {
public void transformCanvas(Canvas canvas, float percentOpen);
}
public SlidingMenu(Context context) {
this(context, null);
}
public SlidingMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutParams behindParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
mViewBehind = new CustomViewBehind(context);
addView(mViewBehind, behindParams);
LayoutParams aboveParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
mViewAbove = new CustomViewAbove(context);
addView(mViewAbove, aboveParams);
// register the CustomViewBehind2 with the CustomViewAbove
mViewAbove.setCustomViewBehind(mViewBehind);
mViewBehind.setCustomViewAbove(mViewAbove);
mViewAbove.setOnPageChangeListener(new OnPageChangeListener() {
public static final int POSITION_OPEN = 0;
public static final int POSITION_CLOSE = 1;
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) { }
public void onPageSelected(int position) {
if (position == POSITION_OPEN && mOpenListener != null) {
mOpenListener.onOpen();
} else if (position == POSITION_CLOSE && mCloseListener != null) {
mCloseListener.onClose();
}
}
});
// now style everything!
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu);
// set the above and behind views if defined in xml
int viewAbove = ta.getResourceId(R.styleable.SlidingMenu_viewAbove, -1);
if (viewAbove != -1)
setContent(viewAbove);
int viewBehind = ta.getResourceId(R.styleable.SlidingMenu_viewBehind, -1);
if (viewBehind != -1)
setMenu(viewBehind);
int touchModeAbove = ta.getInt(R.styleable.SlidingMenu_aboveTouchMode, TOUCHMODE_MARGIN);
setTouchModeAbove(touchModeAbove);
int touchModeBehind = ta.getInt(R.styleable.SlidingMenu_behindTouchMode, TOUCHMODE_MARGIN);
setTouchModeBehind(touchModeBehind);
int offsetBehind = (int) ta.getDimension(R.styleable.SlidingMenu_behindOffset, -1);
int widthBehind = (int) ta.getDimension(R.styleable.SlidingMenu_behindWidth, -1);
if (offsetBehind != -1 && widthBehind != -1)
throw new IllegalStateException("Cannot set both behindOffset and behindWidth for a SlidingMenu");
else if (offsetBehind != -1)
setBehindOffset(offsetBehind);
else if (widthBehind != -1)
setBehindWidth(widthBehind);
else
setBehindOffset(0);
float scrollOffsetBehind = ta.getFloat(R.styleable.SlidingMenu_behindScrollScale, 0.33f);
setBehindScrollScale(scrollOffsetBehind);
int shadowRes = ta.getResourceId(R.styleable.SlidingMenu_shadowDrawable, -1);
if (shadowRes != -1) {
setShadowDrawable(shadowRes);
}
int shadowWidth = (int) ta.getDimension(R.styleable.SlidingMenu_shadowWidth, 0);
setShadowWidth(shadowWidth);
boolean fadeEnabled = ta.getBoolean(R.styleable.SlidingMenu_behindFadeEnabled, true);
setFadeEnabled(fadeEnabled);
float fadeDeg = ta.getFloat(R.styleable.SlidingMenu_behindFadeDegree, 0.66f);
setFadeDegree(fadeDeg);
boolean selectorEnabled = ta.getBoolean(R.styleable.SlidingMenu_selectorEnabled, false);
setSelectorEnabled(selectorEnabled);
int selectorRes = ta.getResourceId(R.styleable.SlidingMenu_selectorDrawable, -1);
if (selectorRes != -1)
setSelectorDrawable(selectorRes);
}
public void setContent(int res) {
setContent(LayoutInflater.from(getContext()).inflate(res, null));
}
public void setContent(View v) {
mViewAbove.setContent(v);
mViewAbove.invalidate();
showAbove(true);
}
public void setMenu(int res) {
setMenu(LayoutInflater.from(getContext()).inflate(res, null));
}
public void setMenu(View v) {
mViewBehind.setMenu(v);
mViewBehind.invalidate();
}
public void setSlidingEnabled(boolean b) {
mViewAbove.setSlidingEnabled(b);
}
public boolean isSlidingEnabled() {
return mViewAbove.isSlidingEnabled();
}
/**
*
* #param b Whether or not the SlidingMenu is in a static mode
* (i.e. nothing is moving and everything is showing)
*/
public void setStatic(boolean b) {
if (b) {
setSlidingEnabled(false);
mViewAbove.setCustomViewBehind(null);
mViewAbove.setCurrentItem(1);
mViewBehind.setCurrentItem(0);
} else {
mViewAbove.setCurrentItem(1);
mViewBehind.setCurrentItem(1);
mViewAbove.setCustomViewBehind(mViewBehind);
setSlidingEnabled(true);
}
}
/**
* Shows the behind view
*/
public void showBehind(boolean b) {
mViewAbove.setCurrentItem(0, b);
}
public void showBehind() {
mViewAbove.setCurrentItem(0);
}
/**
* Shows the above view
*/
public void showAbove(boolean b) {
mViewAbove.setCurrentItem(1, b);
}
public void showAbove() {
mViewAbove.setCurrentItem(1);
}
/**
*
* #return Whether or not the behind view is showing
*/
public boolean isBehindShowing() {
return mViewAbove.getCurrentItem() == 0;
}
/**
*
* #return The margin on the right of the screen that the behind view scrolls to
*/
public int getBehindOffset() {
return ((RelativeLayout.LayoutParams)mViewBehind.getLayoutParams()).rightMargin;
}
/**
*
* #param i The margin on the right of the screen that the behind view scrolls to
*/
public void setBehindOffset(int i) {
RelativeLayout.LayoutParams params = ((RelativeLayout.LayoutParams)mViewBehind.getLayoutParams());
int bottom = params.bottomMargin;
int top = params.topMargin;
int left = params.leftMargin;
params.setMargins(left, top, i, bottom);
}
/**
*
* #param i The width the Sliding Menu will open to in pixels
*/
#SuppressWarnings("deprecation")
public void setBehindWidth(int i) {
int width;
Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
try {
Class<?> cls = Display.class;
Class<?>[] parameterTypes = {Point.class};
Point parameter = new Point();
Method method = cls.getMethod("getSize", parameterTypes);
method.invoke(display, parameter);
width = parameter.x;
} catch (Exception e) {
width = display.getWidth();
}
setBehindOffset(width-i);
}
/**
*
* #param res A resource ID which points to the width the Sliding Menu will open to
*/
public void setBehindWidthRes(int res) {
int i = (int) getContext().getResources().getDimension(res);
setBehindWidth(i);
}
/**
*
* #param res The dimension resource to be set as the behind offset
*/
public void setBehindOffsetRes(int res) {
int i = (int) getContext().getResources().getDimension(res);
setBehindOffset(i);
}
/**
*
* #return The scale of the parallax scroll
*/
public float getBehindScrollScale() {
return mViewAbove.getScrollScale();
}
/**
*
* #param f The scale of the parallax scroll (i.e. 1.0f scrolls 1 pixel for every
* 1 pixel that the above view scrolls and 0.0f scrolls 0 pixels)
*/
public void setBehindScrollScale(float f) {
mViewAbove.setScrollScale(f);
}
public void setBehindCanvasTransformer(CanvasTransformer t) {
mViewBehind.setCanvasTransformer(t);
}
public int getTouchModeAbove() {
return mViewAbove.getTouchMode();
}
public void setTouchModeAbove(int i) {
if (i != TOUCHMODE_FULLSCREEN && i != TOUCHMODE_MARGIN) {
throw new IllegalStateException("TouchMode must be set to either" +
"TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN.");
}
mViewAbove.setTouchMode(i);
}
public int getTouchModeBehind() {
return mViewBehind.getTouchMode();
}
public void setTouchModeBehind(int i) {
if (i != TOUCHMODE_FULLSCREEN && i != TOUCHMODE_MARGIN) {
throw new IllegalStateException("TouchMode must be set to either" +
"TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN.");
}
mViewBehind.setTouchMode(i);
}
public void setShadowDrawable(int resId) {
mViewAbove.setShadowDrawable(resId);
}
public void setShadowWidthRes(int resId) {
setShadowWidth((int)getResources().getDimension(resId));
}
public void setShadowWidth(int pixels) {
mViewAbove.setShadowWidth(pixels);
}
public void setFadeEnabled(boolean b) {
mViewAbove.setBehindFadeEnabled(b);
}
public void setFadeDegree(float f) {
mViewAbove.setBehindFadeDegree(f);
}
public void setSelectorEnabled(boolean b) {
mViewAbove.setSelectorEnabled(true);
}
public void setSelectedView(View v) {
mViewAbove.setSelectedView(v);
}
public void setSelectorDrawable(int res) {
mViewAbove.setSelectorDrawable(BitmapFactory.decodeResource(getResources(), res));
}
public void setSelectorDrawable(Bitmap b) {
mViewAbove.setSelectorDrawable(b);
}
public void setOnOpenListener(OnOpenListener listener) {
//mViewAbove.setOnOpenListener(listener);
mOpenListener = listener;
}
public void setOnCloseListener(OnCloseListener listener) {
//mViewAbove.setOnCloseListener(listener);
mCloseListener = listener;
}
public void setOnOpenedListener(OnOpenedListener listener) {
mViewAbove.setOnOpenedListener(listener);
}
public void setOnClosedListener(OnClosedListener listener) {
mViewAbove.setOnClosedListener(listener);
}
private static class SavedState extends BaseSavedState {
boolean mBehindShowing;
public SavedState(Parcelable superState) {
super(superState);
}
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeBooleanArray(new boolean[]{mBehindShowing});
}
/*
public static final Parcelable.Creator<SavedState> CREATOR
= ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
public SavedState createFromParcel(Parcel in, ClassLoader loader) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
});
SavedState(Parcel in) {
super(in);
boolean[] showing = new boolean[1];
in.readBooleanArray(showing);
mBehindShowing = showing[0];
}
*/
}
#Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.mBehindShowing = isBehindShowing();
return ss;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
if (ss.mBehindShowing) {
showBehind(true);
} else {
showAbove(true);
}
}
#Override
protected boolean fitSystemWindows(Rect insets) {
int leftPadding = getPaddingLeft() + insets.left;
int rightPadding = getPaddingRight() + insets.right;
int topPadding = insets.top;
int bottomPadding = insets.bottom;
this.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
return super.fitSystemWindows(insets);
}
}
What's wrong? How can I fix it? I'm using IntelliJ IDEA 12 CE. Thanks a lot for any help!
This can be resolved by recreating the R.java file.
1. Re-build OR
2. Change the 'android:id' in XML file to a new id and re-build. Make sure you manually change all references to this id.
Sometimes this does´t work even recreating the R.java file, cleaning and rebuilding the project.
for me it works until i delete \gen and \bin folders, then automatically were recreated with the new relationship between resources and their id´s.
I think the problem is just that the inflater cast your item to RelativeLayout and you can't cast a relativeLayout in your item (Maybe this post is more precise : ClassCastException). Perhaps you have to give up and retrieve your object using your id with findViewById.

Categories