How to have a auto scrollable TextView - android

I am trying to have a automatic scroll in android app.
Suppose that, I have xml code like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="show me the texts"
android:id="#+id/button"/>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/text"
android:id="#+id/textView1"/>
</ScrollView>
</LinearLayout>
In this xml code I have a Button on the top of the screen and a TextView which is wrapped by a ScrollView. It means that my TextView is scrollable right now.
It works correctly, because when the user touch the screen and swap down or up, the TextView can be scrolled up and down.
But...
I intend to have a Auto Scrollable TextView and by auto I mean, I need a scrollable TextView which scrolls down about 10dp after 10 seconds.
I know I must use some thread in my application for counting the time but I don't know how to say to TextView scroll down after 10 seconds for example.
any suggestions? Any hint will be appreciated. Thanks

You can use some thing like:
mScrollView.post(new Runnable() {
public void run() {
mScrollView.smoothScrollBy(10, 10);
}
});
Documentation for smoothScrollBy :http://developer.android.com/reference/android/widget/ScrollView.html#smoothScrollBy(int,int)
To execute this task for every 10seconds:
TimerTask fileProcessTask = new TimerTask(){
#Override
public void run() {
//Scrolling here
}
};
Timer tm = new Timer();
tm.schedule(fileProcessTask, 10000L);
Also take a look at this SO Post: https://stackoverflow.com/a/14685729/3326331 , I haven't tried it but you can give it a try.

Create a new Class File and paste the code below.
In your Layout.xml give Reference to EllipsizingTextView rather than using Android TextView.
/*
* Copyright (C) 2011 Micah Hainline
* Copyright (C) 2012 Triposo
* Copyright (C) 2013 Paul Imhoff
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.text.Layout;
import android.text.Layout.Alignment;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* A {#link android.widget.TextView} that ellipsizes more intelligently. This class supports ellipsizing multiline text through setting {#code android:ellipsize} and {#code android:maxLines}.
*/
public class EllipsizingTextView extends TextView {
private static final CharSequence ELLIPSIS = "\u2026";
private static final Pattern DEFAULT_END_PUNCTUATION = Pattern.compile("[\\.!?,;:\u2026]*$", Pattern.DOTALL);
private final List<EllipsizeListener> mEllipsizeListeners = new ArrayList<EllipsizeListener>();
private EllipsizeStrategy mEllipsizeStrategy;
private boolean isEllipsized;
private boolean isStale;
private boolean programmaticChange;
private CharSequence mFullText;
private int mMaxLines;
private float mLineSpacingMult = 1.0f;
private float mLineAddVertPad = 0.0f;
/**
* The end punctuation which will be removed when appending {#link #ELLIPSIS}.
*/
private Pattern mEndPunctPattern;
public EllipsizingTextView(Context context) {
this(context, null);
}
public EllipsizingTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
public EllipsizingTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.maxLines, android.R.attr.ellipsize }, defStyle, 0);
setMaxLines(a.getInt(0, Integer.MAX_VALUE));
a.recycle();
setEndPunctuationPattern(DEFAULT_END_PUNCTUATION);
}
public void setEndPunctuationPattern(Pattern pattern) {
mEndPunctPattern = pattern;
}
public void addEllipsizeListener(EllipsizeListener listener) {
if (listener == null)
throw new NullPointerException();
mEllipsizeListeners.add(listener);
}
public void removeEllipsizeListener(EllipsizeListener listener) {
mEllipsizeListeners.remove(listener);
}
public boolean isEllipsized() {
return isEllipsized;
}
/**
* #return The maximum number of lines displayed in this {#link android.widget.TextView}.
*/
#SuppressLint("Override")
public int getMaxLines() {
return mMaxLines;
}
#Override
public void setMaxLines(int maxLines) {
super.setMaxLines(maxLines);
mMaxLines = maxLines;
isStale = true;
}
#Override
public boolean isFocused() {
return true;
}
/**
* Determines if the last fully visible line is being ellipsized.
*
* #return {#code true} if the last fully visible line is being ellipsized; otherwise, returns {#code false}.
*/
public boolean ellipsizingLastFullyVisibleLine() {
return mMaxLines == Integer.MAX_VALUE;
}
#Override
public void setLineSpacing(float add, float mult) {
mLineAddVertPad = add;
mLineSpacingMult = mult;
super.setLineSpacing(add, mult);
}
#Override
public void setText(CharSequence text, BufferType type) {
if (!programmaticChange) {
mFullText = text;
isStale = true;
}
super.setText(text, type);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (ellipsizingLastFullyVisibleLine())
isStale = true;
}
#Override
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
if (ellipsizingLastFullyVisibleLine())
isStale = true;
}
#Override
protected void onDraw(Canvas canvas) {
if (isStale)
resetText();
super.onDraw(canvas);
}
/**
* Sets the ellipsized text if appropriate.
*/
private void resetText() {
int maxLines = getMaxLines();
CharSequence workingText = mFullText;
boolean ellipsized = false;
if (maxLines != -1) {
if (mEllipsizeStrategy == null)
setEllipsize(null);
workingText = mEllipsizeStrategy.processText(mFullText);
ellipsized = !mEllipsizeStrategy.isInLayout(mFullText);
}
if (!workingText.equals(getText())) {
programmaticChange = true;
try {
setText(workingText);
} finally {
programmaticChange = false;
}
}
isStale = false;
if (ellipsized != isEllipsized) {
isEllipsized = ellipsized;
for (EllipsizeListener listener : mEllipsizeListeners) {
listener.ellipsizeStateChanged(ellipsized);
}
}
}
/**
* Causes words in the text that are longer than the view is wide to be ellipsized instead of broken in the middle. Use {#code null} to turn off ellipsizing.
*
* #param where
* part of text to ellipsize
*/
#Override
public void setEllipsize(TruncateAt where) {
if (where == null) {
mEllipsizeStrategy = new EllipsizeNoneStrategy();
return;
}
switch (where) {
case END:
mEllipsizeStrategy = new EllipsizeEndStrategy();
break;
case START:
mEllipsizeStrategy = new EllipsizeStartStrategy();
break;
case MIDDLE:
mEllipsizeStrategy = new EllipsizeMiddleStrategy();
break;
case MARQUEE:
super.setEllipsize(where);
isStale = false;
default:
mEllipsizeStrategy = new EllipsizeNoneStrategy();
break;
}
}
/**
* A listener that notifies when the ellipsize state has changed.
*/
public interface EllipsizeListener {
void ellipsizeStateChanged(boolean ellipsized);
}
/**
* A base class for an ellipsize strategy.
*/
private abstract class EllipsizeStrategy {
/**
* Returns ellipsized text if the text does not fit inside of the layout; otherwise, returns the full text.
*
* #param text
* text to process
* #return Ellipsized text if the text does not fit inside of the layout; otherwise, returns the full text.
*/
public CharSequence processText(CharSequence text) {
return !isInLayout(text) ? createEllipsizedText(text) : text;
}
/**
* Determines if the text fits inside of the layout.
*
* #param text
* text to fit
* #return {#code true} if the text fits inside of the layout; otherwise, returns {#code false}.
*/
public boolean isInLayout(CharSequence text) {
Layout layout = createWorkingLayout(text);
return layout.getLineCount() <= getLinesCount();
}
/**
* Creates a working layout with the given text.
*
* #param workingText
* text to create layout with
* #return {#link android.text.Layout} with the given text.
*/
protected Layout createWorkingLayout(CharSequence workingText) {
return new StaticLayout(workingText, getPaint(), getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight(), Alignment.ALIGN_NORMAL, mLineSpacingMult, mLineAddVertPad, false /* includepad */);
}
/**
* Get how many lines of text we are allowed to display.
*/
protected int getLinesCount() {
if (ellipsizingLastFullyVisibleLine()) {
int fullyVisibleLinesCount = getFullyVisibleLinesCount();
return fullyVisibleLinesCount == -1 ? 1 : fullyVisibleLinesCount;
} else {
return mMaxLines;
}
}
/**
* Get how many lines of text we can display so their full height is visible.
*/
protected int getFullyVisibleLinesCount() {
Layout layout = createWorkingLayout("");
int height = getHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom();
int lineHeight = layout.getLineBottom(0);
return height / lineHeight;
}
/**
* Creates ellipsized text from the given text.
*
* #param fullText
* text to ellipsize
* #return Ellipsized text
*/
protected abstract CharSequence createEllipsizedText(CharSequence fullText);
}
/**
* An {#link EllipsizingTextView.EllipsizeStrategy} that does not ellipsize text.
*/
private class EllipsizeNoneStrategy extends EllipsizeStrategy {
#Override
protected CharSequence createEllipsizedText(CharSequence fullText) {
return fullText;
}
}
/**
* An {#link EllipsizingTextView.EllipsizeStrategy} that ellipsizes text at the end.
*/
private class EllipsizeEndStrategy extends EllipsizeStrategy {
#Override
protected CharSequence createEllipsizedText(CharSequence fullText) {
Layout layout = createWorkingLayout(fullText);
int cutOffIndex = layout.getLineEnd(mMaxLines - 1);
int textLength = fullText.length();
int cutOffLength = textLength - cutOffIndex;
if (cutOffLength < ELLIPSIS.length())
cutOffLength = ELLIPSIS.length();
String workingText = TextUtils.substring(fullText, 0, textLength - cutOffLength).trim();
String strippedText = stripEndPunctuation(workingText);
while (!isInLayout(strippedText + ELLIPSIS)) {
int lastSpace = workingText.lastIndexOf(' ');
if (lastSpace == -1)
break;
workingText = workingText.substring(0, lastSpace).trim();
strippedText = stripEndPunctuation(workingText);
}
workingText = strippedText + ELLIPSIS;
SpannableStringBuilder dest = new SpannableStringBuilder(workingText);
if (fullText instanceof Spanned) {
TextUtils.copySpansFrom((Spanned) fullText, 0, workingText.length(), null, dest, 0);
}
return dest;
}
/**
* Strips the end punctuation from a given text according to {#link #mEndPunctPattern}.
*
* #param workingText
* text to strip end punctuation from
* #return Text without end punctuation.
*/
public String stripEndPunctuation(CharSequence workingText) {
return mEndPunctPattern.matcher(workingText).replaceFirst("");
}
}
/**
* An {#link EllipsizingTextView.EllipsizeStrategy} that ellipsizes text at the start.
*/
private class EllipsizeStartStrategy extends EllipsizeStrategy {
#Override
protected CharSequence createEllipsizedText(CharSequence fullText) {
Layout layout = createWorkingLayout(fullText);
int cutOffIndex = layout.getLineEnd(mMaxLines - 1);
int textLength = fullText.length();
int cutOffLength = textLength - cutOffIndex;
if (cutOffLength < ELLIPSIS.length())
cutOffLength = ELLIPSIS.length();
String workingText = TextUtils.substring(fullText, cutOffLength, textLength).trim();
while (!isInLayout(ELLIPSIS + workingText)) {
int firstSpace = workingText.indexOf(' ');
if (firstSpace == -1)
break;
workingText = workingText.substring(firstSpace, workingText.length()).trim();
}
workingText = ELLIPSIS + workingText;
SpannableStringBuilder dest = new SpannableStringBuilder(workingText);
if (fullText instanceof Spanned) {
TextUtils.copySpansFrom((Spanned) fullText, textLength - workingText.length(), textLength, null, dest, 0);
}
return dest;
}
}
/**
* An {#link EllipsizingTextView.EllipsizeStrategy} that ellipsizes text in the middle.
*/
private class EllipsizeMiddleStrategy extends EllipsizeStrategy {
#Override
protected CharSequence createEllipsizedText(CharSequence fullText) {
Layout layout = createWorkingLayout(fullText);
int cutOffIndex = layout.getLineEnd(mMaxLines - 1);
int textLength = fullText.length();
int cutOffLength = textLength - cutOffIndex;
if (cutOffLength < ELLIPSIS.length())
cutOffLength = ELLIPSIS.length();
cutOffLength += cutOffIndex % 2; // Make it even.
String firstPart = TextUtils.substring(fullText, 0, textLength / 2 - cutOffLength / 2).trim();
String secondPart = TextUtils.substring(fullText, textLength / 2 + cutOffLength / 2, textLength).trim();
while (!isInLayout(firstPart + ELLIPSIS + secondPart)) {
int lastSpaceFirstPart = firstPart.lastIndexOf(' ');
int firstSpaceSecondPart = secondPart.indexOf(' ');
if (lastSpaceFirstPart == -1 || firstSpaceSecondPart == -1)
break;
firstPart = firstPart.substring(0, lastSpaceFirstPart).trim();
secondPart = secondPart.substring(firstSpaceSecondPart, secondPart.length()).trim();
}
SpannableStringBuilder firstDest = new SpannableStringBuilder(firstPart);
SpannableStringBuilder secondDest = new SpannableStringBuilder(secondPart);
if (fullText instanceof Spanned) {
TextUtils.copySpansFrom((Spanned) fullText, 0, firstPart.length(), null, firstDest, 0);
TextUtils.copySpansFrom((Spanned) fullText, textLength - secondPart.length(), textLength, null, secondDest, 0);
}
return TextUtils.concat(firstDest, ELLIPSIS, secondDest);
}
}
}

Related

Implement badge counter for all types of android device (different launchers) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Some home launchers, like Samsung, Sony, HTC, Nova Launcher etc., support badge counters. How can I implement badge counters for all devices that support it?
1st of all badge view is not any launcher or device specific .If you want to implement Badge View in Android 1st you have to create custom class for badge view
public class BadgeView extends TextView {
public static final int POSITION_TOP_LEFT = 1;
public static final int POSITION_TOP_RIGHT = 2;
public static final int POSITION_BOTTOM_LEFT = 3;
public static final int POSITION_BOTTOM_RIGHT = 4;
public static final int POSITION_CENTER = 5;
private static final int DEFAULT_MARGIN_DIP = 5;
private static final int DEFAULT_LR_PADDING_DIP = 5;
private static final int DEFAULT_CORNER_RADIUS_DIP = 8;
private static final int DEFAULT_POSITION = POSITION_TOP_RIGHT;
private static final int DEFAULT_BADGE_COLOR = Color
.parseColor("#CCFF0000"); // Color.RED;
private static final int DEFAULT_TEXT_COLOR = Color.WHITE;
private static Animation fadeIn;
private static Animation fadeOut;
private Context context;
private View target;
private int badgePosition;
private int badgeMarginH;
private int badgeMarginV;
private int badgeColor;
private boolean isShown;
private ShapeDrawable badgeBg;
private int targetTabIndex;
public BadgeView(Context context) {
this(context, (AttributeSet) null, android.R.attr.textViewStyle);
}
public BadgeView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
/**
* Constructor -
*
* create a new BadgeView instance attached to a target
* {#link android.view.View}.
*
* #param context
* context for this view.
* #param target
* the View to attach the badge to.
*/
public BadgeView(Context context, View target) {
this(context, null, android.R.attr.textViewStyle, target, 0);
}
/**
* Constructor -
*
* create a new BadgeView instance attached to a target
* {#link android.widget.TabWidget} tab at a given index.
*
* #param context
* context for this view.
* #param target
* the TabWidget to attach the badge to.
* #param index
* the position of the tab within the target.
*/
public BadgeView(Context context, TabWidget target, int index) {
this(context, null, android.R.attr.textViewStyle, target, index);
}
public BadgeView(Context context, AttributeSet attrs, int defStyle) {
this(context, attrs, defStyle, null, 0);
}
public BadgeView(Context context, AttributeSet attrs, int defStyle,
View target, int tabIndex) {
super(context, attrs, defStyle);
init(context, target, tabIndex);
}
public BadgeView(Context context, SlidingTabStrip target,
int i) {
// TODO Auto-generated constructor stub
this(context, null, android.R.attr.textViewStyle, target, i);
}
private void init(Context context, View target, int tabIndex) {
this.context = context;
this.target = target;
this.targetTabIndex = tabIndex;
// apply defaults
badgePosition = DEFAULT_POSITION;
badgeMarginH = dipToPixels(DEFAULT_MARGIN_DIP);
badgeMarginV = badgeMarginH;
badgeColor = DEFAULT_BADGE_COLOR;
setTypeface(Typeface.DEFAULT_BOLD);
int paddingPixels = dipToPixels(DEFAULT_LR_PADDING_DIP);
setPadding(paddingPixels, 0, paddingPixels, 0);
setTextColor(DEFAULT_TEXT_COLOR);
fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator());
fadeIn.setDuration(200);
fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator());
fadeOut.setDuration(200);
isShown = false;
if (this.target != null) {
applyTo(this.target);
} else {
show();
}
}
private void applyTo(View target) {
ViewGroup.LayoutParams lp = target.getLayoutParams();
ViewParent parent = target.getParent();
FrameLayout container = new FrameLayout(context);
if (target instanceof TabWidget) {
// set target to the relevant tab child container
target = ((TabWidget) target).getChildTabViewAt(targetTabIndex);
this.target = target;
((ViewGroup) target).addView(container, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
this.setVisibility(View.GONE);
container.addView(this);
} else if (target instanceof SlidingTabStrip) {
// set target to the relevant tab child container
View textView = ((SlidingTabStrip) target)
.getChildAt(targetTabIndex);
ViewGroup group = (ViewGroup) target;
// getting index of TexTView from SlidingTabStrip
int index = group.indexOfChild(textView);
Log.e("index", "" + index);
group.removeView(textView);
group.addView(container, index, lp);
container.addView(textView);
this.setVisibility(View.GONE);
container.addView(this);
group.invalidate();
} else {
// TODO verify that parent is indeed a ViewGroup
ViewGroup group = (ViewGroup) parent;
int index = group.indexOfChild(target);
group.removeView(target);
group.addView(container, index, lp);
container.addView(target);
this.setVisibility(View.GONE);
container.addView(this);
group.invalidate();
}
}
/**
* Make the badge visible in the UI.
*
*/
public void show() {
show(false, null);
}
/**
* Make the badge visible in the UI.
*
* #param animate
* flag to apply the default fade-in animation.
*/
public void show(boolean animate) {
show(animate, fadeIn);
}
/**
* Make the badge visible in the UI.
*
* #param anim
* Animation to apply to the view when made visible.
*/
public void show(Animation anim) {
show(true, anim);
}
/**
* Make the badge non-visible in the UI.
*
*/
public void hide() {
hide(false, null);
}
/**
* Make the badge non-visible in the UI.
*
* #param animate
* flag to apply the default fade-out animation.
*/
public void hide(boolean animate) {
hide(animate, fadeOut);
}
/**
* Make the badge non-visible in the UI.
*
* #param anim
* Animation to apply to the view when made non-visible.
*/
public void hide(Animation anim) {
hide(true, anim);
}
/**
* Toggle the badge visibility in the UI.
*
*/
public void toggle() {
toggle(false, null, null);
}
/**
* Toggle the badge visibility in the UI.
*
* #param animate
* flag to apply the default fade-in/out animation.
*/
public void toggle(boolean animate) {
toggle(animate, fadeIn, fadeOut);
}
/**
* Toggle the badge visibility in the UI.
*
* #param animIn
* Animation to apply to the view when made visible.
* #param animOut
* Animation to apply to the view when made non-visible.
*/
public void toggle(Animation animIn, Animation animOut) {
toggle(true, animIn, animOut);
}
private void show(boolean animate, Animation anim) {
if (getBackground() == null) {
if (badgeBg == null) {
badgeBg = getDefaultBackground();
}
setBackgroundDrawable(badgeBg);
}
applyLayoutParams();
if (animate) {
this.startAnimation(anim);
}
this.setVisibility(View.VISIBLE);
isShown = true;
}
private void hide(boolean animate, Animation anim) {
this.setVisibility(View.GONE);
if (animate) {
this.startAnimation(anim);
}
isShown = false;
}
private void toggle(boolean animate, Animation animIn, Animation animOut) {
if (isShown) {
hide(animate && (animOut != null), animOut);
} else {
show(animate && (animIn != null), animIn);
}
}
/**
* Increment the numeric badge label. If the current badge label cannot be
* converted to an integer value, its label will be set to "0".
*
* #param offset
* the increment offset.
*/
public int increment(int offset) {
CharSequence txt = getText();
int i;
if (txt != null) {
try {
i = Integer.parseInt(txt.toString());
} catch (NumberFormatException e) {
i = 0;
}
} else {
i = 0;
}
i = i + offset;
setText(String.valueOf(i));
return i;
}
/**
* Decrement the numeric badge label. If the current badge label cannot be
* converted to an integer value, its label will be set to "0".
*
* #param offset
* the decrement offset.
*/
public int decrement(int offset) {
return increment(-offset);
}
private ShapeDrawable getDefaultBackground() {
int r = dipToPixels(DEFAULT_CORNER_RADIUS_DIP);
float[] outerR = new float[] { r, r, r, r, r, r, r, r };
RoundRectShape rr = new RoundRectShape(outerR, null, null);
ShapeDrawable drawable = new ShapeDrawable(rr);
drawable.getPaint().setColor(badgeColor);
return drawable;
}
private void applyLayoutParams() {
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, AbsoluteLayout.LayoutParams.WRAP_CONTENT);
switch (badgePosition) {
case POSITION_TOP_LEFT:
lp.gravity = Gravity.LEFT | Gravity.TOP;
lp.setMargins(badgeMarginH, badgeMarginV, 0, 0);
break;
case POSITION_TOP_RIGHT:
lp.gravity = Gravity.RIGHT | Gravity.TOP;
lp.setMargins(0, badgeMarginV, badgeMarginH, 0);
break;
case POSITION_BOTTOM_LEFT:
lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
lp.setMargins(badgeMarginH, 0, 0, badgeMarginV);
break;
case POSITION_BOTTOM_RIGHT:
lp.gravity = Gravity.RIGHT | Gravity.BOTTOM;
lp.setMargins(0, 0, badgeMarginH, badgeMarginV);
break;
case POSITION_CENTER:
lp.gravity = Gravity.CENTER;
lp.setMargins(0, 0, 0, 0);
break;
default:
break;
}
setLayoutParams(lp);
}
/**
* Returns the target View this badge has been attached to.
*
*/
public View getTarget() {
return target;
}
/**
* Is this badge currently visible in the UI?
*
*/
#Override
public boolean isShown() {
return isShown;
}
/**
* Returns the positioning of this badge.
*
* one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT, POSITION_BOTTOM_LEFT,
* POSITION_BOTTOM_RIGHT, POSTION_CENTER.
*
*/
public int getBadgePosition() {
return badgePosition;
}
/**
* Set the positioning of this badge.
*
* #param layoutPosition
* one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT,
* POSITION_BOTTOM_LEFT, POSITION_BOTTOM_RIGHT, POSTION_CENTER.
*
*/
public void setBadgePosition(int layoutPosition) {
this.badgePosition = layoutPosition;
}
/**
* Returns the horizontal margin from the target View that is applied to
* this badge.
*
*/
public int getHorizontalBadgeMargin() {
return badgeMarginH;
}
/**
* Returns the vertical margin from the target View that is applied to this
* badge.
*
*/
public int getVerticalBadgeMargin() {
return badgeMarginV;
}
/**
* Set the horizontal/vertical margin from the target View that is applied
* to this badge.
*
* #param badgeMargin
* the margin in pixels.
*/
public void setBadgeMargin(int badgeMargin) {
this.badgeMarginH = badgeMargin;
this.badgeMarginV = badgeMargin;
}
/**
* Set the horizontal/vertical margin from the target View that is applied
* to this badge.
*
* #param horizontal
* margin in pixels.
* #param vertical
* margin in pixels.
*/
public void setBadgeMargin(int horizontal, int vertical) {
this.badgeMarginH = horizontal;
this.badgeMarginV = vertical;
}
/**
* Returns the color value of the badge background.
*
*/
public int getBadgeBackgroundColor() {
return badgeColor;
}
/**
* Set the color value of the badge background.
*
* #param badgeColor
* the badge background color.
*/
public void setBadgeBackgroundColor(int badgeColor) {
this.badgeColor = badgeColor;
badgeBg = getDefaultBackground();
}
private int dipToPixels(int dip) {
Resources r = getResources();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
r.getDisplayMetrics());
return (int) px;
}
}
And wherever you want badge view just initialize and use it
BadgeView badge;

BadgeView and SlidingTabStrip clicking error

i am using sliding tab from:
https://developer.android.com/samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.html
and BadgeView from:
https://github.com/jgilfelt/android-viewbadger
i just add these lines of code to SlidingTabLayout to access each tab:
public SlidingTabStrip getTabStrip() {
return mTabStrip;
}
so in fragmenta i can use below code to add badgeview to each tab:
public class FragmentA extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.fragment_a,container,false);
Button b1 = (Button) fragmentView.findViewById(R.id.tab1_button_fragmenta);
b1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
View v = ((MainActivity)getActivity()).mSlidingTabLayout.getTabStrip().getChildAt(0);
BadgeView badge = new BadgeView(getActivity(), v);
badge.setText("1");
badge.show();
}
});
Button b2 = (Button) fragmentView.findViewById(R.id.tab2_button_fragmenta);
b2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
View v = ((MainActivity)getActivity()).mSlidingTabLayout.getTabStrip().getChildAt(1);
BadgeView badge = new BadgeView(getActivity(), v);
badge.setText("2");
badge.show();
}
});
Button b3 = (Button) fragmentView.findViewById(R.id.tab3_button_fragmenta);
b3.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
View v = ((MainActivity)getActivity()).mSlidingTabLayout.getTabStrip().getChildAt(2);
BadgeView badge = new BadgeView(getActivity(), v);
badge.setText("3");
badge.show();
}
});
return fragmentView;
}
and the fragment 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:background="#FFCC00" >
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
android:text="This is Fragment A"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="#+id/tab1_button_fragmenta"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/textView"
android:text="Add Badge To Tab 1" />
<Button
android:id="#+id/tab2_button_fragmenta"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/tab1_button_fragmenta"
android:text="Add Badge To Tab 2" />
<Button
android:id="#+id/tab3_button_fragmenta"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/tab2_button_fragmenta"
android:text="Add Badge To Tab 3" />
</RelativeLayout>
the result is:
but after i add BadgeView the functionality of clicking on tabs is gone. so i can not click on tabs to navigate to other pages. can anyone help me what to do?
here is main activity for those who just want to focus on solution and do not waste their time to create project:-)
public class MainActivity extends FragmentActivity {
ViewPager viewPager=null;
SlidingTabLayout mSlidingTabLayout = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager= (ViewPager) findViewById(R.id.pager);
FragmentManager fm = getSupportFragmentManager();
viewPager.setAdapter(new MyAdapter(fm));
mSlidingTabLayout = (SlidingTabLayout)findViewById(R.id.sliding_tabs);
mSlidingTabLayout.setViewPager(viewPager);
viewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));
mSlidingTabLayout.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
}
class MyAdapter extends FragmentStatePagerAdapter
{
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment=null;
if(i==0)
{
fragment=new FragmentA();
}
if(i==1)
{
fragment=new FragmentB();
}
if(i==2)
{
fragment=new FragmentC();
}
return fragment;
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
return ("Tab" + position);
}
}
}
and activity_main:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.tabbadge.SlidingTabLayout
android:id="#+id/sliding_tabs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
</LinearLayout>
First of All:
Code:
1) Use this BadgeView Class instead of jar.
public class BadgeView extends TextView {
public static final int POSITION_TOP_LEFT = 1;
public static final int POSITION_TOP_RIGHT = 2;
public static final int POSITION_BOTTOM_LEFT = 3;
public static final int POSITION_BOTTOM_RIGHT = 4;
public static final int POSITION_CENTER = 5;
private static final int DEFAULT_MARGIN_DIP = 5;
private static final int DEFAULT_LR_PADDING_DIP = 5;
private static final int DEFAULT_CORNER_RADIUS_DIP = 8;
private static final int DEFAULT_POSITION = POSITION_TOP_RIGHT;
private static final int DEFAULT_BADGE_COLOR = Color
.parseColor("#CCFF0000"); // Color.RED;
private static final int DEFAULT_TEXT_COLOR = Color.WHITE;
private static Animation fadeIn;
private static Animation fadeOut;
private Context context;
private View target;
private int badgePosition;
private int badgeMarginH;
private int badgeMarginV;
private int badgeColor;
private boolean isShown;
private ShapeDrawable badgeBg;
private int targetTabIndex;
public BadgeView(Context context) {
this(context, (AttributeSet) null, android.R.attr.textViewStyle);
}
public BadgeView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
/**
* Constructor -
*
* create a new BadgeView instance attached to a target
* {#link android.view.View}.
*
* #param context
* context for this view.
* #param target
* the View to attach the badge to.
*/
public BadgeView(Context context, View target) {
this(context, null, android.R.attr.textViewStyle, target, 0);
}
/**
* Constructor -
*
* create a new BadgeView instance attached to a target
* {#link android.widget.TabWidget} tab at a given index.
*
* #param context
* context for this view.
* #param target
* the TabWidget to attach the badge to.
* #param index
* the position of the tab within the target.
*/
public BadgeView(Context context, TabWidget target, int index) {
this(context, null, android.R.attr.textViewStyle, target, index);
}
public BadgeView(Context context, AttributeSet attrs, int defStyle) {
this(context, attrs, defStyle, null, 0);
}
public BadgeView(Context context, AttributeSet attrs, int defStyle,
View target, int tabIndex) {
super(context, attrs, defStyle);
init(context, target, tabIndex);
}
public BadgeView(Context context, viewbadger.demo.SlidingTabStrip target,
int i) {
// TODO Auto-generated constructor stub
this(context, null, android.R.attr.textViewStyle, target, i);
}
private void init(Context context, View target, int tabIndex) {
this.context = context;
this.target = target;
this.targetTabIndex = tabIndex;
// apply defaults
badgePosition = DEFAULT_POSITION;
badgeMarginH = dipToPixels(DEFAULT_MARGIN_DIP);
badgeMarginV = badgeMarginH;
badgeColor = DEFAULT_BADGE_COLOR;
setTypeface(Typeface.DEFAULT_BOLD);
int paddingPixels = dipToPixels(DEFAULT_LR_PADDING_DIP);
setPadding(paddingPixels, 0, paddingPixels, 0);
setTextColor(DEFAULT_TEXT_COLOR);
fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator());
fadeIn.setDuration(200);
fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator());
fadeOut.setDuration(200);
isShown = false;
if (this.target != null) {
applyTo(this.target);
} else {
show();
}
}
private void applyTo(View target) {
LayoutParams lp = target.getLayoutParams();
ViewParent parent = target.getParent();
FrameLayout container = new FrameLayout(context);
if (target instanceof TabWidget) {
// set target to the relevant tab child container
target = ((TabWidget) target).getChildTabViewAt(targetTabIndex);
this.target = target;
((ViewGroup) target).addView(container, new LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
this.setVisibility(View.GONE);
container.addView(this);
} else if (target instanceof SlidingTabStrip) {
// set target to the relevant tab child container
View textView = ((SlidingTabStrip) target)
.getChildAt(targetTabIndex);
ViewGroup group = (ViewGroup) target;
// getting index of TexTView from SlidingTabStrip
int index = group.indexOfChild(textView);
Log.e("index", "" + index);
group.removeView(textView);
group.addView(container, index, lp);
container.addView(textView);
this.setVisibility(View.GONE);
container.addView(this);
group.invalidate();
} else {
// TODO verify that parent is indeed a ViewGroup
ViewGroup group = (ViewGroup) parent;
int index = group.indexOfChild(target);
group.removeView(target);
group.addView(container, index, lp);
container.addView(target);
this.setVisibility(View.GONE);
container.addView(this);
group.invalidate();
}
}
/**
* Make the badge visible in the UI.
*
*/
public void show() {
show(false, null);
}
/**
* Make the badge visible in the UI.
*
* #param animate
* flag to apply the default fade-in animation.
*/
public void show(boolean animate) {
show(animate, fadeIn);
}
/**
* Make the badge visible in the UI.
*
* #param anim
* Animation to apply to the view when made visible.
*/
public void show(Animation anim) {
show(true, anim);
}
/**
* Make the badge non-visible in the UI.
*
*/
public void hide() {
hide(false, null);
}
/**
* Make the badge non-visible in the UI.
*
* #param animate
* flag to apply the default fade-out animation.
*/
public void hide(boolean animate) {
hide(animate, fadeOut);
}
/**
* Make the badge non-visible in the UI.
*
* #param anim
* Animation to apply to the view when made non-visible.
*/
public void hide(Animation anim) {
hide(true, anim);
}
/**
* Toggle the badge visibility in the UI.
*
*/
public void toggle() {
toggle(false, null, null);
}
/**
* Toggle the badge visibility in the UI.
*
* #param animate
* flag to apply the default fade-in/out animation.
*/
public void toggle(boolean animate) {
toggle(animate, fadeIn, fadeOut);
}
/**
* Toggle the badge visibility in the UI.
*
* #param animIn
* Animation to apply to the view when made visible.
* #param animOut
* Animation to apply to the view when made non-visible.
*/
public void toggle(Animation animIn, Animation animOut) {
toggle(true, animIn, animOut);
}
private void show(boolean animate, Animation anim) {
if (getBackground() == null) {
if (badgeBg == null) {
badgeBg = getDefaultBackground();
}
setBackgroundDrawable(badgeBg);
}
applyLayoutParams();
if (animate) {
this.startAnimation(anim);
}
this.setVisibility(View.VISIBLE);
isShown = true;
}
private void hide(boolean animate, Animation anim) {
this.setVisibility(View.GONE);
if (animate) {
this.startAnimation(anim);
}
isShown = false;
}
private void toggle(boolean animate, Animation animIn, Animation animOut) {
if (isShown) {
hide(animate && (animOut != null), animOut);
} else {
show(animate && (animIn != null), animIn);
}
}
/**
* Increment the numeric badge label. If the current badge label cannot be
* converted to an integer value, its label will be set to "0".
*
* #param offset
* the increment offset.
*/
public int increment(int offset) {
CharSequence txt = getText();
int i;
if (txt != null) {
try {
i = Integer.parseInt(txt.toString());
} catch (NumberFormatException e) {
i = 0;
}
} else {
i = 0;
}
i = i + offset;
setText(String.valueOf(i));
return i;
}
/**
* Decrement the numeric badge label. If the current badge label cannot be
* converted to an integer value, its label will be set to "0".
*
* #param offset
* the decrement offset.
*/
public int decrement(int offset) {
return increment(-offset);
}
private ShapeDrawable getDefaultBackground() {
int r = dipToPixels(DEFAULT_CORNER_RADIUS_DIP);
float[] outerR = new float[] { r, r, r, r, r, r, r, r };
RoundRectShape rr = new RoundRectShape(outerR, null, null);
ShapeDrawable drawable = new ShapeDrawable(rr);
drawable.getPaint().setColor(badgeColor);
return drawable;
}
private void applyLayoutParams() {
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
switch (badgePosition) {
case POSITION_TOP_LEFT:
lp.gravity = Gravity.LEFT | Gravity.TOP;
lp.setMargins(badgeMarginH, badgeMarginV, 0, 0);
break;
case POSITION_TOP_RIGHT:
lp.gravity = Gravity.RIGHT | Gravity.TOP;
lp.setMargins(0, badgeMarginV, badgeMarginH, 0);
break;
case POSITION_BOTTOM_LEFT:
lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
lp.setMargins(badgeMarginH, 0, 0, badgeMarginV);
break;
case POSITION_BOTTOM_RIGHT:
lp.gravity = Gravity.RIGHT | Gravity.BOTTOM;
lp.setMargins(0, 0, badgeMarginH, badgeMarginV);
break;
case POSITION_CENTER:
lp.gravity = Gravity.CENTER;
lp.setMargins(0, 0, 0, 0);
break;
default:
break;
}
setLayoutParams(lp);
}
/**
* Returns the target View this badge has been attached to.
*
*/
public View getTarget() {
return target;
}
/**
* Is this badge currently visible in the UI?
*
*/
#Override
public boolean isShown() {
return isShown;
}
/**
* Returns the positioning of this badge.
*
* one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT, POSITION_BOTTOM_LEFT,
* POSITION_BOTTOM_RIGHT, POSTION_CENTER.
*
*/
public int getBadgePosition() {
return badgePosition;
}
/**
* Set the positioning of this badge.
*
* #param layoutPosition
* one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT,
* POSITION_BOTTOM_LEFT, POSITION_BOTTOM_RIGHT, POSTION_CENTER.
*
*/
public void setBadgePosition(int layoutPosition) {
this.badgePosition = layoutPosition;
}
/**
* Returns the horizontal margin from the target View that is applied to
* this badge.
*
*/
public int getHorizontalBadgeMargin() {
return badgeMarginH;
}
/**
* Returns the vertical margin from the target View that is applied to this
* badge.
*
*/
public int getVerticalBadgeMargin() {
return badgeMarginV;
}
/**
* Set the horizontal/vertical margin from the target View that is applied
* to this badge.
*
* #param badgeMargin
* the margin in pixels.
*/
public void setBadgeMargin(int badgeMargin) {
this.badgeMarginH = badgeMargin;
this.badgeMarginV = badgeMargin;
}
/**
* Set the horizontal/vertical margin from the target View that is applied
* to this badge.
*
* #param horizontal
* margin in pixels.
* #param vertical
* margin in pixels.
*/
public void setBadgeMargin(int horizontal, int vertical) {
this.badgeMarginH = horizontal;
this.badgeMarginV = vertical;
}
/**
* Returns the color value of the badge background.
*
*/
public int getBadgeBackgroundColor() {
return badgeColor;
}
/**
* Set the color value of the badge background.
*
* #param badgeColor
* the badge background color.
*/
public void setBadgeBackgroundColor(int badgeColor) {
this.badgeColor = badgeColor;
badgeBg = getDefaultBackground();
}
private int dipToPixels(int dip) {
Resources r = getResources();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
r.getDisplayMetrics());
return (int) px;
}
}
2) Use this SlidingTabLayout instead of Original one:
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package viewbadger.demo;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Build;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.TextView;
/**
* To be used with ViewPager to provide a tab indicator component which give
* constant feedback as to the user's scroll progress.
* <p>
* To use the component, simply add it to your view hierarchy. Then in your
* {#link android.app.Activity} or {#link android.support.v4.app.Fragment} call
* {#link #setViewPager(ViewPager)} providing it the ViewPager this layout is
* being used for.
* <p>
* The colors can be customized in two ways. The first and simplest is to
* provide an array of colors via {#link #setSelectedIndicatorColors(int...)}
* and {#link #setDividerColors(int...)}. The alternative is via the
* {#link TabColorizer} interface which provides you complete control over which
* color is used for any individual position.
* <p>
* The views used as tabs can be customized by calling
* {#link #setCustomTabView(int, int)}, providing the layout ID of your custom
* layout.
*/
public class SlidingTabLayout extends HorizontalScrollView {
/**
* Allows complete control over the colors drawn in the tab layout. Set with
* {#link #setCustomTabColorizer(TabColorizer)}.
*/
public interface TabColorizer {
/**
* #return return the color of the indicator used when {#code position}
* is selected.
*/
int getIndicatorColor(int position);
/**
* #return return the color of the divider drawn to the right of
* {#code position}.
*/
int getDividerColor(int position);
}
private static final int TITLE_OFFSET_DIPS = 24;
private static final int TAB_VIEW_PADDING_DIPS = 16;
private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
private int mTitleOffset;
private int mTabViewLayoutId;
private int mTabViewTextViewId;
public SlidingTabStrip getTabStrip() {
return mTabStrip;
}
private ViewPager mViewPager;
private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
private final SlidingTabStrip mTabStrip;
public SlidingTabLayout(Context context) {
this(context, null);
}
public SlidingTabLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// Disable the Scroll Bar
setHorizontalScrollBarEnabled(false);
// Make sure that the Tab Strips fills this View
setFillViewport(true);
mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources()
.getDisplayMetrics().density);
mTabStrip = new SlidingTabStrip(context);
addView(mTabStrip, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
}
/**
* Set the custom {#link TabColorizer} to be used.
*
* If you only require simple custmisation then you can use
* {#link #setSelectedIndicatorColors(int...)} and
* {#link #setDividerColors(int...)} to achieve similar effects.
*/
public void setCustomTabColorizer(TabColorizer tabColorizer) {
mTabStrip.setCustomTabColorizer(tabColorizer);
}
/**
* Sets the colors to be used for indicating the selected tab. These colors
* are treated as a circular array. Providing one color will mean that all
* tabs are indicated with the same color.
*/
public void setSelectedIndicatorColors(int... colors) {
mTabStrip.setSelectedIndicatorColors(colors);
}
/**
* Sets the colors to be used for tab dividers. These colors are treated as
* a circular array. Providing one color will mean that all tabs are
* indicated with the same color.
*/
public void setDividerColors(int... colors) {
mTabStrip.setDividerColors(colors);
}
/**
* Set the {#link ViewPager.OnPageChangeListener}. When using
* {#link SlidingTabLayout} you are required to set any
* {#link ViewPager.OnPageChangeListener} through this method. This is so
* that the layout can update it's scroll position correctly.
*
* #see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
*/
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
mViewPagerPageChangeListener = listener;
}
/**
* Set the custom layout to be inflated for the tab views.
*
* #param layoutResId
* Layout id to be inflated
* #param textViewId
* id of the {#link TextView} in the inflated view
*/
public void setCustomTabView(int layoutResId, int textViewId) {
mTabViewLayoutId = layoutResId;
mTabViewTextViewId = textViewId;
}
/**
* Sets the associated view pager. Note that the assumption here is that the
* pager content (number of tabs and tab titles) does not change after this
* call has been made.
*/
public void setViewPager(ViewPager viewPager) {
mTabStrip.removeAllViews();
mViewPager = viewPager;
if (viewPager != null) {
viewPager.setOnPageChangeListener(new InternalViewPagerListener());
populateTabStrip();
}
}
/**
* Create a default view to be used for tabs. This is called if a custom tab
* view is not set via {#link #setCustomTabView(int, int)}.
*/
#SuppressLint("NewApi")
protected TextView createDefaultTabView(Context context) {
TextView textView = new TextView(context);
textView.setGravity(Gravity.CENTER);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
textView.setTypeface(Typeface.DEFAULT_BOLD);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// If we're running on Honeycomb or newer, then we can use the
// Theme's
// selectableItemBackground to ensure that the View has a pressed
// state
TypedValue outValue = new TypedValue();
getContext().getTheme().resolveAttribute(
android.R.attr.selectableItemBackground, outValue, true);
textView.setBackgroundResource(outValue.resourceId);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// If we're running on ICS or newer, enable all-caps to match the
// Action Bar tab style
textView.setAllCaps(true);
}
int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources()
.getDisplayMetrics().density);
textView.setPadding(padding, padding, padding, padding);
return textView;
}
private void populateTabStrip() {
final PagerAdapter adapter = mViewPager.getAdapter();
final View.OnClickListener tabClickListener = new TabClickListener();
for (int i = 0; i < adapter.getCount(); i++) {
View tabView = null;
TextView tabTitleView = null;
if (mTabViewLayoutId != 0) {
// If there is a custom tab view layout id set, try and inflate
// it
tabView = LayoutInflater.from(getContext()).inflate(
mTabViewLayoutId, mTabStrip, false);
tabTitleView = (TextView) tabView
.findViewById(mTabViewTextViewId);
}
if (tabView == null) {
tabView = createDefaultTabView(getContext());
}
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
tabTitleView = (TextView) tabView;
}
tabTitleView.setText(adapter.getPageTitle(i));
// tabView.setOnClickListener(tabClickListener);
final int index_i = i;
tabView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
mViewPager.setCurrentItem(index_i);
}
});
mTabStrip.addView(tabView);
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mViewPager != null) {
scrollToTab(mViewPager.getCurrentItem(), 0);
}
}
private void scrollToTab(int tabIndex, int positionOffset) {
final int tabStripChildCount = mTabStrip.getChildCount();
if (tabStripChildCount == 0 || tabIndex < 0
|| tabIndex >= tabStripChildCount) {
return;
}
View selectedChild = mTabStrip.getChildAt(tabIndex);
if (selectedChild != null) {
int targetScrollX = selectedChild.getLeft() + positionOffset;
if (tabIndex > 0 || positionOffset > 0) {
// If we're not at the first child and are mid-scroll, make sure
// we obey the offset
targetScrollX -= mTitleOffset;
}
scrollTo(targetScrollX, 0);
}
}
private class InternalViewPagerListener implements
ViewPager.OnPageChangeListener {
private int mScrollState;
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
int tabStripChildCount = mTabStrip.getChildCount();
if ((tabStripChildCount == 0) || (position < 0)
|| (position >= tabStripChildCount)) {
return;
}
mTabStrip.onViewPagerPageChanged(position, positionOffset);
View selectedTitle = mTabStrip.getChildAt(position);
int extraOffset = (selectedTitle != null) ? (int) (positionOffset * selectedTitle
.getWidth()) : 0;
scrollToTab(position, extraOffset);
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageScrolled(position,
positionOffset, positionOffsetPixels);
}
}
#Override
public void onPageScrollStateChanged(int state) {
mScrollState = state;
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageScrollStateChanged(state);
}
}
#Override
public void onPageSelected(int position) {
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
mTabStrip.onViewPagerPageChanged(position, 0f);
scrollToTab(position, 0);
}
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageSelected(position);
}
}
}
private class TabClickListener implements View.OnClickListener {
#Override
public void onClick(View v) {
Log.e("tab click listener", "" + v + " : unmatched");
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
View vv = mTabStrip.getChildAt(i);
if (vv instanceof FrameLayout) {
Log.e("frameLayout", "framelayout");
Log.e("" + v, "" + vv);
}
if (v == vv) {
mViewPager.setCurrentItem(i);
Log.e("tab click listener", "" + v + " : matched pos : "
+ i);
return;
}
}
}
}
}
3) FragmentA button click listener code :
Button b1 = (Button) fragmentView
.findViewById(R.id.tab1_button_fragmenta);
b1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
badge = new BadgeView(getActivity(),
((DemoActivity) getActivity()).mSlidingTabLayout
.getTabStrip(), 0);
badge.setText("1");
badge.toggle();
}
});
Button b2 = (Button) fragmentView
.findViewById(R.id.tab1_button_fragmentb);
b2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
BadgeView badge = new BadgeView(getActivity(),
((DemoActivity) getActivity()).mSlidingTabLayout
.getTabStrip(), 1);
badge.setText("2");
badge.toggle();
}
});
And You are Done. :)
Now Reasoning:
The problem is that ViewBadger Removes the original View and adds Framelayout and that removed view after dynamically adding a textView. is That matters?
Yes: because You are using SlidingTabLayout. In which onTabClickListener Class is used, which checks that if a view is of type TextView. See this code below, Before adding the badview it will always show the textview, but after that it will show framelayout for badgedview.
private class TabClickListener implements View.OnClickListener {
#Override
public void onClick(View v) {
Log.e("tab click listener", "" + v + " : unmatched");
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
View vv = mTabStrip.getChildAt(i);
// I have added these lines for debugging
if (vv instanceof FrameLayout) {
Log.e("frameLayout", "framelayout");
}
else if (vv instanceof TextView) {
Log.e("textview", "textview");
}
// Original Code
if (v == mTabStrip.getChildAt(i)) {
mViewPager.setCurrentItem(i);
Log.e("tab click listener", "" + v + " : matched pos : "
+ i);
return;
}
}
}
}
So I replaced that clickListener Class and Used this code :
final int index_i = i;
tabView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
mViewPager.setCurrentItem(index_i);
}
});
which does not see that whether it is textView of FrameLayout or whatever, just load the item at ith Index. :)
Cheers
-Nadeem Iqbal

ActionBar setIcon with Font-Awesome

Is it possible to set an Icon in ActionBar through setIcon method (that accept drawable or Resource id) with a "Text" using AwesomeFont?
Should I create a Drawable or something like that? In Drawable what should I Create?
EDIT
public class AwesomeTextView extends TextView {
private static Typeface fontAwesome;
public AwesomeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
if (fontAwesome == null) {
fontAwesome = Typeface.createFromAsset(context.getAssets(), "fonts/fontawesome-webfont.ttf");
}
setTypeface(fontAwesome);
}
}
So I had created an AwesomeTextView that uses font-awesome, Is there a way to make an AwesomeTextView as drawable?
I made a repo to easily add font awesome icons to your android project
https://github.com/bperin/FontAwesomeAndroid
If you're trying to add these in an action bar you'll probably need to make a custom layout via XML
Yes, you need to create a Drawable and draw the icon. You could take a look at the TextDrawable project on github. You can modify it such that Font-Awesome is used as the typeface.
Make sure that you bundle the font along with the project.
Here's a complete guide on how to set Icon with FontAwesome with setIcon() method.
http://blog.incognitech.in/font-awesome-in-android
UPDATE:
FontManager Class
public class FontAwesomeManager {
public static final String ROOT = "fonts/";
public static final String FONTAWESOME = ROOT + "fontawesome-webfont.ttf";
public static Typeface getTypeface(Context context, String font) {
return Typeface.createFromAsset(context.getAssets(), font);
}
}
TextDrawable class
package in.incognitech.reminder.util;
/**
* Copyright (c) 2012 Wireless Designs, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.TypedValue;
/**
* A Drawable object that draws text.
* A TextDrawable accepts most of the same parameters that can be applied to
* {#link android.widget.TextView} for displaying and formatting text.
*
* Optionally, a {#link Path} may be supplied on which to draw the text.
*
* A TextDrawable has an intrinsic size equal to that required to draw all
* the text it has been supplied, when possible. In cases where a {#link Path}
* has been supplied, the caller must explicitly call
* {#link #setBounds(android.graphics.Rect) setBounds()} to provide the Drawable
* size based on the Path constraints.
*/
public class TextDrawable extends Drawable {
/* Platform XML constants for typeface */
private static final int SANS = 1;
private static final int SERIF = 2;
private static final int MONOSPACE = 3;
/* Resources for scaling values to the given device */
private Resources mResources;
/* Paint to hold most drawing primitives for the text */
private TextPaint mTextPaint;
/* Layout is used to measure and draw the text */
private StaticLayout mTextLayout;
/* Alignment of the text inside its bounds */
private Layout.Alignment mTextAlignment = Layout.Alignment.ALIGN_NORMAL;
/* Optional path on which to draw the text */
private Path mTextPath;
/* Stateful text color list */
private ColorStateList mTextColors;
/* Container for the bounds to be reported to widgets */
private Rect mTextBounds;
/* Text string to draw */
private CharSequence mText = "";
/* Attribute lists to pull default values from the current theme */
private static final int[] themeAttributes = {
android.R.attr.textAppearance
};
private static final int[] appearanceAttributes = {
android.R.attr.textSize,
android.R.attr.typeface,
android.R.attr.textStyle,
android.R.attr.textColor
};
public TextDrawable(Context context) {
super();
//Used to load and scale resource items
mResources = context.getResources();
//Definition of this drawables size
mTextBounds = new Rect();
//Paint to use for the text
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.density = mResources.getDisplayMetrics().density;
mTextPaint.setDither(true);
int textSize = 15;
ColorStateList textColor = null;
int styleIndex = -1;
int typefaceIndex = -1;
//Set default parameters from the current theme
TypedArray a = context.getTheme().obtainStyledAttributes(themeAttributes);
int appearanceId = a.getResourceId(0, -1);
a.recycle();
TypedArray ap = null;
if (appearanceId != -1) {
ap = context.obtainStyledAttributes(appearanceId, appearanceAttributes);
}
if (ap != null) {
for (int i=0; i < ap.getIndexCount(); i++) {
int attr = ap.getIndex(i);
switch (attr) {
case 0: //Text Size
textSize = a.getDimensionPixelSize(attr, textSize);
break;
case 1: //Typeface
typefaceIndex = a.getInt(attr, typefaceIndex);
break;
case 2: //Text Style
styleIndex = a.getInt(attr, styleIndex);
break;
case 3: //Text Color
textColor = a.getColorStateList(attr);
break;
default:
break;
}
}
ap.recycle();
}
setTextColor(textColor != null ? textColor : ColorStateList.valueOf(0xFF000000));
setRawTextSize(textSize);
Typeface tf = null;
switch (typefaceIndex) {
case SANS:
tf = Typeface.SANS_SERIF;
break;
case SERIF:
tf = Typeface.SERIF;
break;
case MONOSPACE:
tf = Typeface.MONOSPACE;
break;
}
setTypeface(tf, styleIndex);
}
/**
* Set the text that will be displayed
* #param text Text to display
*/
public void setText(CharSequence text) {
if (text == null) text = "";
mText = text;
measureContent();
}
/**
* Return the text currently being displayed
*/
public CharSequence getText() {
return mText;
}
/**
* Return the current text size, in pixels
*/
public float getTextSize() {
return mTextPaint.getTextSize();
}
/**
* Set the text size. The value will be interpreted in "sp" units
* #param size Text size value, in sp
*/
public void setTextSize(float size) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
}
/**
* Set the text size, using the supplied complex units
* #param unit Units for the text size, such as dp or sp
* #param size Text size value
*/
public void setTextSize(int unit, float size) {
float dimension = TypedValue.applyDimension(unit, size,
mResources.getDisplayMetrics());
setRawTextSize(dimension);
}
/*
* Set the text size, in raw pixels
*/
private void setRawTextSize(float size) {
if (size != mTextPaint.getTextSize()) {
mTextPaint.setTextSize(size);
measureContent();
}
}
/**
* Return the horizontal stretch factor of the text
*/
public float getTextScaleX() {
return mTextPaint.getTextScaleX();
}
/**
* Set the horizontal stretch factor of the text
* #param size Text scale factor
*/
public void setTextScaleX(float size) {
if (size != mTextPaint.getTextScaleX()) {
mTextPaint.setTextScaleX(size);
measureContent();
}
}
/**
* Return the current text alignment setting
*/
public Layout.Alignment getTextAlign() {
return mTextAlignment;
}
/**
* Set the text alignment. The alignment itself is based on the text layout direction.
* For LTR text NORMAL is left aligned and OPPOSITE is right aligned.
* For RTL text, those alignments are reversed.
* #param align Text alignment value. Should be set to one of:
*
* {#link Layout.Alignment#ALIGN_NORMAL},
* {#link Layout.Alignment#ALIGN_NORMAL},
* {#link Layout.Alignment#ALIGN_OPPOSITE}.
*/
public void setTextAlign(Layout.Alignment align) {
if (mTextAlignment != align) {
mTextAlignment = align;
measureContent();
}
}
/**
* Sets the typeface and style in which the text should be displayed.
* Note that not all Typeface families actually have bold and italic
* variants, so you may need to use
* {#link #setTypeface(Typeface, int)} to get the appearance
* that you actually want.
*/
public void setTypeface(Typeface tf) {
if (mTextPaint.getTypeface() != tf) {
mTextPaint.setTypeface(tf);
measureContent();
}
}
/**
* Sets the typeface and style in which the text should be displayed,
* and turns on the fake bold and italic bits in the Paint if the
* Typeface that you provided does not have all the bits in the
* style that you specified.
*
*/
public void setTypeface(Typeface tf, int style) {
if (style > 0) {
if (tf == null) {
tf = Typeface.defaultFromStyle(style);
} else {
tf = Typeface.create(tf, style);
}
setTypeface(tf);
// now compute what (if any) algorithmic styling is needed
int typefaceStyle = tf != null ? tf.getStyle() : 0;
int need = style & ~typefaceStyle;
mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
} else {
mTextPaint.setFakeBoldText(false);
mTextPaint.setTextSkewX(0);
setTypeface(tf);
}
}
/**
* Return the current typeface and style that the Paint
* using for display.
*/
public Typeface getTypeface() {
return mTextPaint.getTypeface();
}
/**
* Set a single text color for all states
* #param color Color value such as {#link Color#WHITE} or {#link Color#argb(int, int, int, int)}
*/
public void setTextColor(int color) {
setTextColor(ColorStateList.valueOf(color));
}
/**
* Set the text color as a state list
* #param colorStateList ColorStateList of text colors, such as inflated from an R.color resource
*/
public void setTextColor(ColorStateList colorStateList) {
mTextColors = colorStateList;
updateTextColors(getState());
}
/**
* Optional Path object on which to draw the text. If this is set,
* TextDrawable cannot properly measure the bounds this drawable will need.
* You must call {#link #setBounds(int, int, int, int) setBounds()} before
* applying this TextDrawable to any View.
*
* Calling this method with <code>null</code> will remove any Path currently attached.
*/
public void setTextPath(Path path) {
if (mTextPath != path) {
mTextPath = path;
measureContent();
}
}
/**
* Internal method to take measurements of the current contents and apply
* the correct bounds when possible.
*/
private void measureContent() {
//If drawing to a path, we cannot measure intrinsic bounds
//We must resly on setBounds being called externally
if (mTextPath != null) {
//Clear any previous measurement
mTextLayout = null;
mTextBounds.setEmpty();
} else {
//Measure text bounds
double desired = Math.ceil( Layout.getDesiredWidth(mText, mTextPaint) );
mTextLayout = new StaticLayout(mText, mTextPaint, (int)desired,
mTextAlignment, 1.0f, 0.0f, false);
mTextBounds.set(0, 0, mTextLayout.getWidth(), mTextLayout.getHeight());
}
//We may need to be redrawn
invalidateSelf();
}
/**
* Internal method to apply the correct text color based on the drawable's state
*/
private boolean updateTextColors(int[] stateSet) {
int newColor = mTextColors.getColorForState(stateSet, Color.WHITE);
if (mTextPaint.getColor() != newColor) {
mTextPaint.setColor(newColor);
return true;
}
return false;
}
#Override
protected void onBoundsChange(Rect bounds) {
//Update the internal bounds in response to any external requests
mTextBounds.set(bounds);
}
#Override
public boolean isStateful() {
/*
* The drawable's ability to represent state is based on
* the text color list set
*/
return mTextColors.isStateful();
}
#Override
protected boolean onStateChange(int[] state) {
//Upon state changes, grab the correct text color
return updateTextColors(state);
}
#Override
public int getIntrinsicHeight() {
//Return the vertical bounds measured, or -1 if none
if (mTextBounds.isEmpty()) {
return -1;
} else {
return (mTextBounds.bottom - mTextBounds.top);
}
}
#Override
public int getIntrinsicWidth() {
//Return the horizontal bounds measured, or -1 if none
if (mTextBounds.isEmpty()) {
return -1;
} else {
return (mTextBounds.right - mTextBounds.left);
}
}
#Override
public void draw(Canvas canvas) {
final Rect bounds = getBounds();
final int count = canvas.save();
canvas.translate(bounds.left, bounds.top);
if (mTextPath == null) {
//Allow the layout to draw the text
mTextLayout.draw(canvas);
} else {
//Draw directly on the canvas using the supplied path
canvas.drawTextOnPath(mText.toString(), mTextPath, 0, 0, mTextPaint);
}
canvas.restoreToCount(count);
}
#Override
public void setAlpha(int alpha) {
if (mTextPaint.getAlpha() != alpha) {
mTextPaint.setAlpha(alpha);
}
}
#Override
public int getOpacity() {
return mTextPaint.getAlpha();
}
#Override
public void setColorFilter(ColorFilter cf) {
if (mTextPaint.getColorFilter() != cf) {
mTextPaint.setColorFilter(cf);
}
}
}
Use FontManager & TextDrawable class
// ...
TextDrawable faIcon = new TextDrawable(this);
faIcon.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
faIcon.setTextAlign(Layout.Alignment.ALIGN_CENTER);
faIcon.setTypeface(FontAwesomeManager.getTypeface(this, FontAwesomeManager.FONTAWESOME));
faIcon.setText(getResources().getText(R.string.fa_android));
getActionBar().setIcon(faIcon);
// ...

Marquee Set Speed

I Am using a marquee to show the text in one of my Activitys. My question is it possible to speed up the rate of the marquee so it scrolls along the screen faster. Below is my XML and Java.
TextView et2 = (TextView) findViewById(R.id.noneednum);
et2.setEllipsize(TruncateAt.MARQUEE);
et2.setText("");
if (num.size() > 0) {
for (String str : num) {
et2.append(str + " ");
}
}
et2.setSelected(true);
}
And XML:
<TextView
android:id="#+id/noneednum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:gravity="center_vertical|center_horizontal"
android:lines="1"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="Large Text"
android:textColor="#fff"
android:textSize="140dp" />
You have to create a custom class for scrolling the text:
ScrollTextView.java
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;
}
}
In your layout write like this:
<yourpackagename.ScrollTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/scrolltext" />
In your activity write like this:
ScrollTextView scrolltext=(ScrollTextView) findViewById(R.id.scrolltext);
scrolltext.setText(yourscrollingtext);
scrolltext.setTextColor(Color.BLACK);
scrolltext.startScroll();
If you want to increase the scrolling speed then reduce the value of :
private int mRndDuration = 10000;//reduce the value of mRndDuration to increase scrolling speed
Above code fails if the TextView is an instance of AppCompatTextView. Below code works is it is AppCompatTextView. Tested in Marshmallow.
public static void setMarqueeSpeed(TextView tv, float speed) {
if (tv != null) {
try {
Field f = null;
if (tv instanceof AppCompatTextView) {
f = tv.getClass().getSuperclass().getDeclaredField("mMarquee");
} else {
f = tv.getClass().getDeclaredField("mMarquee");
}
if (f != null) {
f.setAccessible(true);
Object marquee = f.get(tv);
if (marquee != null) {
String scrollSpeedFieldName = "mScrollUnit";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scrollSpeedFieldName = "mPixelsPerSecond";
}
Field mf = marquee.getClass().getDeclaredField(scrollSpeedFieldName);
mf.setAccessible(true);
mf.setFloat(marquee, speed);
}
} else {
Logger.e("Marquee", "mMarquee object is null.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
This works for me. If f.get(tv) returns null, try calling mTextView.setSelected(true) before calling setMarqueeSpeed().
Original answer: Android and a TextView's horizontal marquee scroll rate
private void setMarqueeSpeed(TextView tv, float speed, boolean speedIsMultiplier) {
try {
Field f = tv.getClass().getDeclaredField("mMarquee");
f.setAccessible(true);
Object marquee = f.get(tv);
if (marquee != null) {
String scrollSpeedFieldName = "mScrollUnit";
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.L)
scrollSpeedFieldName = "mPixelsPerSecond";
Field mf = marquee.getClass().getDeclaredField(scrollSpeedFieldName);
mf.setAccessible(true);
float newSpeed = speed;
if (speedIsMultiplier)
newSpeed = mf.getFloat(marquee) * speed;
mf.setFloat(marquee, newSpeed);
}
} catch (Exception e) {
e.printStackTrace();
}
}
I resolved above scrolling problems on my device running Android 7.1 taking from multiple posts here and elsewhere
Solved speed issue
Scrolling only if needed / text is longer than width of TextView
Works with extending TextView or AppCompatTextView
package com.myclass.classes;
import android.content.Context;
import android.graphics.Rect;
import android.text.Layout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.LinearInterpolator;
import android.widget.Scroller;
import android.widget.TextView;
public class ScrollTextView extends TextView {
// scrolling feature
private Scroller mSlr;
// the X offset when paused
private int mXPaused = 0;
// whether it's being paused
private boolean mPaused = true;
private float mScrollSpeed = 250f; //Added speed for same scrolling speed regardless of text
/*
* constructor
*/
public ScrollTextView(Context context) {
this(context, null);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(VISIBLE);
getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener); //added listener check
}
/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(VISIBLE);
getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener); //added listener check
}
/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(VISIBLE);
getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener); //added listener check
}
#Override
protected void onDetachedFromWindow() {
removeGlobalListener();
super.onDetachedFromWindow();
}
/**
* begin to scroll the text from the original position
*/
private void startScroll() {
boolean needsScrolling = checkIfNeedsScrolling();
// begin from the middle
mXPaused = -1 * (getWidth() / 2);
// assume it's paused
mPaused = true;
if (needsScrolling) {
resumeScroll();
} else {
pauseScroll();
}
removeGlobalListener();
}
/**
* Removing global listener
**/
private synchronized void removeGlobalListener() {
try {
if (onGlobalLayoutListener != null)
getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
onGlobalLayoutListener = null;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Waiting for layout to initiate
*/
private OnGlobalLayoutListener onGlobalLayoutListener = () -> {
startScroll();
};
/**
* Checking if we need scrolling
*/
private boolean checkIfNeedsScrolling() {
measure(0, 0);
int textViewWidth = getWidth();
if (textViewWidth == 0)
return false;
float textWidth = getTextLength();
return textWidth > textViewWidth;
}
/**
* 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 = (int) (1000f * distance / mScrollSpeed);
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() {
int length = getTextLength();
return length + getWidth();
}
private int getTextLength() {
TextPaint tp = getPaint();
Rect rect = new Rect();
String strTxt = getText().toString();
tp.getTextBounds(strTxt, 0, strTxt.length(), rect);
int length = rect.width();
rect = null;
return length;
}
/**
* 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 boolean isPaused() {
return mPaused;
}
}
With help of the accepted answer & some changes, you can now setSpeed() even at runtime using this library.
https://github.com/RohanPatil1/SpeedMarquee
Using XML
<com.rohan.speed_marquee.SpeedMarquee
android:id="#+id/marqueeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/dummy_text"
android:maxLines="1"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:marquee_speed="180.0" />
Using Methods
findViewById<Button>(R.id.speedButton).setOnClickListener {
//Increment Text3's speed by 100.0
marqueeTextView3.setSpeed(marqueeTextView3.getSpeed() + 100.0f)
}
}

Android: Change activity state when receiving a phone call

A problem came up in my latest android programming project.
The problem is I would like to change Activity that launches when the phone receives a call.
Is it possible to add some text after the contact name when a call is received.
I have search the web for something that could do that, and been looking in the API for hours and I cannot find anything, is it possible with reflection of something like that?
I have made a class that listens to when the phone_state is receiving a call, and I can get the incomming number, but I would like to change the appearance on the screen.
// Thanks in advance
you can,t edit InCallScreen interface. but you can display some Text or whatever above it using toast,
class MyToast ............
package i4nc4mp.myLock.phone;
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.widget.TextView;
/**
* A toast is a view containing a quick little message for the user. The toast class
* helps you create and show those.
* {#more}
*
* <p>
* When the view is shown to the user, appears as a floating view over the
* application. It will never receive focus. The user will probably be in the
* middle of typing something else. The idea is to be as unobtrusive as
* possible, while still showing the user the information you want them to see.
* Two examples are the volume control, and the brief message saying that your
* settings have been saved.
* <p>
* The easiest way to use this class is to call one of the static methods that constructs
* everything you need and returns a new Toast object.
*/
public class MyToast {
static final String TAG = "Toast";
static final boolean localLOGV = false;
/**
* Show the view or text notification for a short period of time. This time
* could be user-definable. This is the default.
* #see #setDuration
*/
public static final int LENGTH_SHORT = 0;
/**
* Show the view or text notification for a long period of time. This time
* could be user-definable.
* #see #setDuration
*/
public static final int LENGTH_LONG = 1;
final Handler mHandler = new Handler();
final Context mContext;
final TN mTN;
int mDuration;
int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
int mX, mY;
float mHorizontalMargin;
float mVerticalMargin;
View mView;
View mNextView;
/**
* Construct an empty Toast object. You must call {#link #setView} before you
* can call {#link #show}.
*
* #param context The context to use. Usually your {#link android.app.Application}
* or {#link android.app.Activity} object.
*/
public MyToast(Context context) {
mContext = context;
mTN = new TN();
mY = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.toast_y_offset);
}
/**
* Show the view for the specified duration.
*/
public void show() {
if (mNextView == null) {
throw new RuntimeException("setView must have been called");
}
INotificationManager service = getService();
String pkg = mContext.getPackageName();
TN tn = mTN;
try {
service.enqueueToast(pkg, tn, mDuration);
} catch (RemoteException e) {
// Empty
}
}
/**
* Close the view if it's showing, or don't show it if it isn't showing yet.
* You do not normally have to call this. Normally view will disappear on its own
* after the appropriate duration.
*/
public void cancel() {
mTN.myHide();
// TODO this still needs to cancel the inflight notification if any
}
/**
* Set the view to show.
* #see #getView
*/
public void setView(View view) {
mNextView = view;
}
/**
* Return the view.
* #see #setView
*/
public View getView() {
return mNextView;
}
/**
* Set how long to show the view for.
* #see #LENGTH_SHORT
* #see #LENGTH_LONG
*/
public void setDuration(int duration) {
mDuration = duration;
}
/**
* Return the duration.
* #see #setDuration
*/
public int getDuration() {
return mDuration;
}
/**
* Set the margins of the view.
*
* #param horizontalMargin The horizontal margin, in percentage of the
* container width, between the container's edges and the
* notification
* #param verticalMargin The vertical margin, in percentage of the
* container height, between the container's edges and the
* notification
*/
public void setMargin(float horizontalMargin, float verticalMargin) {
mHorizontalMargin = horizontalMargin;
mVerticalMargin = verticalMargin;
}
/**
* Return the horizontal margin.
*/
public float getHorizontalMargin() {
return mHorizontalMargin;
}
/**
* Return the vertical margin.
*/
public float getVerticalMargin() {
return mVerticalMargin;
}
/**
* Set the location at which the notification should appear on the screen.
* #see android.view.Gravity
* #see #getGravity
*/
public void setGravity(int gravity, int xOffset, int yOffset) {
mGravity = gravity;
mX = xOffset;
mY = yOffset;
}
/**
* Get the location at which the notification should appear on the screen.
* #see android.view.Gravity
* #see #getGravity
*/
public int getGravity() {
return mGravity;
}
/**
* Return the X offset in pixels to apply to the gravity's location.
*/
public int getXOffset() {
return mX;
}
/**
* Return the Y offset in pixels to apply to the gravity's location.
*/
public int getYOffset() {
return mY;
}
/**
* Make a standard toast that just contains a text view.
*
* #param context The context to use. Usually your {#link android.app.Application}
* or {#link android.app.Activity} object.
* #param text The text to show. Can be formatted text.
* #param duration How long to display the message. Either {#link #LENGTH_SHORT} or
* {#link #LENGTH_LONG}
*
*/
public static MyToast makeText(Context context, CharSequence text, int duration) {
MyToast result = new MyToast(context);
LayoutInflater inflate = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
tv.setText(text);
result.mNextView = v;
result.mDuration = duration;
return result;
}
/**
* Make a standard toast that just contains a text view with the text from a resource.
*
* #param context The context to use. Usually your {#link android.app.Application}
* or {#link android.app.Activity} object.
* #param resId The resource id of the string resource to use. Can be formatted text.
* #param duration How long to display the message. Either {#link #LENGTH_SHORT} or
* {#link #LENGTH_LONG}
*
* #throws Resources.NotFoundException if the resource can't be found.
*/
public static MyToast makeText(Context context, int resId, int duration)
throws Resources.NotFoundException {
return makeText(context, context.getResources().getText(resId), duration);
}
/**
* Update the text in a Toast that was previously created using one of the makeText() methods.
* #param resId The new text for the Toast.
*/
public void setText(int resId) {
setText(mContext.getText(resId));
}
/**
* Update the text in a Toast that was previously created using one of the makeText() methods.
* #param s The new text for the Toast.
*/
public void setText(CharSequence s) {
if (mNextView == null) {
throw new RuntimeException("This Toast was not created with Toast.makeText()");
}
TextView tv = (TextView) mNextView.findViewById(com.android.internal.R.id.message);
if (tv == null) {
throw new RuntimeException("This Toast was not created with Toast.makeText()");
}
tv.setText(s);
}
// =======================================================================================
// All the gunk below is the interaction with the Notification Service, which handles
// the proper ordering of these system-wide.
// =======================================================================================
private static INotificationManager sService;
static private INotificationManager getService() {
if (sService != null) {
return sService;
}
sService = INotificationManager.Stub.asInterface(ServiceManager.getService("notification"));
return sService;
}
private class TN extends ITransientNotification.Stub {
final Runnable mShow = new Runnable() {
public void run() {
handleShow();
}
};
final Runnable mHide = new Runnable() {
public void run() {
handleHide();
}
};
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
WindowManagerImpl mWM;
TN() {
// XXX This should be changed to use a Dialog, with a Theme.Toast
// defined that sets up the layout params appropriately.
final WindowManager.LayoutParams params = mParams;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.format = PixelFormat.TRANSLUCENT;
params.windowAnimations = com.android.internal.R.style.Theme_Dialog_Alert;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.setTitle("Toast");
}
/**
* schedule handleShow into the right thread
*/
public void show() {
if (localLOGV) Log.v(TAG, "SHOW: " + this);
mHandler.post(mShow);
}
/**
* schedule handleHide into the right thread
*/
public void hide() {
System.out.println("hide called");
if (localLOGV) Log.v(TAG, "HIDE: " + this);
// mHandler.post(mHide);
}
public void myHide(){
System.out.println("my hide called");
if (localLOGV) Log.v(TAG, "HIDE: " + this);
mHandler.post(mHide);
}
public void handleShow() {
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
+ " mNextView=" + mNextView);
if (mView != mNextView) {
// remove the old view if necessary
handleHide();
mView = mNextView;
mWM = WindowManagerImpl.getDefault();
final int gravity = mGravity;
mParams.gravity = gravity;
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
mParams.horizontalWeight = 1.0f;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
mParams.verticalWeight = 1.0f;
}
mParams.x = mX;
mParams.y = mY;
mParams.verticalMargin = mVerticalMargin;
mParams.horizontalMargin = mHorizontalMargin;
if (mView.getParent() != null) {
if (localLOGV) Log.v(
TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
mWM.addView(mView, mParams);
}
}
public void handleHide() {
//System.out.println("handle hid ecalles");
if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
if (mView != null) {
// note: checking parent() just to make sure the view has
// been added... i have seen cases where we get here when
// the view isn't yet added, so let's try not to crash.
if (mView.getParent() != null) {
if (localLOGV) Log.v(
TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
mView = null;
}
}
}
}
// in broadcaste receiver ..........
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
toast = new MyToast(context);
toast.setGravity(Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0);
toast.setDuration(Toast.LENGTH_SHORT);
toast.setView(view);
toast.show();
}
else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
toast.cancel();
}
else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
toast.cancel();
}
}

Categories

Resources