How can I start activity inside frame? - java

I'm trying to make a custom tabbar with scrolling tabbar items.
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#drawable/bg"
tools:context=".MainActivity" >
<LinearLayout
android:id="#+id/main_tabbar"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_below="#+id/main_rlTopbar" >
<FrameLayout
android:id="#+id/main_tabcontent"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<HorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:background="#drawable/bottombar" >
<LinearLayout
android:id="#+id/main_llTabs"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_gravity="center_vertical"
android:orientation="horizontal" >
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
</RelativeLayout>
mainactivity.java
...
m_scrollTabbar = new HScrollTabbar(this, R.id.main_tabcontent, R.id.main_llTabs);
m_scrollTabbar.addTab(null, 0, HomeActivity.class, true);
...
hscrolltabbar.java
public class HScrollTabbar {
private int m_nTabContentId = -1;
private int m_nScrollTabbarId = -1;
private Activity m_activityParent = null;
private ArrayList<ButtonTabbarItem> m_aryTabButton = new ArrayList<ButtonTabbarItem>();
private int m_nSelectedIndex = -1;
public void addTab(String labelId, int drawableId, Class<?> c) {
LinearLayout llTabs = (LinearLayout) m_activityParent.findViewById(m_nScrollTabbarId);
ButtonTabbarItem item = new ButtonTabbarItem(m_activityParent, c, m_aryTabButton.size());
llTabs.addView(item);
m_aryTabButton.add(item);
if (m_aryTabButton.size() == 1) {
setSelectedIndex(0);
}
item.setOnSelectTabListener(onSelectTabListener);
}
private OnSelectTabListener onSelectTabListener = new OnSelectTabListener() {
#Override
public void onSelect(int nSelectedIndex) {
setSelectedIndex(nSelectedIndex);
}
};
public void setSelectedIndex(int nIndex) {
if (m_nSelectedIndex == nIndex)
return;
ButtonTabbarItem item = null;
if (m_nSelectedIndex > -1) {
item = m_aryTabButton.get(m_nSelectedIndex);
item.setSelected(false);
}
m_nSelectedIndex = nIndex;
item = m_aryTabButton.get(m_nSelectedIndex);
item.setSelected(true);
FrameLayout frame = (FrameLayout) m_activityParent.findViewById(m_nTabContentId);
Intent intent = new Intent();
intent.setClass(frame.getContext(), item.getClassTarget());
frame.getContext().startActivity(intent);
}
public int getSelectedIndex() {
return m_nSelectedIndex;
}
}
buttontabbaritem.java
public class ButtonTabbarItem extends FrameLayout {
private static final int TAB_BTN_TAG = 100;
private Class<?> m_classTarget;
OnSelectTabListener m_listener = null;
public ButtonTabbarItem(Context context, Class<?> classTarget, int nIndex) {
super(context);
LinearLayout layout = new LinearLayout(context);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.hscroll_tabbar_item, layout);
addView(view);
Button btn = (Button) view.findViewById(R.id.hscroll_tabbar_item_btn);
btn.setOnClickListener(onClickTab);
btn.setTag(TAB_BTN_TAG + nIndex);
m_classTarget = classTarget;
}
public Class<?> getClassTarget() {
return m_classTarget;
}
public void setClassTarget(Class<?> classTarget) {
m_classTarget = classTarget;
}
public void setSelected(boolean bSelected) {
if (bSelected) {
} else {
}
}
private OnClickListener onClickTab = new OnClickListener() {
#Override
public void onClick(View v) {
if (m_listener != null)
m_listener.onSelect((Integer) v.getTag() - TAB_BTN_TAG);
}
};
public interface OnSelectTabListener {
public void onSelect(int nSelectedIndex);
}
public void setOnSelectTabListener(OnSelectTabListener listener) {
m_listener = listener;
}
}
FrameLayout frame = (FrameLayout) m_activityParent.findViewById(m_nTabContentId);
Intent intent = new Intent();
intent.setClass(frame.getContext(), item.getClassTarget());
frame.getContext().startActivity(intent);
I'm trying to start activity inside frame, but it's not work.
Please help me.

Related

Is it possible to create a recents screen like in android for the activities of my app

I am trying to make an Activity which will hold all the recents screen in my app not in the android device.
The idea it is to create the recents view like in android.
I do not have for the moment an idea how to do that. I have searched in the official site of android but didn't get what I want.
I have some activities which there is declared WebView and I want to take title, url and the view of that Url and to save to show at VisualHistory.
The design I am able to do I have achieved but I do not know how to show the recents screen or views.
The color of the background should based from url.
If someone don't understand something let me know.
Below you can find a photo which will show what I am trying to do, I have copied this photo from another app.
I have planned these steps to follow to achieve that.
In the Pojo.class and in db it is not defined the image which will be shown in the cardview because I do not know how to achieve that.
I want the background which for the moment in blue to be depended from the url color. Is it any way to get the color of the url ?
Create a POJO.class
Create a DB which will hold this data
Create an Adapter
Create a Fragment
I have a Log here which shows me the items.
[VisualHistoryItem{id=109, title='Wikipedia, the free encyclopedia', url='https://en.m.wikipedia.org/w/index.php?title=Main_Page'}, VisualHistoryItem{id=112, title='', url='https://mail.google.com/'}, VisualHistoryItem{id=113, title='Gmail – kostenloser Speicherplatz und E-Mails von Google', url='https://www.google.com/intl/de/gmail/about/#'}]
This saves a visual history item.
mVisualHistory.setUrl(url);
mVisualHistory.setTitle(view.getTitle());
Bitmap topass= getSnapshoot.takeScreenShot(BookmarkActivity.this);
try {
String filename = mVisualHistory.getId()+".png";
FileOutputStream stream = BookmarkActivity.this.openFileOutput(filename, Context.MODE_PRIVATE);
topass.compress(Bitmap.CompressFormat.PNG, 100, stream);
stream.close();
topass.recycle();
} catch (Exception e) {
e.printStackTrace();
}
mVisualRepository.insertNoteTask(mVisualHistory);
I have created an Activity code is below.
public class ActivityTabs extends AppCompatActivity implements View.OnClickListener {
private PopupMenu mPopupMenu;
private FrameLayout settings;
private FrameLayout frameLayout;
private LinearLayout linearLayout;
private ImageView incognito;
private TextView textOfHistory;
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabs);
findViewById(R.id.vgGoMain).setOnClickListener(this);
findViewById(R.id.vgAdd).setOnClickListener(this);
settings = findViewById(R.id.vgSettingsHis);
linearLayout = findViewById(R.id.layoutEmptyVisHistory);
settings.setOnClickListener(this);
textOfHistory = findViewById(R.id.tvEmptyHistory);
FragmentVisualHistoryVertical newFragment = new FragmentVisualHistoryVertical();
getSupportFragmentManager().beginTransaction().add(R.id.frameLayoutVisHistory, newFragment).commit();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frameLayoutVisHistory, newFragment)
.commit();
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.vgGoMain:
finish();
return;
case R.id.vgAdd:
Intent intent = new Intent(this, ActivitySearchEngine.class);
startActivity(intent);
finish();
return;
case R.id.vgSettingsHis:
showMenuSettings();
return;
default:
break;
}
}
public void showMenuSettings() {
mPopupMenu = new PopupMenu(this, settings);
final MenuInflater menuInflater = mPopupMenu.getMenuInflater();
menuInflater.inflate(R.menu.history_settings, mPopupMenu.getMenu());
mPopupMenu.show();
}
}
And this is the XML for this Activity.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/historyEmptyBack"
android:gravity="center_horizontal"
android:orientation="vertical">
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:id="#+id/frameLayoutVisHistory"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingBottom="#dimen/bottomPanelHeight"></FrameLayout>
<LinearLayout
android:id="#+id/layoutEmptyVisHistory"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="#+id/tvEmptyHistoryTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="#dimen/common_24dp"
android:gravity="center_horizontal"
android:lineSpacingExtra="3.0sp"
android:text="#string/VHVEmptyTite"
android:textColor="#color/historyEmptyTitle"
android:textSize="22.0sp" />
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="48.0dip"
android:layout_weight="1.0">
<LinearLayout
android:id="#+id/horizontalEmpty"
style="#style/LayoutEmptySmile"
android:layout_width="#dimen/visual_history_element_width"
android:layout_height="#dimen/visual_history_element_height"
android:orientation="vertical">
<ImageView
style="#style/EmptyHistorySmile"
android:src="#drawable/vh_smile_gray" />
<TextView
style="#style/EmptyHistoryText"
android:layout_marginTop="#dimen/common_16dp"
android:gravity="center_horizontal"
android:paddingLeft="#dimen/common_16dp"
android:paddingRight="#dimen/common_16dp"
android:text="#string/VHVEmptyDesc" />
</LinearLayout>
<LinearLayout
android:id="#+id/verticalEmpty"
style="#style/LayoutEmptySmile"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="#dimen/common_24dp"
android:layout_marginRight="#dimen/common_24dp"
android:orientation="horizontal"
android:paddingLeft="#dimen/common_16dp"
android:paddingTop="#dimen/common_16dp"
android:paddingRight="#dimen/common_16dp"
android:paddingBottom="#dimen/common_16dp">
<ImageView
style="#style/EmptyHistorySmile"
android:src="#drawable/vh_smile_gray" />
<TextView
style="#style/EmptyHistoryText"
android:layout_width="wrap_content"
android:gravity="left"
android:paddingLeft="#dimen/common_16dp"
android:text="#string/VHVEmptyDesc" />
</LinearLayout>
<LinearLayout
android:id="#+id/layoutIncognito"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingBottom="#dimen/bottomPanelHeight"
android:visibility="visible">
<LinearLayout
android:id="#+id/layoutEmptyDesc"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="#dimen/common_16dp"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="#+id/ivEmptyHistory"
android:layout_width="#dimen/history_private"
android:layout_height="#dimen/history_private"
android:src="#drawable/incognito_icon_history" />
<TextView
android:id="#+id/tvEmptyHistory"
style="#style/EmptyHistoryText"
android:layout_marginTop="#dimen/common_16dp"
android:gravity="center_horizontal"
android:paddingLeft="#dimen/common_16dp"
android:paddingRight="#dimen/common_16dp"
android:text="#string/SVSearchPrivateMode"
android:textColor="#color/historyTextColor"
android:textSize="#dimen/common_18sp" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#color/historyEmptyBack"
android:gravity="bottom"
android:orientation="vertical"
android:paddingLeft="2.0dip"
android:paddingRight="2.0dip">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout style="#style/VisHistoryMenuSideLayout">
<FrameLayout
android:id="#+id/vgGoMain"
style="#style/VisHistoryFrLayoutMenu"
android:paddingRight="14.0dip">
<TextView
style="#style/VisHistoryTvMenu"
android:text="#string/VHVHomeBarButtonItemTitle" />
</FrameLayout>
<View style="#style/VisHistoryEmptyView" />
</LinearLayout>
<FrameLayout
android:id="#+id/vgAdd"
style="#style/VisHistoryFrLayoutMenu">
<ImageView
style="#style/VisHistoryMenuIv"
android:scaleX="0.8"
android:scaleY="0.8"
android:src="#drawable/newtab_button" />
</FrameLayout>
<LinearLayout style="#style/VisHistoryMenuSideLayout">
<View style="#style/VisHistoryEmptyView" />
<FrameLayout
android:id="#+id/vgTrash"
style="#style/VisHistoryFrLayoutMenu">
<ImageView
style="#style/VisHistoryMenuIv"
android:scaleX="1.3"
android:scaleY="1.3"
android:src="#drawable/trash" />
</FrameLayout>
<View style="#style/VisHistoryEmptyView" />
<FrameLayout
android:id="#+id/vgSettingsHis"
style="#style/VisHistoryFrLayoutMenu"
android:paddingLeft="0.0dip"
android:paddingRight="0.0dip">
<android.support.v7.widget.AppCompatImageView
style="#style/VisHistoryMenuIv"
android:layout_gravity="right"
app:srcCompat="#drawable/ic_dots_vertical"
tools:ignore="VectorDrawableCompat" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>
This is another Fragment
Here will show of the list
public class FragmentVisualHistoryVertical extends FragmentVisualHistory implements VisualRecyclerAdapter.OnVisualHistoryItemListener {
public View paramView;
private VisualRecyclerAdapter mVisualHistoryRecyclerAdapter;
private RecyclerView mRecyclerView;
private VisualHistoryRepository getmNoteRepository;
private ArrayList<VisualHistoryItem> mVisualHistoryItems = new ArrayList<>();
#Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
paramView = inflater.inflate(R.layout.fragment_vis_history_vertical, container, false);
mRecyclerView = paramView.findViewById(R.id.rvWebHistory);
initRecyclerView();
getmNoteRepository = new VisualHistoryRepository(getActivity());
retrieveVisualHistory();
return paramView;
}
private void initRecyclerView(){
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(linearLayoutManager);
linearLayoutManager.setReverseLayout(true);
new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(mRecyclerView);
mVisualHistoryRecyclerAdapter = new VisualRecyclerAdapter(mVisualHistoryItems, this, mContext);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
linearLayoutManager.getOrientation());
mRecyclerView.addItemDecoration(dividerItemDecoration);
mRecyclerView.setAdapter(mVisualHistoryRecyclerAdapter);
}
private void retrieveVisualHistory() {
getmNoteRepository.retrieveVisualHistoryTask().observe(this, new Observer<List<VisualHistoryItem>>() {
#Override
public void onChanged(#Nullable List<VisualHistoryItem> item) {
if(mVisualHistoryItems.size() > 0){
mVisualHistoryItems.clear();
}
if(item != null){
mVisualHistoryItems.addAll(item);
}
mVisualHistoryRecyclerAdapter.notifyDataSetChanged();
}
});
}
#Override
public void onItemClicked(int position) {
}
private void deleteNote(VisualHistoryItem item) {
mVisualHistoryItems.remove(item);
mVisualHistoryRecyclerAdapter.notifyDataSetChanged();
getmNoteRepository.deleteVisualHistoryTask(item);
}
ItemTouchHelper.SimpleCallback itemTouchHelperCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
deleteNote(mVisualHistoryItems.get(viewHolder.getAdapterPosition()));
}
};
}
This is the XML.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:id="#+id/rvWebHistory" android:layout_width="match_parent" android:layout_height="match_parent"/>
This is the room db
#Database(entities = {VisualHistoryItem.class}, version = 1)
public abstract class VisualHistoryDB extends RoomDatabase {
private static final String DATABASE_NAME = "visualHistory_db";
private static VisualHistoryDB instance;
public static VisualHistoryDB getInstance(final Context context) {
if (instance == null) {
instance = Room.databaseBuilder(
context.getApplicationContext(),
VisualHistoryDB.class,
DATABASE_NAME
).build();
}
return instance;
}
public abstract VisualHistoryDao getVisualHistoryDao();
}
The room db Dao
#Dao
public interface VisualHistoryDao {
#Insert
long[] insertVisualHistory(VisualHistoryItem... visualHistoryItems);
#Query("SELECT * FROM visualHistory")
LiveData<List<VisualHistoryItem>> getVisualHistory();
#Delete
int delete(VisualHistoryItem... visualHistoryItems);
}
This is the pojo.class
#Entity(tableName = "visualHistory")
public class VisualHistoryItem implements Parcelable {
#PrimaryKey(autoGenerate = true)
private int id;
#ColumnInfo(name = "title")
private String title;
#ColumnInfo(name = "url")
private String url;
public VisualHistoryItem(int id, String title, String url) {
this.id = id;
this.title = title;
this.url = url;
}
#Ignore
public VisualHistoryItem() {
}
protected VisualHistoryItem(Parcel in) {
id = in.readInt();
title = in.readString();
url = in.readString();
}
public static final Creator<VisualHistoryItem> CREATOR = new Creator<VisualHistoryItem>() {
#Override
public VisualHistoryItem createFromParcel(Parcel in) {
return new VisualHistoryItem(in);
}
#Override
public VisualHistoryItem[] newArray(int size) {
return new VisualHistoryItem[size];
}
};
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
#Override
public String toString() {
return "VisualHistoryItem{" +
"id=" + id +
", title='" + title + '\'' +
", url='" + url + '\'' +
'}';
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(id);
parcel.writeString(title);
parcel.writeString(url);
}
}
And this is the Adapter.
public class VisualRecyclerAdapter extends RecyclerView.Adapter<VisualRecyclerAdapter.ViewHolder> {
private ArrayList<VisualHistoryItem> mVisualHistoryItem = new ArrayList<>();
private OnVisualHistoryItemListener mItemListener;
private final Context context;
public VisualRecyclerAdapter(ArrayList<VisualHistoryItem> mVisualHistoryItem, OnVisualHistoryItemListener mItemListener, Context context) {
this.context = context;
this.mVisualHistoryItem = mVisualHistoryItem;
this.mItemListener = mItemListener;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fragment_visual_history, viewGroup, false);
return new ViewHolder(view, mItemListener);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
Resources res = viewHolder.itemView.getContext().getResources();
viewHolder.visFragmentMain.setBackgroundColor(res.getColor(R.color.blue_text));
viewHolder.tvPageUrl.setText(mVisualHistoryItem.get(i).getUrl());
viewHolder.tvPageName.setText(mVisualHistoryItem.get(i).getTitle());
Bitmap bmp = null;
String filename = mVisualHistoryItem.get(i).getId()+".png";
try {
FileInputStream is = context.openFileInput(filename);
bmp = BitmapFactory.decodeStream(is);
is.close();
} catch (Exception e) {
e.printStackTrace();
}
if (bmp!=null) {
BitmapDrawable ob = new BitmapDrawable(context.getResources(), bmp);
viewHolder.ivVisualHistory.setBackground(ob);
}
}
#Override
public int getItemCount() {
return mVisualHistoryItem.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView ivVisualHistory;
OnVisualHistoryItemListener itemListener;
TextView tvPageName, tvPageUrl;
RelativeLayout visFragmentMain;
CardView cardView;
public ViewHolder(#NonNull View itemView, OnVisualHistoryItemListener mItemListener) {
super(itemView);
itemListener = mItemListener;
ivVisualHistory = itemView.findViewById(R.id.ivVisualHistory);
visFragmentMain = itemView.findViewById(R.id.visFragmentMain);
tvPageName = itemView.findViewById(R.id.tvPageName);
tvPageUrl = itemView.findViewById(R.id.tvPageUrl);
cardView = itemView.findViewById(R.id.cardView);
}
#Override
public void onClick(View v) {
itemListener.onItemClicked(getAdapterPosition());
}
}
public interface OnVisualHistoryItemListener {
void onItemClicked(int position);
}
}
This is what I am trying to achieve.
This is my actual view.
Well you can get the favicon of the website and use the Palette class of android explained here to get the prominent color of the url and if you want to get the snapshot you can save the snapshot and save instance data before launching another activity. To take snapshot you can use takesnapshot meathod after creating util class, code as follows:
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.view.View;
class Util {
static Bitmap takeScreenShot(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap b1 = view.getDrawingCache();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
//Find the screen dimensions to create bitmap in the same size.
int width = activity.getWindowManager().getDefaultDisplay().getWidth();
int height = activity.getWindowManager().getDefaultDisplay().getHeight();
Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height - statusBarHeight);
view.destroyDrawingCache();
return b;
}
}
in your activity use it to save it to png file as follows:
Bitmap topass=Util.takeScreenShot(this);
try {
//Write file
String filename = "bitmap.png";
FileOutputStream stream = this.openFileOutput(filename, Context.MODE_PRIVATE);
topass.compress(Bitmap.CompressFormat.PNG, 100, stream);
//Cleanup
stream.close();
topass.recycle();
} catch (Exception e) {
e.printStackTrace();
}
Instead of using name "bitmap.png" use your "id.png"(String.valueof(id)+".png") as you have put int "id" name in your db. You can save screenshot of every activity with its id and whenever you build the cardview of it, show the screenshot by the name of "id.png". To show screenshot, you can use
Bitmap bmp = null;
String filename = String.valueof(getId())+".png";
try {
FileInputStream is = this.openFileInput(filename);
bmp = BitmapFactory.decodeStream(is);
is.close();
} catch (Exception e) {
e.printStackTrace();
}
if(bmp!=null)
{
ConstraintLayout cl =findViewById(R.id.shopbk); //it can be your any view
BitmapDrawable ob = new BitmapDrawable(getResources(), bmp);
cl.setBackground(ob); /* you should use glide here to show bitmap drawable as your preview will be very small as compared to screenshot actual size*/
}
and as far as getting the color (you said the link is not working) is concerned you can get firstly the bitmap using
try {
URL url = new URL("http://..somepath url../favicon.ico");
Bitmap image = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch(IOException e) {
System.out.println(e);
}
and then use palette to extract the color using
Palette.generateAsync(image, new Palette.PaletteAsyncListener() {
public void onGenerated(Palette palette) {
// Do something with colors...
}
});
for this you will need to implement one dependancy
dependencies {
...
compile 'com.android.support:palette-v7:21.0.+'
}

Show empty view when data set is empty in recyclerview

I have a recyclerview which shows multiple cardviews with items. In the recyclerview, I have a popup menu to delete that current cardview.
When the dataset is empty I would like to show an empty view. Something with an image and text saying "empty" I have tried some online examples. No success.
My layout is a cardview(card_view_row.xml) is a simple view with a cardview that shows a few items.
Here is my recyclerview
public class AlarmRecyclerViewAdapter extends
RecyclerView.Adapter<AlarmRecyclerViewAdapter.DataObjectHolder> {
private ArrayList<Alarm> mDataset;
private static AlarmRecyclerViewAdapter.MyClickListener myClickListener;
private AlarmDataAccess dataAccess;
private Alarm alarm;
private int switchOn = 1;
private int switchOff = 0;
private static Context context;
private PopupMenu popupMenu;
public static class DataObjectHolder extends RecyclerView.ViewHolder
implements View
.OnClickListener {
TextView label;
TextView dateTime;
TextView label2;
TextView textViewLabel;
TextView gender;
TextView daysofweek;
Switch aSwitch;
ImageView trash;
public DataObjectHolder(View itemView) {
super(itemView);
dateTime = (TextView) itemView.findViewById(R.id.textView2);
label = (TextView) itemView.findViewById(R.id.textView);
label2 =(TextView) itemView.findViewById(R.id.textView3);
aSwitch = (Switch)itemView.findViewById(R.id.switchButton);
trash = (ImageView)itemView.findViewById(R.id.imageTrash);
gender = (TextView)itemView.findViewById(R.id.textViewGender);
daysofweek = (TextView)itemView.findViewById(R.id.textViewDays);
textViewLabel = (TextView)itemView.findViewById(R.id.textViewLabel);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
myClickListener.onItemClick(getAdapterPosition(), v);
}
}
public void setOnItemClickListener(AlarmRecyclerViewAdapter.MyClickListener myClickListener) {
this.myClickListener = myClickListener;
}
public AlarmRecyclerViewAdapter(ArrayList<Alarm> myDataset, Context context2) {
mDataset = myDataset;
context = context2;
}
#Override
public AlarmRecyclerViewAdapter.DataObjectHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view_row, parent, false);
AlarmRecyclerViewAdapter.DataObjectHolder dataObjectHolder = new AlarmRecyclerViewAdapter.DataObjectHolder(view);
return dataObjectHolder;
}
#Override
public void onBindViewHolder(final AlarmRecyclerViewAdapter.DataObjectHolder holder, final int position) {
boolean status = false;
int gender;
alarm = new Alarm();
dataAccess = new AlarmDataAccess(context);
dataAccess.open();
holder.label.setText(mDataset.get(position).getHourOfDay() + ":" + mDataset.get(position).getMinute() + " " + mDataset.get(position).getTimeSet());
holder.textViewLabel.setText(mDataset.get(position).getLabel());
gender = mDataset.get(position).getGender();
if(gender == 0){
holder.gender.setText("Male voice");
}else{
holder.gender.setText("Female voice");
}
holder.daysofweek.setText(mDataset.get(position).getDays());
holder.label2.setText("" + mDataset.get(position).getAffirmationName());
holder.trash.setImageResource(R.drawable.menu2);
if( mDataset.get(position).getStatus() == 0){
status = false;
}else {
status = true;
}
holder.aSwitch.setChecked(status);
holder.aSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.isPressed()) {
if (isChecked) {
mDataset.get(position).setStatus(switchOn);
} else {
mDataset.get(position).setStatus(switchOff);
}
alarm.setId(mDataset.get(position).getId());
alarm.setStatus(mDataset.get(position).getStatus());
dataAccess.updateStatus(alarm);
}
}
});
holder.trash.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popupMenu = new PopupMenu(AlarmRecyclerViewAdapter.context, v);
popupMenu.inflate(R.menu.popup_menu);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.edit:
long selectedAlarmId = mDataset.get(position).getId();
Intent intent = new Intent(AlarmRecyclerViewAdapter.context, EditAlarmActivity.class);
intent.putExtra("id", selectedAlarmId);
intent.putExtra("Edit", "FromEdit");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
AlarmRecyclerViewAdapter.context.startActivity(intent);
return true;
case R.id.delete:
long id = mDataset.get(position).getId();
mDataset.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mDataset.size());
dataAccess.deleteAlarm(id);
return true;
}
return false;
}
});
popupMenu.show();
}
});
}
public void deleteItem(int index) {
mDataset.remove(index);
notifyItemRemoved(index);
}
#Override
public int getItemCount() {
return mDataset.size();
}
}
My recyclerview is inside a fragment view
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/fragment_place">
<ImageButton
android:id="#+id/add_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="end|bottom"
android:tint="#color/icon"
android:elevation="12dp"
android:background="#drawable/oval_ripple"
tools:backgroundTint="#96ceb4"
android:src="#android:drawable/ic_input_add"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_marginStart="12dp"
android:layout_marginTop="14dp" />
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:layout_below="#+id/add_button"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp" />
</RelativeLayout>
Is there a way to detect if the data set is empty to show an empty view with text saying empty or something? I need this done inside recyclerview since I am deleting items inside there.
EDIT
I finally figured out how to do it. I am posting this incase anyone else has the same problem.
http://akbaribrahim.com/empty-view-for-androids-recyclerview/
For my personal use I use this trick :
I use two LinearLayout, one with my RecyclerView and another with a simple TextView saying "Empty". Both are in the same parent view.
<LinearLayout
android:id="#+id/linearContent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="invisible">
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="vertical" />
</LinearLayout>
<LinearLayout
android:id="#+id/linearEmpty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/textEmpty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="30dp"
android:text="#string/dialog_no_result"
android:textColor="#color/cardview_dark_background" />
</LinearLayout>
And when I update my list of item I call this method :
if (linearContent != null && linearEmpty != null) {
if (mListItems.isEmpty()) {
linearContent.setVisibility(View.GONE);
linearEmpty.setVisibility(View.VISIBLE);
textEmpty.setVisibility(View.VISIBLE);
} else {
linearContent.setVisibility(View.VISIBLE);
linearEmpty.setVisibility(View.GONE);
textEmpty.setVisibility(View.GONE);
}
}
Then I use the same layout, but just change the visibility of some objects.
Hope it help.

How to find apps that start with a specific alphabet? - Android Launcher

I'm making a launcher for android with a feature where the user selects an alphabet, then apps starting with that alphabet will be displayed.
I'm having a class that stores name, icon, etc of apps and can successfully display it using Gridiew. But I can't seem to figure out how to display only the selected apps that starts with the selected alphabet.
MainActivity/Dashboard.java
public class Dashboard extends Activity {
DrawerAdapter drawerAdapterObject;
GridView drawerGrid;
class Pac {
Drawable icon;
String name;
String label;
}
Pac[] pacs;
PackageManager pm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
drawerGrid = (GridView) findViewById(R.id.content);
pm = getPackageManager();
set_pacs();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
registerReceiver(new PacReciever(), filter);
}
public void set_pacs() {
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
mainIntent.hasExtra("facebok");
List<ResolveInfo> pacsList = pm.queryIntentActivities(mainIntent, 0);
pacs = new Pac[pacsList.size()];
for(int i = 0; i < pacsList.size(); i++) {
pacs[i] = new Pac();
pacs[i].icon = pacsList.get(i).loadIcon(pm);
pacs[i].name = pacsList.get(i).activityInfo.packageName;
pacs[i].label = pacsList.get(i).loadLabel(pm).toString();
}
new SortApps().exchage_sort(pacs);
drawerAdapterObject = new DrawerAdapter(this, pacs);
drawerGrid.setAdapter(drawerAdapterObject);
drawerGrid.setOnItemClickListener(new DrawerClickListner(this, pacs, pm));
}
public class PacReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
set_pacs();
}
}
public void test(){
Intent test = new Intent(this,MainActivity.class);
startActivity(test);
}
}
activity_dashboard.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_dashboard"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.zyconut.socio.Dashboard">
<SlidingDrawer
android:id="#+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:handle="#+id/handle"
android:content="#+id/content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<ImageView
android:id="#+id/handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#mipmap/ic_launcher"/>
<GridView
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimarytrans"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:verticalSpacing="50dp"
android:horizontalSpacing="50dp"/>
</SlidingDrawer>
</RelativeLayout>
DrawerAdapter.java
public class DrawerAdapter extends BaseAdapter {
Context mContext;
Dashboard.Pac[] pacsForAdapter;
public DrawerAdapter(Context c, Dashboard.Pac pacs[]) {
mContext = c;
pacsForAdapter = pacs;
}
#Override
public int getCount() {
return pacsForAdapter.length;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
static class ViewHolder {
TextView text;
ImageView icon;
}
#Override
public View getView(int pos, View convertView, ViewGroup viewGroup) {
ViewHolder viewHolder;
LayoutInflater li = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(convertView == null) {
convertView = li.inflate(R.layout.drawer_item, null);
viewHolder = new ViewHolder();
viewHolder.text = (TextView) convertView.findViewById(R.id.icon_text);
viewHolder.icon = (ImageView) convertView.findViewById(R.id.icon_image);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.icon.setImageDrawable(pacsForAdapter[pos].icon);
viewHolder.text.setText(pacsForAdapter[pos].label);
return convertView;
}
}
DrawerClickListner.java
public class DrawerClickListner implements OnItemClickListener {
Context mContext;
Dashboard.Pac[] pacsForAdapter;
PackageManager pmForListner;
public DrawerClickListner(Context c, Dashboard.Pac[] pacs, PackageManager pm) {
mContext = c;
pacsForAdapter = pacs;
pmForListner = pm;
}
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int pos, long l) {
Intent launchIntent = pmForListner.getLaunchIntentForPackage(pacsForAdapter[pos].name);
mContext.startActivity(launchIntent);
}
}
SortApps.java
public class SortApps {
public void exchage_sort(Dashboard.Pac[] pacs){
int i,j;
Dashboard.Pac temp;
for(i = 0; i < pacs.length; i++) {
for(j = i + 1; j < pacs.length; j++) {
if(pacs[i].label.compareToIgnoreCase(pacs[j].label) > 0) {
temp = pacs[i];
pacs[i] = pacs[j];
pacs[j] = temp;
}
}
}
}
}
drawer_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<ImageView
android:id="#+id/icon_image"
android:layout_width="65dp"
android:layout_height="65dp"
android:padding="3dp"/>
<TextView
android:id="#+id/icon_text"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:maxLines="2"
android:gravity="center_horizontal"/>
</LinearLayout>
This is my first post, please do forgive me for any mistakes.
I just need someone to point me to how i can display apps starting with 'A' only. Rest I may be able to figure it out.
Thanks in advance
You can get the list of installed applications using the following snippet.
List<String> installedApps = new ArrayList<String>();
List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);
for(int i=0;i<packs.size();i++) {
PackageInfo p = packs.get(i);
String appName = p.applicationInfo.loadLabel(getPackageManager()).toString();
installedApps.add(appName);
}
Then you can use this List to filter applications based on starting alphabet.

FrameLayout does not match_parent

I am using fragNav and bottombar plugin. I am trying to make a fullscreen fragment through a FrameLayout. By default, those plugins came with an actionBar which i delete in my theme with "Theme.AppCompat.Light.NoActionBar". But Once i did this there is still a white bar on top on my screen. When i look at hierarchyView it appears that my FrameLayout is not matching the parent but all my xml are setup with match_parent width and height..
MainActivity.java
public class MainActivity extends AppCompatActivity {
private BottomBar mBottomBar;
private FragNavController fragNavController;
private final int TAB_FIRST = FragNavController.TAB1;
private final int TAB_SECOND = FragNavController.TAB2;
private final int TAB_THIRD = FragNavController.TAB3;
private final int TAB_FOURTH = FragNavController.TAB4;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<Fragment> fragments = new ArrayList<>(4);
fragments.add(FirstFragment.newInstance(0));
fragments.add(SecondFragment.newInstance(0));
fragments.add(ThirdFragment.newInstance(0));
fragments.add(FourthFragment.newInstance(0));
fragNavController = new FragNavController(getSupportFragmentManager(), R.id.container, fragments);
//BottomBar menu
mBottomBar = BottomBar.attach(this, savedInstanceState);
mBottomBar.setItems(R.menu.bottombar_menu);
mBottomBar.setOnMenuTabClickListener(new OnMenuTabClickListener() {
#Override
public void onMenuTabSelected(#IdRes int menuItemId) {
//switch between tabs
switch (menuItemId) {
case R.id.bottomBarItemOne:
fragNavController.switchTab(TAB_FIRST);
break;
case R.id.bottomBarItemSecond:
fragNavController.switchTab(TAB_SECOND);
break;
case R.id.bottomBarItemThird:
fragNavController.switchTab(TAB_THIRD);
break;
case R.id.bottomBarItemFourth:
fragNavController.switchTab(TAB_FOURTH);
break;
}
}
#Override
public void onMenuTabReSelected(#IdRes int menuItemId) {
if (menuItemId == R.id.bottomBarItemOne) {
fragNavController.clearStack();
}
}
});
}
#Override
public void onBackPressed () {
if (fragNavController.getCurrentStack().size() > 1) {
fragNavController.pop();
} else {
super.onBackPressed();
}
}
#Override
protected void onSaveInstanceState (Bundle outState){
super.onSaveInstanceState(outState);
// Necessary to restore the BottomBar's state, otherwise we would
// lose the current tab on orientation change.
mBottomBar.onSaveInstanceState(outState);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="#+id/container"
android:background="#color/black">
</FrameLayout>
FirstFragment.java
public class FirstFragment extends Fragment {
public class SwipeDeckAdapter extends BaseAdapter {
private List<String> data;
private Context context;
public SwipeDeckAdapter(List<String> data, Context context) {
this.data = data;
this.context = context;
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View v = convertView;
if(v == null){
LayoutInflater inflater = getActivity().getLayoutInflater();
// normally use a viewholder
v = inflater.inflate(R.layout.card_view, parent, false);
}
((TextView) v.findViewById(R.id.textView2)).setText(data.get(position));
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String item = (String)getItem(position);
Log.i("MainActivity", item);
}
});
return v;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home,container,false);
final SwipeDeck cardStack = (SwipeDeck) view.findViewById(R.id.swipe_deck);
cardStack.setHardwareAccelerationEnabled(true);
Button btn = (Button) view.findViewById(R.id.undobutton);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cardStack.swipeTopCardLeft(180);
}
});
Button btn2 = (Button) view.findViewById(R.id.joinbutton);
btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cardStack.swipeTopCardRight(180);
}
});
final ArrayList<String> testData = new ArrayList<>();
testData.add("0");
testData.add("1");
testData.add("2");
testData.add("3");
testData.add("4");
final SwipeDeckAdapter adapter = new SwipeDeckAdapter(testData, getActivity() );
cardStack.setAdapter(adapter);
cardStack.setEventCallback(new SwipeDeck.SwipeEventCallback() {
#Override
public void cardSwipedLeft(int position) {
Log.i("MainActivity", "card was swiped left, position in adapter: " + position);
}
#Override
public void cardSwipedRight(int position) {
Log.i("MainActivity", "card was swiped right, position in adapter: " + position);
}
#Override
public void cardsDepleted() {
Log.i("MainActivity", "no more cards");
}
#Override
public void cardActionDown() {
Log.i("MainActivity", "Down");
} ;
#Override
public void cardActionUp() {
Log.i("MainActivity", "Up");
};
});
return view;
}
public static FirstFragment newInstance(int index) {
FirstFragment f = new FirstFragment();
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
}
fragment_first.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:background="#color/black"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="io.MainActivity"
android:fitsSystemWindows="true">
<com.daprlabs.cardstack.SwipeLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:swipedeck="http://schemas.android.com/apk/res-auto"
android:id="#+id/framelayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="10">
<com.daprlabs.cardstack.SwipeDeck
android:id="#+id/swipe_deck"
android:layout_weight="8"
android:layout_width="match_parent"
android:layout_height="0dp"
swipedeck:card_spacing="0dp"
swipedeck:max_visible="3"
swipedeck:render_above="true"
swipedeck:rotation_degrees="15"
swipedeck:opacity_end="0.33">
</com.daprlabs.cardstack.SwipeDeck>
<RelativeLayout
android:id="#+id/rl"
android:layout_weight="2"
android:layout_width="match_parent"
android:layout_height="0dp">
<RelativeLayout
android:id="#+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true">
<Button
android:id="#+id/undobutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Undo"
android:onClick="onClick"/>
<Button
android:id="#+id/joinbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/undobutton"
android:text="Join"
android:onClick="onClick"/>
</RelativeLayout>
</RelativeLayout>
</com.daprlabs.cardstack.SwipeLinearLayout>
In your parent RelativeLayout in fragment_first can you remove the android:fitsSystemWindows="true", I think that may be the cause of the issue.

Dynamically Setting a Fixed Height for a Staggered Grid View

I'm trying to take a RecyclerView with a StaggeredGridLayout and make it a fixed height by having it measure the views and set the height dynamically. I'm overriding the onMeasure(), but it does not always seem to measure correctly. I'd say it works about 50% of the time. The other 50% of the time it under measures it. I think it has to do with when the text wraps in the view_tile_small.xml, but I'm not sure.
Fragment
public class AtTheMuseumFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
//Odds n Ends Variables
private MapFragment mapFragment;
private FragmentTransaction fragmentTransaction;
private User user = new User();
private MuseumCollection museumCollection;
private Context context;
//Story Grid Adapter Variables
private AtTheMuseumAdapter nearMeAdapter;
private TileFactory tileFactory;
//Interfaces
private OnFragmentChangeListener changeListener;
#Bind(R.id.stories_list_view) RecyclerView storiesListView;
#Bind(R.id.swipe_container) SwipeRefreshLayout swipeRefreshLayout;
public static AtTheMuseumFragment newInstance(MuseumCollection museumCollection) {
AtTheMuseumFragment fragment = new AtTheMuseumFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
public AtTheMuseumFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
museumCollection = ((MainActivity) getActivity()).getMuseumCollection();
context = getActivity().getApplicationContext();
tileFactory = new TileFactory();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_museum, container, false);
ButterKnife.bind(this, view);
//Sets up the layoutManager to the Mason View
storiesListView.setLayoutManager(new MeasuredStaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
//Sets up The map
try{
fragmentTransaction = getChildFragmentManager().beginTransaction();
mapFragment = MapFragment.newInstance(MapFragment.MUSEUM);
fragmentTransaction.add(R.id.museum_map, mapFragment).commit();
}catch (Exception e){
Log.d("Map - Initial Inflate:", e.getMessage());
}
//Sets up the swipe to refresh jawn
swipeRefreshLayout.setOnRefreshListener(this);
setNearMeAdapter();
return view;
}
#Override
public void onResume(){
super.onResume();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
changeListener = (OnFragmentChangeListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
changeListener = null;
}
/**
* Loads the adapter once the data is ready
*
*/
public void setNearMeAdapter(){
List<MuseumObject> newList = museumCollection.getObjectsNearUser(User.position, 4);
List<Tile> tiles = tileFactory.createAtMuseumFeed(newList, true);
nearMeAdapter = new AtTheMuseumAdapter(context, tiles, getActivity());
storiesListView.setAdapter(nearMeAdapter);
}
/**
* Refreshes Adapter with new data
*
*/
public void refreshNearMeAdapter(){
//TODO CHANGE THIS TO LOCATION BASED WHEN TIME IS RIGHT - Peter
//nearMeAdapter.setNewData(MuseumCollection.getObjectsNearUser(User.position, 4));
List<MuseumObject> newList = museumCollection.getRandomOrder();
nearMeAdapter.setNewData(tileFactory.createAtMuseumFeed(newList,false));
}
/**
* Adds past data to the Adapter
*
*/
public void loadPastObjects(){
//TODO MAKE THIS NOT ONLY LOAD RANDOM DATA - Peter
List<MuseumObject> newList = museumCollection.getRandomOrder();
nearMeAdapter.addNewData(tileFactory.createAtMuseumFeed(newList, false));
nearMeAdapter.notifyDataSetChanged();
}
#Override
public void onRefresh() {
user.updateUserLocation();
refreshNearMeAdapter();
mapFragment.refreshMap(museumCollection.getObjectFeed());
swipeRefreshLayout.setRefreshing(false);
}
public interface OnFragmentChangeListener {
void onFragmentChange(String fragment);
}
#OnClick(R.id.explore_map)
public void exploreMap(){
changeListener.onFragmentChange("map");
}
#OnClick(R.id.load_more)
public void loadMore(){
loadPastObjects();
}
}
MeasuredStaggeredGridLayoutManager
public class MeasuredStaggeredGridLayoutManager extends StaggeredGridLayoutManager {
public MeasuredStaggeredGridLayoutManager(int spanCount, int orientation) {
super(spanCount, orientation);
}
private int[] mMeasuredDimension = new int[2];
#Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
int heightR = 0;
int heightL = 0;
for (int i = 0; i < getItemCount(); i++) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
if (getOrientation() == HORIZONTAL) {
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
if(i % 2 == 0){
heightL += mMeasuredDimension[1];
}else{
heightR += mMeasuredDimension[1];
}
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
if(heightL != 0 || heightR != 0){
height = (heightL > heightR) ? heightL : heightR;
}
//TODO come up with a better way to fix the slightly wrong height
// must be not accounting for padding or margin or something - Peter
height += (20 * (getItemCount() / 2)) + 5;
setMeasuredDimension(width, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
if (view != null) {
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
getPaddingLeft() + getPaddingRight(), p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
getPaddingTop() + getPaddingBottom(), p.height);
view.measure(childWidthSpec, childHeightSpec);
measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}
}
AtTheMuseumAdapter
public class AtTheMuseumAdapter extends RecyclerView.Adapter<AtTheMuseumAdapter.MuseumStoriesViewHolder> {
private List<Tile> tiles;
private LayoutInflater inflater;
private AdapterCallback mListener;
private Context context;
public AtTheMuseumAdapter(Context context, List<Tile> tiles, Activity activity) {
this.tiles = tiles;
this.context = context;
inflater = LayoutInflater.from(this.context);
//Sets up interface between Stock Adapter and Fragment
try {
this.mListener = ((AdapterCallback) activity);
} catch (ClassCastException e) {
throw new ClassCastException("Fragment must implement AdapterCallback.");
}
}
#Override
public MuseumStoriesViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = inflater.inflate(R.layout.view_tile_small, viewGroup, false);
MuseumStoriesViewHolder holder = new MuseumStoriesViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(MuseumStoriesViewHolder holder, int position) {
Tile currentTile = tiles.get(position);
holder.title.setText(currentTile.getTitle());
holder.desc.setText(currentTile.getDescription());
holder.type.setText(currentTile.getObjectTypeName());
//Using Picasso since it handles caching and all that jazz
Picasso.with(context)
.load(currentTile.getImg())
.into(holder.img);
}
#Override
public int getItemCount() {
return tiles.size();
}
public void setNewData(List<Tile> newItems){
tiles = newItems;
notifyDataSetChanged();
}
public void addNewData(final List<Tile> newItems){
tiles.addAll(newItems);
notifyDataSetChanged();
}
class MuseumStoriesViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView type,title,desc;
public ImageView img;
public MuseumStoriesViewHolder(View itemView) {
super(itemView);
//Tried Butterknife, but it doesn't seem like it was working in the view holder. - Peter
type = (TextView) itemView.findViewById(R.id.small_box_type);
title = (TextView) itemView.findViewById(R.id.small_box_title);
desc = (TextView) itemView.findViewById(R.id.small_box_desc);
img = (ImageView) itemView.findViewById(R.id.small_box_image);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
Tile t = tiles.get(getPosition());
switch (t.getObjectTypeName()){
case Tile.OBJECT_NAME:
mListener.onObjectClick(t.getObjectID());
break;
case Tile.TOUR_NAME:
mListener.onTourCLick(t.getTourID());
break;
case Tile.STORY_NAME:
mListener.onStoryClick(t.getObjectID(), t.getStoryID());
break;
}
}
}
public interface AdapterCallback {
public void onObjectClick(String objectID);
public void onStoryClick(String objectID, String storyID);
public void onTourCLick(String tourID);
}
}
view_tile_small.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/margin_small"
android:background="#color/small_box_background_color">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--TODO Make layout_height wrap contenet -->
<ImageView
android:id="#+id/small_box_image"
android:layout_width="match_parent"
android:layout_height="150dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:maxHeight="150dp"
android:background="#color/transparent"/>
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="right"
android:src="#drawable/abc_btn_rating_star_off_mtrl_alpha"
/>
<TextView
android:id="#+id/small_box_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_normal"
android:paddingBottom="#dimen/margin_normal"
android:textSize="#dimen/font_small"
android:textColor="#color/font_white"
android:background="#drawable/small_box_text_bottom_border"
android:layout_gravity="bottom"
android:text="Object Story"
/>
</FrameLayout>
<TextView
android:id="#+id/small_box_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/margin_larger"
android:layout_marginBottom="#dimen/margin_normal"
android:layout_marginRight="#dimen/margin_larger"
android:layout_marginTop="#dimen/margin_larger"
android:textSize="#dimen/font_large"
android:textColor="#color/font_black"
android:text="Sample Text Here"
/>
<TextView
android:id="#+id/small_box_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/margin_larger"
android:layout_marginBottom="#dimen/margin_larger"
android:textSize="#dimen/font_normal"
android:textColor="#color/font_black"
android:textStyle="italic"
android:text="Sample Text Here"
/>
</LinearLayout>
fragment_museum
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.bluecadet.android.nasm.ui.AtTheMuseumFragment"
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="100dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:descendantFocusability="blocksDescendants"
>
<TextView
android:id="#+id/museum_header"
style="#style/header"
android:text="#string/museum_header"
android:layout_margin="#dimen/margin_larger"
android:elevation="8dp"
/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="275dp"
android:elevation="2dp"
>
<FrameLayout
android:id="#+id/museum_map"
android:layout_height="fill_parent"
android:layout_width="match_parent"
/>
<include
layout="#layout/view_explore_map" />
</FrameLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/stories_list_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/margin_normal"
android:layout_marginLeft="#dimen/margin_small"
android:layout_marginRight="#dimen/margin_small"
android:layout_marginTop="#dimen/margin_normal"
android:stretchMode="columnWidth"
/>
<Button
android:id="#+id/load_more"
style="#style/home_button"
android:gravity="center"
android:text="#string/button_load_more"
/>
</LinearLayout>
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
ViewTreeObserver code I'm playing with now. It's in Fragment.
mTopStoriesListView.setLayoutManager(new NewMeasuredStaggeredLayoutManager(2, StaggeredGridLayoutManager.VERTICAL, mTopStoriesListView));
mTopStoriesListView.setNestedScrollingEnabled(false);
//Testing Issue 54
final ViewTreeObserver viewTreeObserver = mTopStoriesListView.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mTopStoriesListView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int l = 0,r = 0;
for(int i = 0 ; i < mNearMeAdapter.getItemCount(); i++){
int h = mTopStoriesListView.getLayoutManager().findViewByPosition(i).getHeight();
ViewGroup.MarginLayoutParams layout = (ViewGroup.MarginLayoutParams) mTopStoriesListView.getLayoutManager()
.findViewByPosition(i).getLayoutParams();
int t = layout.topMargin;
int b = layout.bottomMargin;
if(i % 2 == 0){
l += h + t + b;
}else{
r += h + t + b;
}
}
int viewHeight = (l > r) ? l : r;
mTopStoriesListView.getLayoutParams().height = viewHeight;
Log.d("TAG", String.valueOf(viewHeight));
}
});
}
//END TEST
Have you look at ViewTreeObserver ?
I got a similar problem on a passed project and I have found it more reliable than onMesure to dynamically get Layout properties
You can go through it from here : http://developer.android.com/reference/android/view/ViewTreeObserver.html

Categories