I'm working on Android app which main purpose is to display CNN breaking news styled bar on the bottom and some pictures. I created two custom views, one for displaying photos and the second one for displaying bar. It displays one picture at a time for specified amount of time and swaps current picture with next one from the queue.
To animate text in bottom bar I used canvas, onDraw() and handler.postDelayed. This solution gives poor result. Text movement is not smooth especially when it comes to swap image.
What should I use instead of canvas? Is there any OpenGL-based lib which could make this task relatively painless? I tried to use AndEngine, but its lack of documentation and problems with threads discouraged me to working with it anymore.
public class Infobar extends View {
private List<Message> messages;
private Handler handler;
private Paint boxPaint;
private Paint defaultTextPaint;
private Paint importantTextPaint;
private long offset = 0;
private long maxOffset = 1000;
private int textWidth = 1000;
private int textHeight = 50;
private int measuredWidth;
private int measuredHeight;
private Runnable animateRunnable = new Runnable() {
public void run() {
animateMessage();
}
};
long startTime = new Date().getTime();
private int backgroundCol = Color.parseColor("#ffff00");
private int textColor = Color.parseColor("#000000");
private static final int FRAME_DELAY = 10;
private static final int FRAME_SHIFT = 3;
private static final int EMPTY_SPACE = 2;
private static final String SEPARATOR = " ✩ ";
private static final int TEXT_SIZE = 35;
public Infobar(Context context, AttributeSet attrs) {
super(context, attrs);
handler = new Handler();
messages = new ArrayList<Message>();
boxPaint = new Paint();
defaultTextPaint = new Paint();
defaultTextPaint.setColor(getResources().getColor(R.color.info_bar_default_text_color));
importantTextPaint = new Paint();
importantTextPaint.setColor(getResources().getColor(R.color.info_bar_important_text_color));
handler.postDelayed(animateRunnable, FRAME_DELAY);
}
public void setMessagesList(List<Message> list) {
messages = list;
}
public void setBackgroundColor(String color) {
backgroundCol = Color.parseColor(color);
}
public void setTextColor(String color) {
textColor = Color.parseColor(color);
}
public List<Message> getMessagesList() {
return messages;
}
private String getMessagesString() {
StringBuilder builder = new StringBuilder();
for(Message message : messages) {
builder.append(message.content);
if(messages.indexOf(message) != (messages.size() - 1)) {
builder.append(SEPARATOR);
}
}
return builder.toString();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measuredWidth = getMeasuredWidth();
measuredHeight = getMeasuredHeight();
}
#Override
protected void onDraw(Canvas canvas) {
drawBackground(canvas, false);
drawMessage(canvas, getMessagesString());
super.onDraw(canvas);
}
private void drawBackground(Canvas canvas, boolean important) {
boxPaint.setColor(backgroundCol) ;
canvas.drawRect(0, 0, measuredWidth, measuredHeight, boxPaint);
}
private void drawMessage(Canvas canvas, String message) {
defaultTextPaint.setTextSize(TEXT_SIZE);
Rect bounds = new Rect();
defaultTextPaint.getTextBounds(message, 0, message.length(), bounds);
defaultTextPaint.setColor(textColor);
textWidth = bounds.width();
textHeight = bounds.height();
int positionX = measuredWidth - (int)offset;
int positionY = measuredHeight - textHeight/2;
if(offset > (measuredWidth + textWidth)) {
offset = 0;
positionX = measuredWidth;
}
canvas.drawText(message, positionX, positionY, defaultTextPaint);
}
private void animateMessage() {
offset += FRAME_SHIFT;
//offset = Math.round((new Date().getTime() - startTime) * 0.2) % (measuredWidth + textWidth);
invalidate();
handler.removeCallbacks(animateRunnable);
handler.postDelayed(animateRunnable, FRAME_DELAY);
}
}
Unless there is a specific reason, you can use the built-in marquee function of TextView:
<LinearLayout>
<TextView
android:id="#+id/myText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="1"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:text="Your long text goes here. You can also change it programmatically" />
</LinearLayout>
Then in the activity code:
TextView myText=(TextView) findViewById(R.id.myText);
myText.setSelected(true); //needs this to work
Related
I have custom view which draws bitmaps on canvas. I want to improve my code so the memory chart in profiler looks smooth. I want to know why there are such leaps and GC removing objects every few second. It's worth mentioning that if I remove characterCreator.draw(canvas); from draw() method then the chart is smooth. Here is how my chart looks like now:
And now the important code:
CharacterCreatorView.java
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
if(characterCreator != null)
characterCreator.draw(canvas);
invalidate();
}
CharacterCreator.java
private static final int ROW_BOTTOM_TO_TOP = 8;
private static final int ROW_RIGHT_TO_LEFT = 9;
private static final int ROW_TOP_TO_BOTTOM = 10;
private static final int ROW_LEFT_TO_RIGHT = 11;
private static final int COL_COUNT = 13;
private static final int ROW_COUNT = 21;
private final Bitmap[] leftToRights;
private final Bitmap[] rightToLefts;
private final Bitmap[] topToBottoms;
private final Bitmap[] bottomToTops;
public CharacterCreator(Bitmap baseSprite) {
this.image = baseSprite;
this.widthAllCols = image.getWidth();
this.heightAllRows = image.getHeight();
this.widthOneFrame = this.widthAllCols / 13;
this.heightOneFrame = this.heightAllRows / ROW_COUNT;
this.topToBottoms = new Bitmap[COL_COUNT];
this.rightToLefts = new Bitmap[COL_COUNT];
this.leftToRights = new Bitmap[COL_COUNT];
this.bottomToTops = new Bitmap[COL_COUNT];
imageResized = Bitmap.createScaledBitmap(getMoveBitmaps()[0], 300, 300, false);
}
(...)
public void draw(Canvas canvas) {
imageResized = Bitmap.createScaledBitmap(getCurrentMoveBitmap(), 300, 300, false);
// canvas.drawBitmap(imageResized, 0, 0, null);
}
public Bitmap getCurrentMoveBitmap() {
Bitmap[] bitmaps = this.getMoveBitmaps();
return bitmaps[this.colUsing];
}
public Bitmap[] getMoveBitmaps() {
switch (rowUsing) {
case ROW_BOTTOM_TO_TOP:
return this.bottomToTops;
case ROW_RIGHT_TO_LEFT:
return this.rightToLefts;
case ROW_TOP_TO_BOTTOM:
return this.topToBottoms;
case ROW_LEFT_TO_RIGHT:
return this.leftToRights;
default:
return null;
}
}
My code does not work correctly. SurfaceView shows a black screen instead of Bitmaps. I make a game loop that doesn't depend on CPU, like Fix Your Timestep!, but I can't get it to work.
public class DrawView extends SurfaceView implements SurfaceHolder.Callback {
private DrawThreat drawThread;
public Background background;
private int height;
private int width;
public DrawView(Context context) {
super(context);
getHolder().addCallback(this);
drawThread = new DrawThreat(getHolder(), this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Rect surface = getHolder().getSurfaceFrame();
this.width = surface.width();
this.height = surface.height();
Bitmap back= BitmapFactory.decodeResource(App.getContext().getResources(), R.drawable.fon);
back = Bitmap.createScaledBitmap(back, width, height, false);
background = new Background(back, back, 0, 0, 0, -height);
drawThread = new DrawThreat(getHolder(), this);
drawThread.start();
}
public class DrawThreat extends Thread {
private final DrawView drawView;
private SurfaceHolder surfaceHolder;
private boolean running=true;
private static final int UPDATES_PER_SECOND = 25;
private static final int UPDATE_INTERVAL = 1000 / UPDATES_PER_SECOND * 1000000;
private static final int MAX_FRAMESKIP = 5;
private long nextUpdate = System.nanoTime();
public DrawThreat(SurfaceHolder surfaceHolder, DrawView drawView){
super();
this.surfaceHolder = surfaceHolder;
this.drawView = drawView;
}
I tried to implement a game loop, but only a black screen is displayed
#Override
public void run(){
while (running){
Canvas canvas = surfaceHolder.lockCanvas();
int skippedFrames = 0;
while (System.nanoTime() > this.nextUpdate && skippedFrames < MAX_FRAMESKIP) {
long delta = UPDATE_INTERVAL;
this.drawView.update(delta);
this.nextUpdate += UPDATE_INTERVAL;
skippedFrames++;
}
double interpolation = (System.nanoTime() + UPDATE_INTERVAL - this.nextUpdate) / (double) UPDATE_INTERVAL;
this.drawView.draw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
Please point out the errors and tell me the right way to implement the idea.
I have a custom view, that is sometimes being drawn and sometimes not .. this is reproduce-able across multiple phone.
Don't know why this is happening .. setDimensions() is being called during the onMeasure call of a GalleryGridElement (relative layout) which I use as gallery elements in my recyclerview.
One example would be .. going into the recycler view gallery activity, the circular progress view is there .. when you leave the activity and come back .. onResume creates a new adapter and gives it to the recycler view .. however the circular progress views don't show this time:
public class CircularProgressView extends View {
private Paint mIndicatorColour;
private RectF mIndicatorRect;
private Paint mBackCircleColour;
private static final float START_ANGLE = -90;
private volatile float mStopAngle = 0;
private float mOutterCircleStrokeWidth = 20;
private float mInnerCircleStrokeWidth = 16;
private float mViewWidth = 0, mViewHeight = 0;
private volatile int mCurrentProgress = 0;
private ExecutorService mExecutorService;
public CircularProgressView(Context context) {
super(context);
setUp();
}
public CircularProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
setUp();
}
public CircularProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setUp();
}
private void setUp(){
mIndicatorRect = new RectF(0,0,300,300);
mIndicatorColour = new Paint();
mIndicatorColour.setColor(Color.parseColor("#D62F85"));
mIndicatorColour.setStyle(Paint.Style.STROKE);
mIndicatorColour.setStrokeWidth(mInnerCircleStrokeWidth);
mIndicatorColour.setAntiAlias(true);
mIndicatorColour.setDither(true);
mIndicatorColour.setStrokeJoin(Paint.Join.ROUND);
mIndicatorColour.setStrokeCap(Paint.Cap.ROUND);
mBackCircleColour = new Paint();
mBackCircleColour.setColor(Color.WHITE);
mBackCircleColour.setStyle(Paint.Style.STROKE);
mBackCircleColour.setStrokeWidth(mOutterCircleStrokeWidth);
mBackCircleColour.setAntiAlias(true);
mBackCircleColour.setDither(true);
mBackCircleColour.setStrokeJoin(Paint.Join.ROUND);
mBackCircleColour.setStrokeCap(Paint.Cap.ROUND);
mExecutorService = Executors.newSingleThreadExecutor();
}
public void setDimensions(float width, int scaleCircleThicknessValue){
mViewHeight = width;
mViewWidth = width;
mIndicatorRect.left = mIndicatorRect.top = mOutterCircleStrokeWidth;
mIndicatorRect.right = mIndicatorRect.bottom = width - mOutterCircleStrokeWidth;
mIndicatorColour.setStrokeWidth(mInnerCircleStrokeWidth);
mBackCircleColour.setStrokeWidth(mOutterCircleStrokeWidth);
mInnerCircleStrokeWidth = (0.1f * scaleCircleThicknessValue) * width;
mOutterCircleStrokeWidth = mInnerCircleStrokeWidth + 5;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int desiredWidth = Math.round(mViewWidth);
int desiredHeight = Math.round(mViewHeight);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
} else {
//Be whatever you want
width = desiredWidth;
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//Set values
setMeasuredDimension(width, height);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(mIndicatorRect, 0, 360, false, mBackCircleColour);
canvas.drawArc(mIndicatorRect, START_ANGLE, mStopAngle, false, mIndicatorColour);
}
public synchronized void setProgress(final int progress) {
if ((mCurrentProgress != progress) && (progress > 0)) {
mCurrentProgress = progress;
mExecutorService.submit(new Runnable() {
#Override
public void run() {
final float currentAngle = mStopAngle;
float newAngle = (360f * ((float) progress / 100f));
float step = (Math.round(newAngle) - Math.round(currentAngle)) <= 1 ? 1 : (newAngle - currentAngle)/5f;
if (step < 0.01) {
newAngle = 359;
}
for (float i = currentAngle; i < newAngle; i += step) {
try {
mStopAngle = i;
postInvalidate();
Thread.sleep(1000 / 60);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
}
public float getProgress(){
return (360f-mStopAngle) < 1f ? 1 : mStopAngle / 360f;
}
}
Just following up on this incase someone runs into this issue:
Since I am using a custom view inside a custom view with the recycler view.
When I bind the view-holder to model, I make sure to completely re-render the view ... ie :
mCircularProgressView.setVisibility(VISIBLE);
mCircularProgressView.setDimensions(getWidth() * 0.82f, 1);
mCircularProgressView.requestLayout();
mCircularProgressView.postInvalidate();
This makes sure the view is drawn no matter what.
i have an issue with inserting custom views into my relative layout that takes only a part of the screen. When the activity loads it should populate views with specific width and height at x,y position that i get from my server, then when i click insert mode and click on the relative layout it should draw the view where i clicked as well...The problem is, sometimes it draws rectangle(should be square), sometimes just a line, sometimes nothing. It behaves differently if i change my width and height.
Custom view :
public class TableView extends View {
private static final String TAG = "TableView";
private int numberOfSeats;
private int tableId;
private int positionX;
private int positionY;
private int objectWidth;
private int objectHeight;
private boolean isTaken;
private String tableKind;
private Rect rectangle;
private Paint paint;
/* public TableView(Context context, AttributeSet attrs) {
super(context, attrs);
}*/
public TableView(Context context,int numberOfSeats,int tableId,int positionX,int positionY,int width,int height
,boolean isTaken, String tableKind) {
super(context);
this.numberOfSeats = numberOfSeats;
this.tableId = tableId;
this.positionX = positionX;
this.positionY = positionY;
this.objectWidth = width;
this.objectHeight = height;
this.isTaken = isTaken;
this.tableId = tableId;
this.tableKind = tableKind;
//defining shape
rectangle = new Rect(positionX,positionY,width,height);
//defining shape color
paint = new Paint();
paint.setColor(Color.GRAY);
Log.i(TAG, "TableView: tableId: "+tableId+" isTaken: "+isTaken);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = objectWidth;
int desiredHeight = objectHeight;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
} else {
//Be whatever you want
width = desiredWidth;
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//canvas.drawColor(Color.BLUE);
canvas.drawRect(rectangle, paint);
}
public int getNumberOfSeats() {
return numberOfSeats;
}
public int getTableId() {
return tableId;
}
public int getPositionX() {
return positionX;
}
public int getPositionY() {
return positionY;
}
public int getObjectWidth() {
return objectWidth;
}
public int getObjectHeight() {
return objectHeight;
}
public boolean isTaken() {
return isTaken;
}
public String getTableKind() {
return tableKind;
}
}
Main activity:
public class MainActivity extends AppCompatActivity {
int numberOfSeats = 1;
int tableId = 0;
int positionX = 100;
int positionY = 208;
boolean isTaken = true;
String tableKind = "table";
int objectWidth =200;
int objectHeight=200;
TextView topTable;
RelativeLayout floorPlan ;
Button saveBtn ;
private boolean insertTableCheck = false;
private static final String TAG = "MainActivity";
private int idTest = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
topTable =(TextView) findViewById(R.id.tableView);
floorPlan = (RelativeLayout) findViewById(R.id.floor_plan);
saveBtn = (Button) findViewById(R.id.saveBtn);
for (int i = 0;i<15;i++) {
TableView tv = new TableView(MainActivity.this, numberOfSeats, tableId, positionX, positionY, objectWidth, objectHeight
, isTaken, tableKind);
tv.setTag(i);
positionX +=25;
positionY +=34;
//tv.setY(positionY);
//tv.setX(positionX);
floorPlan.addView(tv);
}
floorPlan.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (insertTableCheck) {
saveBtn.setVisibility(View.VISIBLE);
int x = (int)motionEvent.getX()-objectWidth/2;
int y =(int) motionEvent.getY()-objectHeight/2;
Log.i(TAG, "insertTable: insertingTable on: " + x + " " + y);
TableView tav = new TableView(MainActivity.this,numberOfSeats,tableId,x,
y,objectWidth,objectHeight,isTaken,tableKind);
tav.setX(x);
tav.setY(y);
floorPlan.addView(tav);
/*TextView tableForInsert = new TextView(MainActivity.this);
tableForInsert.setBackgroundColor(Color.BLACK);
tableForInsert.setWidth(objectWidth);
tableForInsert.setHeight(objectHeight);
tableForInsert.setX(x);
tableForInsert.setY(y);
floorPlan.addView(tableForInsert);*/
insertTableCheck = false;
} else {
Log.i(TAG, "onTouch: just clicked on layout");
}
return true;
}
});
}
Note that for loop and the data above is just for testing! Any help would be much appreciated. Thanks
So Google includes the SlidingTabStrip as an open source library in the Android Studio sample collection:
class SlidingTabStrip extends LinearLayout {
private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 0;
private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 3;
private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
private final int mBottomBorderThickness;
private final Paint mBottomBorderPaint;
private final int mSelectedIndicatorThickness;
private final Paint mSelectedIndicatorPaint;
private final int mDefaultBottomBorderColor;
private int mSelectedPosition;
private float mSelectionOffset;
private SlidingTabLayout.TabColorizer mCustomTabColorizer;
private final SimpleTabColorizer mDefaultTabColorizer;
SlidingTabStrip(Context context) {
this(context, null);
}
SlidingTabStrip(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
final float density = getResources().getDisplayMetrics().density;
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true);
final int themeForegroundColor = outValue.data;
mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor,
DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
mDefaultTabColorizer = new SimpleTabColorizer();
mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
mBottomBorderPaint = new Paint();
mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
mSelectedIndicatorPaint = new Paint();
}
void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
mCustomTabColorizer = customTabColorizer;
invalidate();
}
void setSelectedIndicatorColors(int... colors) {
// Make sure that the custom colorizer is removed
mCustomTabColorizer = null;
mDefaultTabColorizer.setIndicatorColors(colors);
invalidate();
}
void onViewPagerPageChanged(int position, float positionOffset) {
mSelectedPosition = position;
mSelectionOffset = positionOffset;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
final int height = getHeight();
final int childCount = getChildCount();
final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
? mCustomTabColorizer
: mDefaultTabColorizer;
// Thick colored underline below the current selection
if (childCount > 0) {
View selectedTitle = getChildAt(mSelectedPosition);
int left = selectedTitle.getLeft();
int right = selectedTitle.getRight();
int color = tabColorizer.getIndicatorColor(mSelectedPosition);
if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
if (color != nextColor) {
color = blendColors(nextColor, color, mSelectionOffset);
}
// Draw the selection partway between the tabs
View nextTitle = getChildAt(mSelectedPosition + 1);
left = (int) (mSelectionOffset * nextTitle.getLeft() +
(1.0f - mSelectionOffset) * left);
right = (int) (mSelectionOffset * nextTitle.getRight() +
(1.0f - mSelectionOffset) * right);
}
mSelectedIndicatorPaint.setColor(color);
canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
height, mSelectedIndicatorPaint);
}
// Thin underline along the entire bottom edge
canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
}
/**
* Set the alpha value of the {#code color} to be the given {#code alpha} value.
*/
private static int setColorAlpha(int color, byte alpha) {
return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
}
/**
* Blend {#code color1} and {#code color2} using the given ratio.
*
* #param ratio of which to blend. 1.0 will return {#code color1}, 0.5 will give an even blend,
* 0.0 will return {#code color2}.
*/
private static int blendColors(int color1, int color2, float ratio) {
final float inverseRation = 1f - ratio;
float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
return Color.rgb((int) r, (int) g, (int) b);
}
private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
private int[] mIndicatorColors;
#Override
public final int getIndicatorColor(int position) {
return mIndicatorColors[position % mIndicatorColors.length];
}
void setIndicatorColors(int... colors) {
mIndicatorColors = colors;
}
}
}
With its layout file:
<com.example.SlidingTabLayout
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#000" />
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
I'm just unable to find out how I can completely customise the layout of this library such as border thickness, color or other properties which corresponds to these constants in the library such as SELECTED_INDICATOR_THICKNESS_DIPS and DEFAULT_SELECTED_INDICATOR_COLOR, if I assign a theme in the layout file I can only change common properties like background and foreground color but not border thickness or other properties only available for the SlidingTabStrip properties
Any idea how to change these without modifying the actual library code?
The library is located here:
https://developer.android.com/samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabStrip.html
You can change border thickness, color or other properties in the class itself:
class SlidingTabStrip extends LinearLayout {
private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
according to your requirement.
The color codes are in hex format.
For example(how to change the indicator color):
class SlidingTabStrip extends LinearLayout {
// change the strip color
private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
...
}
Check Sliding Tab Layout