I need to create a custom ListView item with a TextView and a colored rectangle.
To do it I have an ArrayAdapter:
public class JobQuickListAdapter extends ArrayAdapter<Job>{
private int resource;
public JobQuickListAdapter(Context context, int resource, List<Job> items) {
super(context, resource, items);
this.resource = resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
JobTagView jobView;
Job item = getItem(position);
String jobTitle = item.getTitle();
if (convertView == null) {
jobView = new JobTagView(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater vi = (LayoutInflater)getContext().getSystemService(inflater);
vi.inflate(resource, jobView, true);
} else {
jobView = (JobTagView) convertView;
}
jobView.setColor(Color.BLUE);
TextView jobTitleText = (TextView)jobView.findViewById(R.id.jobItemTitle);
jobTitleText.setText(jobTitle);
return jobView;
}
}
And my Custom View extending from LinearLayout:
public class JobTagView extends LinearLayout{
private Paint paintOrig;
private RectF originRect;
private boolean pathCreated;
private int color;
public JobTagView(Context context) {
super(context);
initJobTag();
}
public JobTagView(Context context, AttributeSet attrs) {
super(context, attrs);
initJobTag();
}
private void initJobTag(){
setWillNotDraw(false);
paintOrig = new Paint();
paintOrig.setStyle(Paint.Style.FILL);
pathCreated = false;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (!pathCreated){
float hR = h * 14 / 100;
float wR = w * 2 / 100;
originRect = new RectF(0, hR, wR, h - hR);
pathCreated = true;
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(originRect, paintOrig);
}
public int getColor() {
return color;
}
public void setColor(int color) {
paintOrig.setColor(color);
this.color = color;
this.invalidate();
}
}
And the layout:
<com.sinPlanB.jobSniffer.utils.JobTagView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.sinPlanB.jobSniffer.utils"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="5dp"
android:background="#drawable/job_tab_search">
<TextView android:id="#+id/jobItemTitle"
android:textIsSelectable="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:lines="2"
android:textSize="16sp"/>
</com.sinPlanB.jobSniffer.utils.JobTagView>
My problem comes when the colored rectangle is drawn, because the rectangle seems to be drawn several times and with a small displacement each time. A first black rectangle in a right position and a wrong blue rectangle (the one created after changing the rectangle color --> jobView.setColor(Color.BLUE)) totally displaced.
What am I doing wrong? Is there any tutorial about drawing Custom Items in a List View?
Related
I have Staggered Grid view in which each item contains an image and text. Have a look at this
Below code is item layout xml. DynamicHeightImageView is extended ImageView which is use to change height of image. Here I have tried to set
android:layout_width="fill_parent"
But I think it is not working.
<?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:background="#drawable/background_card"
android:orientation="vertical" >
<com.etsy.android.grid.util.DynamicHeightImageView
android:id="#+id/image"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#drawable/ic_launcher"
android:gravity="center" />
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
android:paddingLeft="8dp"
android:textColor="#ED430F"
android:paddingRight="8dp"
android:paddingTop="4dp"
android:textSize="15sp"
android:typeface="sans" />
<TextView
android:id="#+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:paddingBottom="8dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="4dp"
android:textSize="12sp"
android:textColor="#848484"
android:textStyle="italic" />
</LinearLayout>
DynamicHeightImageView class has following code
public class DynamicHeightImageView extends ImageView {
private double mHeightRatio;
public static float radius = 2.0f;
Path clipPath = new Path();
RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight());
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public DynamicHeightImageView(Context context, AttributeSet attrs) {
super(context, attrs);
if (Build.VERSION.SDK_INT < 18) {
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public DynamicHeightImageView(Context context) {
super(context);
if (Build.VERSION.SDK_INT < 18) {
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
public void setHeightRatio(double ratio) {
if (ratio != mHeightRatio) {
mHeightRatio = ratio;
requestLayout();
}
}
public double getHeightRatio() {
return mHeightRatio;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mHeightRatio > 0.0) {
// set the image views size
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = (int) (width * mHeightRatio);
setMeasuredDimension(width, height);
}
else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
#Override
protected void onDraw(Canvas canvas) {
rect.left = 0;
rect.top = 0;
rect.right = this.getWidth();
rect.bottom = this.getHeight();
clipPath.addRoundRect(rect, radius, radius, Path.Direction.CW);
canvas.clipPath(clipPath);
super.onDraw(canvas);
}
}
Below code is Grid View Adapter class. This actually binds data with GridView. Here I have also tried to set image view width to fill the parent but it is not working result is the same. Can anyone tel me where I am making mistake?
public class DataAdapter extends ArrayAdapter<Video> {
Activity activity;
int resource;
List<Video> datas;
public DataAdapter(Activity activity, int resource, List<Video> objects) {
super(activity, resource, objects);
this.activity = activity;
this.resource = resource;
this.datas = objects;
}
#SuppressWarnings("deprecation")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
final DealHolder holder;
if (row == null) {
LayoutInflater inflater = activity.getLayoutInflater();
row = inflater.inflate(resource, parent, false);
holder = new DealHolder();
holder.image = (DynamicHeightImageView)row.findViewById(R.id.image);
holder.title = (TextView)row.findViewById(R.id.title);
holder.date = (TextView)row.findViewById(R.id.description);
row.setTag(holder);
}
else {
holder = (DealHolder) row.getTag();
}
final Video data = datas.get(position);
Picasso.with(this.getContext())
.load(data.getImgURL())
.into(holder.image);
holder.image.setHeightRatio(getRandomHeight());
holder.image.getLayoutParams().width = LayoutParams.FILL_PARENT;
holder.image.requestLayout();
holder.title.setText(data.getTitle());
holder.date.setText(data.getUploadedDate().toGMTString().subSequence(0, 16));
return row;
}
static class DealHolder {
DynamicHeightImageView image;
TextView title;
TextView date;
}
private float getRandomHeight(){
ArrayList<Float> lista = new ArrayList<Float>();
lista.add((float) 0.5);
lista.add((float) 1.0);
lista.add((float) 0.75);
lista.add((float) 1.5);
Collections.shuffle(lista);
return lista.get(0);
}
}
In a project of mine, I have a custom HorizontalScrollView class that displays a line chart. It gets rid of all of the elements and then it adds a single ImageView as a child element. It works fine the first time, but if I were to change to other fragment and switch back to the fragment containing the line chart, the ImageView is not present, although the object is recreated exactly the same way as the first time. If I inspect it with the DDMS the ImageView is really not in the UI graph. Any ideas why?? I really need some help on that.
That is my code (from which I have omitted some irrelevant parts):
public class LineChartView extends HorizontalScrollView {
// Private Constants ...
// Private Fields...
public LineChartView(Context context) {
super(context);
init();
}
public LineChartView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LineChartView(Context context, float[] lineValues) {
super(context);
mLineValues = lineValues;
init();
}
public LineChartView(Context context, AttributeSet attrs, float[] lineValues) {
super(context, attrs);
mLineValues = lineValues;
init();
}
private void init() {
// Setting densityMultiplier
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
int pixelDensity = displayMetrics.densityDpi;
mDensityMultiplier = pixelDensity / DisplayMetrics.DENSITY_DEFAULT;
// Initalising Paints...
initChildElements();
}
private void initChildElements() {
removeAllViews();
// Adding the image view to the visual graph
mChartImage = new ImageView(getContext());
ViewGroup.LayoutParams chartLayoutParams = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mChartImage.setLayoutParams(chartLayoutParams);
addViewInLayout(mChartImage, 0, mChartImage.getLayoutParams(), true);
}
public void setLineValuesList(float[] lineValuesList) {
if (lineValuesList == null) {
mLineValues = new float[]{};
} else {
mLineValues = lineValuesList;
}
requestLayout();
invalidate();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mChartImage.setImageDrawable(renderLineChart(h, 1.5f)); // Calculate the bitmap with the same height
super.onSizeChanged(w, h, oldw, oldh);
}
private BitmapDrawable renderLineChart(int height, float scale) {
if (height <= 0 || mLineValues.length == 0)
return null;
// Drawing logic... (not really relevant)
return new BitmapDrawable(getContext().getResources(), resultBitmap);
}
private float calculateWidth(float distanceBetween) {
int strokeCount = mLineValues.length - 1;
return strokeCount * distanceBetween;
}
private float calculateDistanceToNextValue(float scale) {
return BASE_DISTANCE_BETWEEN_POINTS * mDensityMultiplier * scale;
}
}
I have a next problem, which happens in 2 cases:
First case.
1). I have some custom veiw which draw photos on it with different opacity. here is method MyView.onDraw:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.getClipBounds(clipRect);
int i1 = Math.min(testColors.length-1, (int)Math.floor(posX/PHOTO_DISTANCE));
int c1 = testColors[Math.max(0, i1)];
int i2 = Math.min(testColors.length-1, (int)Math.ceil(posX/PHOTO_DISTANCE));
int c2 = testColors[Math.max(0, i2)];
paint.setColor(c1);
float r = (255f/PHOTO_DISTANCE*posX)%255;
paint.setAlpha(255);
if(photoA != null){//bitmap != null
bitmapRect.set(0, 0, photoA.getWidth(), photoA.getHeight());
canvas.drawBitmap(photoA, bitmapRect, clipRect, paint);
}
paint.setAlpha((int)(r));
if(photoB != null){//bitmap != null
bitmapRect.set(0, 0, photoB.getWidth(), photoB.getHeight());
canvas.drawBitmap(photoB, bitmapRect, clipRect, paint);
}
}
testColors - array of colors(int);
photoA, photoB - bitmaps;
i1, i2 - image indexes;
c1, c2 - colors. they are not importatant.
I added this view to FrameView:
viewHolder.myFrame.addView(viewHolder.myView, 0);
And in this FrameView I have some clickable RelativeLayout's:
<com.app.custom.view.ClickableRelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/share_action_container"
app1:pressedStateColor="#color/app_pressed_default"
app1:unpressedStateColor="#color/color_white"
android:background="#color/transparent"
android:layout_centerHorizontal="true">
<RelativeLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/circle_background"
android:id="#+id/share_icon"
android:layout_centerHorizontal="true">
<ImageView
android:id="#+id/img_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:tag="icon"
android:src="#drawable/ic_share"/>
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_below="#id/share_icon"
android:text="Share"
android:layout_marginTop="3dp"
android:shadowColor="#color/text_shadow"
android:shadowDx="#integer/shadowDX"
android:shadowDy="#integer/shadowDY"
android:shadowRadius="#integer/shadowRadius"
android:background="#color/transparent"
android:layout_centerHorizontal="true"
android:textSize="#dimen/icon_text_size"
android:tag="text"
android:textColor="#android:color/white"
android:id="#+id/txt_share_action"/>
</com.app.custom.view.ClickableRelativeLayout>
Here is a Java code of ClickableRelativeLayout:
public class ClickableRelativeLayout extends RelativeLayout implements View.OnTouchListener {
private ViewHolder viewHolder;
private int pressedStateColor;
private int unpressedStateColor;
private final int DEFAULT_PRESSED_STATE_COLOR;
private final int DEFAULT_UNPRESSED_STATE_COLOR;
public ClickableRelativeLayout(Context context) {
super(context);
DEFAULT_PRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_pressed_default);
DEFAULT_UNPRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_blue_without_transparent);
setup();
initColors(context, null);
}
public ClickableRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
DEFAULT_PRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_pressed_default);
DEFAULT_UNPRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_blue_without_transparent);
setup();
initColors(context, attrs);
}
public ClickableRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
DEFAULT_PRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_pressed_default);
DEFAULT_UNPRESSED_STATE_COLOR = context.getResources().getColor(R.color.app_blue_without_transparent);
setup();
initColors(context, attrs);
}
private void setup(){
setOnTouchListener(this);
}
private void initColors(Context context, AttributeSet attrs){
if(attrs != null) {
TypedArray styledAttributes = context.obtainStyledAttributes(attrs, R.styleable.ClickableRelativeLayout);
pressedStateColor = styledAttributes.getColor(R.styleable.ClickableRelativeLayout_pressedStateColor,
DEFAULT_PRESSED_STATE_COLOR);
unpressedStateColor = styledAttributes.getColor(R.styleable.RowLayout_android_verticalSpacing,
DEFAULT_UNPRESSED_STATE_COLOR);
styledAttributes.recycle();
}else{
pressedStateColor = DEFAULT_PRESSED_STATE_COLOR;
unpressedStateColor = DEFAULT_UNPRESSED_STATE_COLOR;
}
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
viewHolder = new ViewHolder(
(TextView) findViewWithTag("text"),
(ImageView) findViewWithTag("icon")
);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
if (hasOnClickListeners()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
select();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
unSelect();
break;
}
}
}
return false;
}
private void select(){
if(isInitializedCorrect()){
final int color = pressedStateColor;
viewHolder.text.setTextColor(color);
ImageHelper.INSTANCE.applyColorFilterToImage(viewHolder.icon.getDrawable(), color);
}
}
private void unSelect(){
if(isInitializedCorrect()){
final int color = unpressedStateColor;
viewHolder.text.setTextColor(color);
viewHolder.icon.setColorFilter(color);
}
}
private boolean isInitializedCorrect(){
return viewHolder != null && viewHolder.icon != null && viewHolder.text != null;
}
private class ViewHolder{
ImageView icon;
TextView text;
public ViewHolder(TextView text, ImageView icon) {
this.text = text;
this.icon = icon;
}
}
}
And when I clicked on this layout, background of MyView shrinks, and sets to this ClickableRelativeLayout:
And Second case.
I have some text view on same frame, it is invisible by default, and when you scrolled 10 photos, I apply AlphaAnimation for this TextView and it draws slowly. Here is a code of alpha animation:
AlphaAnimation animation1 = new AlphaAnimation(0.0f, 1.0f);
animation1.setDuration(1300);
animation1.setFillAfter(true);
//here is my TextView
viewHolder.gotItView.setVisibility(View.VISIBLE);
viewHolder.gotItView.startAnimation(animation1);
And happens the same this. On background of this TextView appears content of MyView
I have a custom view (a class extending View) that I'd like to add as a header of List View. Here's the code snippet:
public class MyActivity extends RoboListActivity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View header = getLayoutInflater().inflate(R.layout.myactivity_apps_header, null);
getListView().addHeaderView(header);
...more code
}
But, I can't see anything. But, when I tried to add a non-custom view, it works. Am I missing something, please guide
Providing Complete Source Code
Custom View
public class SpaceCustomView extends View {
private Paint mPaint;
private Paint mTextPaint;
private final String mMessage = "Foo Bar";
private Rect mBounds;
public StorageSpaceCustomView(Context context) {
super(context);
initInput();
}
public StorageSpaceCustomView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
initInput();
}
public StorageSpaceCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initInput();
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
#Override
public void onDraw(android.graphics.Canvas canvas) {
canvas.drawRect(30, 30, 800, 80, mPaint);
canvas.drawText(mMessage, 30, 60, mTextPaint);
}
private void initInput() {
mBounds = new Rect();
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mTextPaint = new Paint();
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextAlign(Paint.Align.LEFT);
mTextPaint.setTextSize(20);
mTextPaint.getTextBounds(mMessage, 0, mMessage.length(), mBounds);
}
}
Header Layout XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.mycompany.app.view.custom.SpaceCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Activity Class
public class AppsActivity extends RoboListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//add header and footer views
View header = getLayoutInflater().inflate(R.layout.activity_apps_header, null);
getListView().addHeaderView(header);
View footer = getLayoutInflater().inflate(R.layout.activity_pps_footer, null);
getListView().addFooterView(footer);
List<AppInfo> applicationList = Mycatalog.getPromotions();
AppListAdapter adapter = new AppListAdapter(this, applicationList);
setListAdapter(adapter);
}
private class AppListAdapter extends ArrayAdapter<AppInfo> {
public AppListAdapter(Activity activity, List<AppInfo> apps) {
super(activity, android.R.layout.simple_list_item_1, apps);
}
#Override
public boolean isEmpty(){
return false;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// if we weren't given a view, inflate one
if (null == convertView) {
convertView = getLayoutInflater()
.inflate(R.layout.activity_uninstall_apps, null);
}
return convertView;
}
}
}
Conclusion: I can see the footer but not the header.
ListView shows headers and footers only when it's Adapter's isEmpty() returns false.
So try setting an adapter that does that...
I'm using scrollable static cards as an item selector (scroll through until you find one, then use the onItemSelected event to catch the click). It works, but it doesn't show the scroll bar on the bottom like it does for menu items and all standard system cards. Is there a way to enable it?
Here's the adapter code:
private class FooCardScrollAdapter extends CardScrollAdapter {
#Override
public int findIdPosition(Object id) {
return -1;
}
#Override
public int findItemPosition(Object item) {
return mCards.indexOf(item);
}
#Override
public int getCount() {
return mCards.size();
}
#Override
public Object getItem(int position) {
return mCards.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return mCards.get(position).toView();
}
}
As of XE16 this is now possible by just setting
mCardScrollView.setHorizontalScrollBarEnabled(true);
This is a known issue; there is no way to currently get the scroll indicator on a GDK CardScrollView. Please follow issue 256 on our issue tracker to be updated as the GDK evolves!
So I had the same problem as you. To solve it, I had to create my own scrollbar view. It's not as good as the built-in one for the Mirror API because it doesn't handle fling scrolling, but It's the best we can do until google releases their own.
First we create a custom view SimulatedScrollBar:
public class SimulatedScrollBar extends View {
private static final String TAG = SimulatedScrollBar.class.getSimpleName();
private static final boolean DEBUG = false;
private static final int WHITE_SCROLLBAR_COLOR = 0xfffefefe;
private int mScrollPosition;
private int mNumItems;
private Paint mPaint;
private float mInnerWidth;
private float mInnerHeight;
private int mOffsetX;
private int mWidth;
private int mHeight;
public SimulatedScrollBar(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.SimulatedScrollBar,
0, 0);
try {
mScrollPosition = a.getInteger(R.styleable.SimulatedScrollBar_scrollPosition, 0);
mNumItems = a.getInteger(R.styleable.SimulatedScrollBar_numItems, 0);
} finally {
a.recycle();
}
init();
}
private void init() {
mPaint = new Paint();
mPaint.setColor(WHITE_SCROLLBAR_COLOR);
mPaint.setStyle(Paint.Style.FILL);
}
public int getScrollPosition() {
return mScrollPosition;
}
public void setScrollPosition(int scrollPosition) {
mScrollPosition = scrollPosition;
invalidate();
requestLayout();
}
public int getNumItems() {
return mNumItems;
}
public void setNumItems(int numItems) {
mNumItems = numItems;
invalidate();
requestLayout();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
float xpad = (float)(getPaddingLeft() + getPaddingRight());
float ypad = (float)(getPaddingTop() + getPaddingBottom());
mInnerWidth = (float)w - xpad;
mInnerHeight = (float)h - ypad;
if (DEBUG) Log.i(TAG, "onSizeChanged() mInnerWidth=" + mInnerWidth + " mInnerHeight=" + mInnerHeight);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
float widthFraction = mNumItems > 0 ? 1.0f / (float)mNumItems : 0;
float scrollFraction = mNumItems > 0 ? (float)mScrollPosition / (float)mNumItems : 0;
mOffsetX = (int)(mInnerWidth * scrollFraction);
mWidth = (int)(mInnerWidth * widthFraction);
mHeight = (int)mInnerHeight;
Rect rect = new Rect(mOffsetX, 0, mOffsetX + mWidth, mHeight);
if (DEBUG) Log.i(TAG, "onDraw() mOffsetX=" + mOffsetX + " mWidth=" + mWidth + " mHeight=" + mHeight
+ " mScrollPosition=" + mScrollPosition + " mNumItems=" + mNumItems);
canvas.drawRect(rect, mPaint);
}
}
We need an attribute file `attrs.xml' to support configuring the view:
<resources>
<declare-styleable name="SimulatedScrollBar">
<attr name="scrollPosition" format="integer"/>
<attr name="numItems" format="integer"/>
</declare-styleable>
</resources>
Now we make a layout card_scroll_layout.xml which has the card scroll view and our scroll bar overlaying:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.chanapps.glass.chan"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black">
<com.google.android.glass.widget.CardScrollView
android:id="#+id/card_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ProgressBar
android:id="#+id/progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:indeterminate="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
/>
<com.chanapps.glass.chan.view.SimulatedScrollBar
android:id="#+id/simulated_scroll_bar"
android:layout_width="match_parent"
android:layout_height="10px"
android:layout_gravity="bottom"
custom:numItems="0"
custom:scrollPosition="0"
/>
</FrameLayout>
Here's what you put in your onCreate() to hook the pieces together:
mSimulatedScrollBar = (SimulatedScrollBar)rootLayout.findViewById(R.id.simulated_scroll_bar);
mSimulatedScrollBar.setScrollPosition(0);
mSimulatedScrollBar.setNumItems(mAdapter.getCount());
mCardScrollView = (CardScrollView)rootLayout.findViewById(R.id.card_scroll_view);
mCardScrollView.setAdapter(mAdapter);
mCardScrollView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (mSimulatedScrollBar != null)
mSimulatedScrollBar.setScrollPosition(position);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
mCardScrollView.activate();
Now when you slide through the list, you'll see the scroll bar at the bottom tracking the list position. If your adapter changes sizes, update the number of items and scroll position in the adapter or in an onLoadFinished() loader callback.