Reputation: 11175
I am currently working on rewriting one of my iOS apps to release on Android. I'm making good progress but I am looking for some guidance regarding the best way to approach the list rows.
These are the cells/rows I am trying to recreate:
As you can see, I have a white background view with padding around each edge and rounded corners, so I guess for this I would need to embed everything within a view of some sort? The other part I am unsure about is how to create the coloured circle on the right. Would this be another view with rounded corners and a coloured background? I haven't managed to figure out how to get this to the right of the two textViews that I currently have. So if anyone could give a code example then that would be great.
This is my current XML:
<ImageView
android:layout_width="78dp"
android:layout_height="78dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:scaleType="centerCrop"
android:adjustViewBounds="false"
android:id="@+id/attractionImageView"
android:contentDescription="Attraction Image"
android:background="@color/colorPrimary" />
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:background="@drawable/fast_pass"
android:id="@+id/fastPassImageView" />
<LinearLayout android:orientation="vertical" android:layout_height="match_parent" android:layout_width="fill_parent" android:layout_toEndOf="@+id/attractionImageView" android:layout_toRightOf="@+id/attractionImageView">
<TextView
android:layout_width="match_parent"
android:layout_height="49dp"
android:id="@+id/attractionNameTextView"
android:text="Attraction Name"
android:layout_marginLeft="5dp"/>
<LinearLayout android:orientation="horizontal" android:layout_height="match_parent" android:layout_width="fill_parent" android:layout_toEndOf="@+id/attractionImageView" android:layout_toRightOf="@+id/attractionImageView">
<ImageView
android:layout_width="13dp"
android:layout_height="13dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:id="@+id/updatedImageView"
android:background="@drawable/updated"
android:layout_gravity="center_vertical"/>
<TextView
android:layout_width="match_parent"
android:layout_height="29dp"
android:id="@+id/updatedTextView"
android:text="Updated"
android:gravity="center_vertical"/>
</LinearLayout>
</LinearLayout>
This seems to work well for everything I've got so far, but I'm not sure where to go from here. This is how it looks:
Any suggestions?
Upvotes: 0
Views: 1792
Reputation: 43342
As an alternate solution, I just got something working with CardViews and using Picasso with a CircleTransformation for the circle.
In this simple example, I used a RecyclerView of CardViews.
First, here is the CircleTransformation class that is used by Picasso:
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import com.squareup.picasso.Transformation;
public class CircleTransform implements Transformation {
@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
Canvas canvas = new Canvas(bitmap);
BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);
paint.setShader(shader);
float r = size/2f;
canvas.drawCircle(r, r, r-1, paint);
Paint paintBorder = new Paint();
paintBorder.setStyle(Style.STROKE);
paintBorder.setColor(Color.argb(84,0,0,0));
paintBorder.setAntiAlias(true);
paintBorder.setStrokeWidth(1);
canvas.drawCircle(r, r, r-1, paintBorder);
squaredBitmap.recycle();
return bitmap;
}
@Override
public String key() {
return "circle";
}
}
Here is the Fragment:
public class BlankFragment extends Fragment {
public BlankFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_blank, container, false);
RecyclerView rv = (RecyclerView) rootView.findViewById(R.id.rv_recycler_view);
rv.setHasFixedSize(true);
MyAdapter adapter = new MyAdapter(new String[]{"testone", "testtwo", "testthree", "testfour"}, getActivity());
rv.setAdapter(adapter);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
rv.setLayoutManager(llm);
return rootView;
}
}
fragment_blank.xml:
<?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.support.v7.widget.RecyclerView
android:id="@+id/rv_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
The adapter, which includes the defaultCircleWithText() method for drawing the circle and text. Here I'm just using one color for the circles, but you can extend this to set the correct circle color for each row:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private String[] mDataset;
Context mContext;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class MyViewHolder extends RecyclerView.ViewHolder {
public CardView mCardView;
public TextView mTextView;
public ImageView mImageView;
public MyViewHolder(View v) {
super(v);
mCardView = (CardView) v.findViewById(R.id.card_view);
mTextView = (TextView) v.findViewById(R.id.tv_text);
mImageView = (ImageView) v.findViewById(R.id.iv_image);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(String[] myDataset, Context context) {
mDataset = myDataset;
mContext = context;
}
// Create new views (invoked by the layout manager)
@Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_item, parent, false);
// set the view's size, margins, paddings and layout parameters
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.mTextView.setText(mDataset[position]);
Drawable drawable = new BitmapDrawable(mContext.getResources(), defaultCircleWithText("test"));
Picasso.with(mContext).load((String)null).fit().transform(new CircleTransform()).placeholder(drawable).into(holder.mImageView);
}
@Override
public int getItemCount() {
return mDataset.length;
}
public final static int BIG_IMAGE = 138;
public static Bitmap defaultCircleWithText(String text) {
int size = BIG_IMAGE;
Bitmap image = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(image);
int alpha = 165;
//hard-coded circle color:
int color = Color.argb(alpha,253,70,45);
Paint p_circle = new Paint();
p_circle.setAntiAlias(true);
p_circle.setColor(color);
c.drawCircle(size/2f, size/2f, size/2f-1, p_circle);
Paint p_text = new Paint();
p_text.setAntiAlias(true);
p_text.setColor(Color.WHITE);
p_text.setTextSize(58);
RectF bounds = new RectF(0, 0, c.getWidth(), c.getHeight());
// measure text width
bounds.right = p_text.measureText(text, 0, text.length());
// measure text height
bounds.bottom = p_text.descent() - p_text.ascent();
bounds.left += (c.getWidth() - bounds.right) / 2.0f;
bounds.top += (c.getHeight() - bounds.bottom) / 2.0f;
c.drawText(text, bounds.left, bounds.top - p_text.ascent(), p_text);
return image;
}
}
card_item.xml:
<?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="78dp" >
<android.support.v7.widget.CardView
android:id="@+id/card_view"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
card_view:cardCornerRadius="4dp"
android:layout_width="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/tv_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="test" >
</TextView>
<ImageView
android:id="@+id/iv_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
Result:
Upvotes: 0
Reputation: 166
I suppose that you're using custom views for your listview's items, if so, I would set the background of the custom view to something like this:
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="@color/white" />
<stroke android:width="4dp" android:color="@color/beige" /> //If you want a stroke
<corners
android:topLeftRadius="20dp"
android:topRightRadius="20dp"
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
Upvotes: 1
Reputation: 93728
For the colored circle- I'd suggest just a text view set to the proper size with a circle drawable set as the background of the view. Should get what you want.
For the background- I'd just stick the entire row in either a linear or relative layout, then set a RoundedBitmapDrawable as the background of the layout. That will give you the rounded background effect. If necessary add some margin to the top and bottom of each view to increase the gap between items.
Upvotes: 1