[SOLVED] Is it possible to make SearchView(android.support.v7.widget) in the ActionBar(android.support.v7.app) like a MultiAutoCompleteTextView?
Suggesting words like here, after custom delimiter.
I didn't extend MultiAutoCompleteTextView because I didn't want to lose some features like icon, "X" button.
UPDATE:
I tried to extend SearchView:
public class MultiAutoCompleteSearchView extends android.support.v7.widget.SearchView {
private MultiAutoCompleteSearchView.SearchAutoComplete mSearchAutoComplete;
public static class SearchAutoComplete extends android.support.v7.widget.SearchView.SearchAutoComplete {
private String mSeparator = "+";
public SearchAutoComplete(Context context) {
super(context);
}
public SearchAutoComplete(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SearchAutoComplete(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void replaceText(CharSequence text) {
String newText = getText().toString();
if (newText.contains(mSeparator)) {
int lastIndex = newText.lastIndexOf(mSeparator);
newText = newText.substring(0, lastIndex + 1) + text.toString();
} else {
newText = text.toString();
}
super.replaceText(newText);
}
#Override
protected void performFiltering(CharSequence text, int keyCode) {
String newText = text.toString();
if (newText.indexOf(mSeparator) != -1) {
int lastIndex = newText.lastIndexOf(mSeparator);
if (lastIndex != newText.length() - 1) {
newText = newText.substring(lastIndex + 1).trim();
if (newText.length() >= getThreshold()) {
text = newText;
}
}
}
super.performFiltering(text, keyCode);
}
}
public void initialize() {
mSearchAutoComplete = (MultiAutoCompleteSearchView.SearchAutoComplete)
findViewById(android.support.v7.appcompat.R.id.search_src_text);
this.setAdapter(null);
this.setOnItemClickListener(null);
}
public MultiAutoCompleteSearchView(Context context) {
super(context);
initialize();
}
public MultiAutoCompleteSearchView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public MultiAutoCompleteSearchView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
public void setOnItemClickListener(AdapterView.OnItemClickListener listener) {
mSearchAutoComplete.setOnItemClickListener(listener);
}
public void setAdapter(ArrayAdapter<?> adapter) {
mSearchAutoComplete.setAdapter(adapter);
}
}
And xml file for menu.
<menu 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"
tools:context=".SearchActivity">
<item android:id="#+id/action_search"
android:title="#string/action_search"
android:icon="#drawable/ic_action_search"
app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="cullycross.com.searchview.MultiAutoCompleteSearchView" />
</menu>
And activity method:
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_search, menu);
final MenuItem searchItem = menu.findItem(R.id.action_search);
final MultiAutoCompleteSearchView searchView = (MultiAutoCompleteSearchView)
MenuItemCompat.getActionView(searchItem);
searchView.setQueryHint("Type any word");
MultiAutoCompleteSearchView.SearchAutoComplete searchAutoComplete =
(MultiAutoCompleteSearchView.SearchAutoComplete)searchView
.findViewById(R.id.search_src_text);
searchAutoComplete.setAdapter(new ArrayAdapter<String>(
this,
android.R.layout.simple_dropdown_item_1line,
options
));
return true;
}
But for some reason I get a NPE here: searchView.setQueryHint("Type any word");, so it means, that getActionView returns null.
A lot of hours are passed, I found a solution:
Custom adapter:
public class DelimiterAdapter extends ArrayAdapter<String> implements Filterable {
private final static String [] options = {
"Apple","Mango","Peach","Banana","Orange","Grapes","Watermelon","Tomato"
};
private final LayoutInflater mInflater;
private List<String> mSubStrings;
private String mMainString;
public String getMainString() { return mMainString; }
private AmazingFilter mFilter;
public DelimiterAdapter(Context context, int resource) {
super(context, -1);
mInflater = LayoutInflater.from(context);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final TextView tv;
if (convertView != null) {
tv = (TextView) convertView;
} else {
tv = (TextView) mInflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
}
tv.setText(getItem(position));
return tv;
}
#Override
public int getCount() {
return mSubStrings.size();
}
#Override
public String getItem(int position) {
return mSubStrings.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public Filter getFilter() {
if(mFilter == null) {
mFilter = new AmazingFilter();
}
return mFilter;
}
private class AmazingFilter extends Filter {
private final static String DELIMITER = "+";
#Override
protected FilterResults performFiltering(CharSequence constraint) {
final FilterResults filterResults = new FilterResults();
String request;
mSubStrings = new ArrayList<String>();
if(constraint != null) {
request = constraint.toString();
//cuts the string with delimiter
if (request.contains(DELIMITER) &&
request.lastIndexOf(DELIMITER) != request.length() - 1) {
final String[] splitted = request.split("\\" + DELIMITER);
request = splitted[splitted.length - 1].trim();
//save string before delimiter
int index = constraint.toString().lastIndexOf(request);
mMainString = constraint.toString().substring(0, index);
} else {
request = request.trim();
mMainString = "";
}
//checks for substring of any word in the dictionary
for(String s : options) {
if(s.contains(request)) {
mSubStrings.add(s);
}
}
}
filterResults.values = mSubStrings;
filterResults.count = mSubStrings.size();
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
clear();
for (String request : (ArrayList<String>)results.values) {
add(request);
}
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
}
Extended SearchView:
public class MultiAutoCompleteSearchView extends android.support.v7.widget.SearchView {
private SearchAutoComplete mSearchAutoComplete;
public void initialize() {
mSearchAutoComplete = (SearchAutoComplete)
findViewById(android.support.v7.appcompat.R.id.search_src_text);
this.setAdapter(null);
this.setOnItemClickListener(null);
}
public MultiAutoCompleteSearchView(Context context) {
super(context);
initialize();
}
public MultiAutoCompleteSearchView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public MultiAutoCompleteSearchView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
public void setOnItemClickListener(AdapterView.OnItemClickListener listener) {
mSearchAutoComplete.setOnItemClickListener(listener);
}
public void setAdapter(ArrayAdapter<?> adapter) {
mSearchAutoComplete.setAdapter(adapter);
}
}
Activity method onCreateMenuOptions
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_search, menu);
final MenuItem searchItem = menu.findItem(R.id.action_search);
final MultiAutoCompleteSearchView searchView = (MultiAutoCompleteSearchView)
MenuItemCompat.getActionView(searchItem);
searchView.setQueryHint("Type any word");
MultiAutoCompleteSearchView.SearchAutoComplete searchAutoComplete =
(MultiAutoCompleteSearchView.SearchAutoComplete)searchView
.findViewById(R.id.search_src_text);
//since words are very short
searchAutoComplete.setThreshold(1);
searchAutoComplete.setAdapter(new DelimiterAdapter(
this,
android.R.layout.simple_dropdown_item_1line
));
searchView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String stringBefore, newString;
stringBefore = ((DelimiterAdapter)parent.getAdapter()).getMainString();
newString = parent.getAdapter().getItem(position).toString();
searchView.setQuery(stringBefore+newString, false);
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String s) {
if(s.length() > 0) {
mFindString = s;
// do smth with string
return true;
}
return false;
}
#Override
public boolean onQueryTextChange(String s) {
return false;
}
});
return true;
}
XML file of the menu:
<menu 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"
tools:context=".SearchActivity">
<item android:id="#+id/action_search"
android:title="#string/action_search"
android:icon="#drawable/ic_action_search"
app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="cullycross.com.searchview.MultiAutoCompleteSearchView" />
</menu>
Related
I'm using SearchView to filter music items. But when I search for an item the title of the song updates but not the actual song. Originally I had listSongs = musicFiles which worked but didn't update the items only the title. Then I changed it to listSongs = mFiles, which throws a nullPointerException.
MusicAdapter
public class MusicAdapter extends RecyclerView.Adapter<MusicAdapter.MyVieHolder> {
private Context mContext;
static ArrayList<MusicFiles> mFiles = new ArrayList<>();
MusicAdapter(Context mContext, ArrayList<MusicFiles> mFiles){
MusicAdapter.mFiles = mFiles;
this.mContext = mContext;
}
#NonNull
#Override
public MyVieHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.music_items, parent, false);
return new MyVieHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyVieHolder holder, final int position) {
holder.file_name.setText(mFiles.get(position).getTitle());
byte[] image = getAlbumArt(mFiles.get(position).getPath());
if (image != null){
Glide.with(mContext).asBitmap()
.load(image)
.into(holder.album_art);
}
else{
Glide.with(mContext).asBitmap()
.load(R.drawable.something_3)
.into(holder.album_art);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, MainActivity.class);
intent.putExtra("position" , position);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
notifyDataSetChanged();
}
});
}
#Override
public int getItemCount() {
return mFiles.size();
}
public class MyVieHolder extends RecyclerView.ViewHolder{
TextView file_name;
ImageView album_art;
public MyVieHolder(#NonNull View itemView) {
super(itemView);
file_name = itemView.findViewById(R.id.music_file_name);
album_art = itemView.findViewById(R.id.music_img);
}
}
private byte[] getAlbumArt(String uri){
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(uri);
byte[] art = retriever.getEmbeddedPicture();
retriever.release();
return art;
}
public void updateList(ArrayList<MusicFiles> musicFilesArrayList){
mFiles = new ArrayList<>();
mFiles.addAll(musicFilesArrayList);
notifyDataSetChanged();
}
MainActivity
This is the code I'm having trouble with
public void getInentMethod() {
position = getIntent().getIntExtra("position", 0);
listSongs = mFiles; //bug occurs when listSongs = mFiles
if (listSongs != null) {
playBtn.setBackgroundResource(R.drawable.ic_pause);
uri = Uri.parse(listSongs.get(position).getPath());
}
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
}
else {
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
playBtn.setBackgroundResource(R.drawable.ic_play);
mediaPlayer.stop();
}
seekBar.setMax(mediaPlayer.getDuration()/1000);
metaData(uri);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search, menu);
MenuItem menuItem = menu.findItem(R.id.search_option);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setOnQueryTextListener(this);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onQueryTextSubmit (String query){
return false;
}
#Override
public boolean onQueryTextChange (String newText){
String userInput = newText.toLowerCase();
ArrayList<MusicFiles> musicFilesArrayList = new ArrayList<>();
for (MusicFiles mFiles : musicFiles){
if(mFiles.getTitle().toLowerCase().contains(userInput)){
musicFilesArrayList.add(mFiles);
}
}
musicAdapter.updateList(musicFilesArrayList);
return true;
}
When listSongs = mFiles I receive a nullPointerException, uri param cannot be null. I don't know what's causing this?
I'm also receiving an IndexOutOfBoundsException.
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0.
Any help will be appreciated.
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/search_bar"
android:title="search"
android:icon="#drawable/ic_baseline_search_24"
app:showAsAction="always|collapseActionView"
app:actionViewClass="android.widget.SearchView" />
</menu>
Inside onCreateOptionsMenu
getMenuInflater().inflate(R.menu.main_menu,menu);
MenuItem searchItem=menu.findItem(R.id.search_bar);
MenuItem settingsItem=menu.findItem(R.id.action_settings);
SearchView searchView= (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
//do filter here
adapter.getFilter().filter(newText);
return false;
}
});
return true;
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
if (item.getItemId()==R.id.search_bar) return true;
return super.onOptionsItemSelected(item);
}
In the Adapter class, create two arraylists
class Adapter implements Filterable{
private List<TotalItems> totalItems; //original
private List<TotalItems> totalItemsAll; //copy
Context context;
public Adapter(ArrayList<TotalItems> totalItems,Context context){
this.totalItems=totalItems;
this.context=context;
this.totalItemsAll=new ArrayList<>(totalItems);
}
#Override
public Filter getFilter() {
return filter;
}
private Filter filter=new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
//TotalItems is my model class
List<TotalItems> filteredList=new ArrayList<>();
if (charSequence==null||charSequence.length()==0)
filteredList.addAll(totalItemsAll);
else {
String filterPattern=charSequence.toString().toLowerCase().trim();
for (TotalItems productList:totalItemsAll){
if (productList.getiName().toLowerCase().contains(filterPattern)){
filteredList.add(productList);
}else Toast.makeText(context,"No results found",Toast.LENGTH_LONG).show();
}
}
FilterResults filterResults=new FilterResults();
filterResults.values=filteredList;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
totalItems.clear();
totalItems.addAll((List)filterResults.values);
notifyDataSetChanged();
}
};
}
Let me know if this works for you
I have written code for an app that is designed to read XML and populate a listview with the data read. The data is stored in a containing class. I've created an adapter class as well as a custom filter. For some reason, when I type inside my searchView, nothing comes up! I've looked all over youtube/google for a few days and cannot find anything! please help!
private class ArticleAdapter extends ArrayAdapter<Article> implements Filterable {
private List<Article> completeList = new ArrayList<>(articles);
public ArticleAdapter(Context ctx) {
super(ctx, 0);
}
#NonNull
#Override
public Filter getFilter() {
return titleFilter;
}
public int getCount() {
return articles.size();
}
public Article getItem(int position) {
return articles.get(position);
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.title_layout, parent, false);
}
TextView articleTitle = convertView.findViewById(R.id.titleId);
Article article = getItem(position);
if (article != null) {
articleTitle.setText(getItem(position).title);
}
return convertView;
}
Filter titleFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
List<Article> suggestions = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
suggestions.addAll(completeList);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (Article title : completeList) {
if (title.getTitle().toLowerCase().contains(filterPattern)) {
suggestions.add(title);
}
}
}
results.values = suggestions;
results.count = suggestions.size();
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
clear();
addAll((List) results.values);
notifyDataSetChanged();
}
#Override
public CharSequence convertResultToString(Object resultValue) {
return ((Article) resultValue).getTitle();
}
};
/* public long getItemId(int position) {
return getItem(position).id;
}
*/
}
}
And this is the onCreateOptionsMenu method from my ArticleList class (main class)
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_search, menu);
item = menu.findItem(R.id.menuSearch);
searchView = (SearchView) item.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
if (articles.isEmpty()) {
}
adapter.getFilter().filter(newText);
return false;
}
});
return super.onCreateOptionsMenu(menu);
}
I had a list of customers where I had to search a customer by their name.So here is the code.I hope it helps. :)
//Defined this two list global
private List customerList = new ArrayList<>();
private List searchCustomerList = new ArrayList<>();
In onCreate() I call this method : addTextListener();
private void addTextListener()
{
try {
searchBar.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence query, int start, int before, int count) {
query = query.toString().toLowerCase();
searchCustomerList.clear();
for (int i = 0; i < customerList.size(); i++) {
if (customerList.get(i) != null) {
String text = customerList.get(i).getCustomerName().toLowerCase();
if (text.toString().contains(query)) {
searchCustomerList.add(customerList.get(i));
}
}
}
Log.d("filterflower", "size: " + searchCustomerList.size());
customerListAdapter.updateList(searchCustomerList); // data set changed
}
});
}catch (Exception e){
e.printStackTrace();
}
}
//Here is the updateList Method in my recycler adapter
public void updateList(List<CustomerListDataModel> searchCustomerList) {
customerList = searchCustomerList;
notifyDataSetChanged();
}
I am building a list that had to be able to reorder the item's position.
Fortunately for me, I've found an external library which has exactly what I needed.
Unfortunately, I could not implement a delete item action using onContextItemSelected() because menuInfo keeps always returning null, so I cannot read the position of selected item I wish to delete.
This user blog post gave a solution by overriding getContextMenuInfo().
If item.getMenuInfo() is null in onContextItemSelected(MenuItem item) method, I guess you are using custom ListView or GridView instead of android default ones. In such case, your custom View is not implementing getContextMenuInfo() method. Don’t worry we can fix that if you have its source. Open the view file and override the method getContextMenuInfo().
I have tried this in many ways, but it seems I am doing things wrong.
Is this the only solution or am I missing something?
Activity
public class SurveyAdd extends AppCompatActivity {
private ArrayList<Pair<Long, String>> mItemArray = new ArrayList<>();
private DragListView mDragListView;
ItemAdapter listAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_survey_add);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDragListView = (DragListView) findViewById(R.id.surveyadd_list);
mDragListView.getRecyclerView().setVerticalScrollBarEnabled(true);
mDragListView.setDragListListener(new DragListView.DragListListener() {
#Override
public void onItemDragStarted(int position) {
}
#Override
public void onItemDragEnded(int fromPosition, int toPosition) {
if (fromPosition != toPosition) {
setSurveyChange(true);
}
}
});
mDragListView.setCanDragHorizontally(false);
mDragListView.setCustomDragItem(new MyDragItem(context, R.layout.item_survey_add));
mDragListView.setLayoutManager(new LinearLayoutManager(context));
mDragListView.setLayoutManager(new LinearLayoutManager(context));
ItemAdapter listAdapter = new ItemAdapter(mItemArray, R.layout.item_survey_add, R.id.item_add_image_button, false);
mDragListView.setAdapter(listAdapter, true);
registerForContextMenu(mDragListView);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_survey_add_item, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.surveyadd_action_delete:
if (item.getMenuInfo() == null) {
Toast.makeText(SurveyAdd.this, "NULL", Toast.LENGTH_SHORT).show();
}
int position = info.position; // CAN'T USE THIS, ALWAYS THROWS NULLPOINTEREXCEPTION
Toast.makeText(SurveyAdd.this, "" + position, Toast.LENGTH_SHORT).show();
return true;
}
}
}
// The activity was simplified for posting
ItemAdapter
imported and edited class
public class ItemAdapter extends DragItemAdapter<Pair<Long, String>, ItemAdapter.ViewHolder> {
private int mLayoutId;
private int mGrabHandleId;
public ItemAdapter(ArrayList<Pair<Long, String>> list, int layoutId, int grabHandleId, boolean dragOnLongPress) {
super(dragOnLongPress);
mLayoutId = layoutId;
mGrabHandleId = grabHandleId;
setHasStableIds(true);
setItemList(list);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
String text = mItemList.get(position).second;
String[] separated = text.split("::");
holder.mText.setText(separated[1]);
holder.itemView.setTag(text);
}
#Override
public long getItemId(int position) {
return mItemList.get(position).first;
}
public class ViewHolder extends DragItemAdapter<Pair<Long, String>, ItemAdapter.ViewHolder>.ViewHolder {
public TextView mText;
public ImageView mIcon;
public ViewHolder(final View itemView) {
super(itemView, mGrabHandleId);
mText = (TextView) itemView.findViewById(R.id.item_add_question);
mIcon = (ImageView) itemView.findViewById(mGrabHandleId);
}
#Override
public void onItemClicked(View view) {
}
#Override
public boolean onItemLongClicked(View view) {
return false;
}
}
}
DragListView
imported and locked class
public class DragListView extends FrameLayout {
public interface DragListListener {
void onItemDragStarted(int position);
void onItemDragEnded(int fromPosition, int toPosition);
}
private DragItemRecyclerView mRecyclerView;
private DragListListener mDragListListener;
private DragItem mDragItem;
private boolean mDragEnabled = true;
private float mTouchX;
private float mTouchY;
public DragListView(Context context) {
super(context);
}
public DragListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DragListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mDragItem = new DragItem(getContext());
mRecyclerView = createRecyclerView();
mRecyclerView.setDragItem(mDragItem);
addView(mRecyclerView);
addView(mDragItem.getDragItemView());
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean retValue = handleTouchEvent(event);
return retValue || super.onInterceptTouchEvent(event);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean retValue = handleTouchEvent(event);
return retValue || super.onTouchEvent(event);
}
private boolean handleTouchEvent(MotionEvent event) {
mTouchX = event.getX();
mTouchY = event.getY();
if (isDragging()) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
mRecyclerView.onDragging(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mRecyclerView.onDragEnded();
break;
}
return true;
}
return false;
}
private DragItemRecyclerView createRecyclerView() {
final DragItemRecyclerView recyclerView = (DragItemRecyclerView) LayoutInflater.from(getContext()).inflate(R.layout.drag_item_recycler_view, this, false);
recyclerView.setMotionEventSplittingEnabled(false);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setVerticalScrollBarEnabled(false);
recyclerView.setHorizontalScrollBarEnabled(false);
recyclerView.setDragItemListener(new DragItemRecyclerView.DragItemListener() {
private int mDragStartPosition;
#Override
public void onDragStarted(int itemPosition, float x, float y) {
getParent().requestDisallowInterceptTouchEvent(true);
mDragStartPosition = itemPosition;
if (mDragListListener != null) {
mDragListListener.onItemDragStarted(itemPosition);
}
}
#Override
public void onDragging(int itemPosition, float x, float y) {
}
#Override
public void onDragEnded(int newItemPosition) {
if (mDragListListener != null) {
mDragListListener.onItemDragEnded(mDragStartPosition, newItemPosition);
}
}
});
return recyclerView;
}
public RecyclerView getRecyclerView() {
return mRecyclerView;
}
public DragItemAdapter getAdapter() {
if (mRecyclerView != null) {
return (DragItemAdapter) mRecyclerView.getAdapter();
}
return null;
}
public void setAdapter(DragItemAdapter adapter, boolean hasFixedItemSize) {
mRecyclerView.setHasFixedSize(hasFixedItemSize);
mRecyclerView.setAdapter(adapter);
adapter.setDragEnabled(mDragEnabled);
adapter.setDragStartedListener(new DragItemAdapter.DragStartedListener() {
#Override
public void onDragStarted(View itemView, long itemId) {
mRecyclerView.onDragStarted(itemView, itemId, mTouchX, mTouchY);
}
});
}
public void setLayoutManager(RecyclerView.LayoutManager layout) {
mRecyclerView.setLayoutManager(layout);
}
public void setDragListListener(DragListListener listener) {
mDragListListener = listener;
}
public boolean isDragEnabled() {
return mDragEnabled;
}
public void setDragEnabled(boolean enabled) {
mDragEnabled = enabled;
if (mRecyclerView.getAdapter() != null) {
((DragItemAdapter) mRecyclerView.getAdapter()).setDragEnabled(mDragEnabled);
}
}
public void setCustomDragItem(DragItem dragItem) {
removeViewAt(1);
DragItem newDragItem;
if (dragItem != null) {
newDragItem = dragItem;
} else {
newDragItem = new DragItem(getContext());
}
newDragItem.setCanDragHorizontally(mDragItem.canDragHorizontally());
newDragItem.setSnapToTouch(mDragItem.isSnapToTouch());
mDragItem = newDragItem;
mRecyclerView.setDragItem(mDragItem);
addView(mDragItem.getDragItemView());
}
public boolean isDragging() {
return mRecyclerView.isDragging();
}
public void setCanDragHorizontally(boolean canDragHorizontally) {
mDragItem.setCanDragHorizontally(canDragHorizontally);
}
public void setSnapDragItemToTouch(boolean snapToTouch) {
mDragItem.setSnapToTouch(snapToTouch);
}
public void setCanNotDragAboveTopItem(boolean canNotDragAboveTop) {
mRecyclerView.setCanNotDragAboveTopItem(canNotDragAboveTop);
}
public void setScrollingEnabled(boolean scrollingEnabled) {
mRecyclerView.setScrollingEnabled(scrollingEnabled);
}
}
This is an old post but i figured it out using that same draglistview.
Im using Xamarin but it's close enough to the same. Just type the C# in Java as necessary:
protected override IContextMenuContextMenuInfo ContextMenuInfo
{
get
{
IContextMenuContextMenuInfo menuInfo = base.ContextMenuInfo;
if (menuInfo == null)
{
IListAdapter adapter = Adapter;
int pos = GetPositionForView(selectedView);
menuInfo = new AdapterContextMenuInfo(selectedView, pos, adapter.GetItemId(pos));
}
return menuInfo;
}
}
public void OnLongPress(MotionEvent e){
int position = PointToPosition(mDownX, mDownY);
int itemNum = position - FirstVisiblePosition;
selectedView = GetChildAt(itemNum); //class variable
...
}
I am using webview in android to play a video. The problem is that video is playing once. I have seen some answers about how to fix it, but still not working. Here's my code:
public class MyChromeClient extends WebChromeClient implements
OnCompletionListener, OnErrorListener {
private Activity _activity;
private VideoView mCustomVideoView;
private LinearLayout mContentView;
private FrameLayout mCustomViewContainer;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT, Gravity.CENTER);
public MyChromeClient(Activity context) {
super();
_activity = context;
}
#Override
public void onShowCustomView(View view, CustomViewCallback callback) {
super.onShowCustomView(view, callback);
if (view instanceof FrameLayout) {
FrameLayout frame = (FrameLayout) view;
if (frame.getFocusedChild() instanceof VideoView) {
mCustomVideoView = (VideoView) frame.getFocusedChild();
frame.removeView(mCustomVideoView);
_activity.setContentView(mCustomVideoView);
mCustomVideoView.setOnCompletionListener(this);
mCustomVideoView.setOnErrorListener(this);
mCustomVideoView.start();
}
}
}
public void onHideCustomView() {
if (mCustomVideoView == null)
return;
// Hide the custom view.
mCustomVideoView.setVisibility(View.GONE);
// Remove the custom view from its container.
mCustomViewContainer.removeView(mCustomVideoView);
mCustomVideoView = null;
mCustomViewContainer.setVisibility(View.GONE);
mCustomVideoView.stopPlayback();
mCustomViewCallback.onCustomViewHidden();
// Show the content view.
mContentView.setVisibility(View.VISIBLE);
}
public void onCompletion(MediaPlayer mp) {
//Intent intent = new Intent(_activity, _activity.getClass());
//intent.setClass(_activity, _activity.getClass());
//_activity.startActivity(intent);
//_activity.finish();
}
public boolean onError(MediaPlayer mp, int what, int extra) {
return true;
}
}
try this
add this in show method
WebChromeClient.CustomViewCallback CustomViewCallback; mCustomViewCallback = callback;
then in hide method...
mCustomViewCallback.onCustomViewHidden(); mCustomViewCallback = null; HTML5WebView.this.goBack();
EDIT :-
public class HTML5WebView extends WebView {
static final String LOGTAG = "HTML5WebView";
private void init(Context context) {
mContext = context;
Activity a = (Activity) mContext;
mLayout = new FrameLayout(context);
mBrowserFrameLayout = (FrameLayout) LayoutInflater.from(a).inflate(R.layout.custom_screen, null);
mContentView = (FrameLayout) mBrowserFrameLayout.findViewById(R.id.main_content);
mCustomViewContainer = (FrameLayout) mBrowserFrameLayout.findViewById(R.id.fullscreen_custom_content);
mLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);
// Configure the webview
WebSettings s = getSettings();
s.setBuiltInZoomControls(true);
s.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
s.setUseWideViewPort(true);
s.setLoadWithOverviewMode(true);
s.setSaveFormData(true);
s.setJavaScriptEnabled(true);
mWebChromeClient = new MyWebChromeClient();
setWebChromeClient(mWebChromeClient);
setWebViewClient(new WebViewClient());
setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
s.setDomStorageEnabled(true);
mContentView.addView(this);
}
public HTML5WebView(Context context) {
super(context);
init(context);
}
public HTML5WebView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public HTML5WebView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public FrameLayout getLayout() {
return mLayout;
}
public boolean inCustomView() {
return (mCustomView != null);
}
public void hideCustomView() {
mWebChromeClient.onHideCustomView();
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if ((mCustomView == null) && canGoBack()){
goBack();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
private class MyWebChromeClient extends WebChromeClient {
private Bitmap mDefaultVideoPoster;
private View mVideoProgressView;
FrameLayout frame;
#Override
public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback)
{
HTML5WebView.this.setVisibility(View.GONE);
isVideoPlaying = true;
// if a view already exists then immediately terminate the new one
if (mCustomView != null) {
callback.onCustomViewHidden();
return;
}
mCustomViewContainer.addView(view);
mCustomView = view;
frame = (FrameLayout) mCustomView;
mCustomViewCallback = callback;
VideoView mVideoView;
if(frame.getFocusedChild() instanceof VideoView){
mVideoView = (VideoView) frame.getFocusedChild();
}
mCustomViewContainer.setVisibility(View.VISIBLE);
}
#Override
public void onHideCustomView() {
if (mCustomView == null)
return;
// Hide the custom view.
mCustomView.setVisibility(View.GONE);
// Remove the custom view from its container.
mCustomViewContainer.removeView(mCustomView);
mCustomView = null;
mCustomViewContainer.setVisibility(View.GONE);
mCustomViewCallback.onCustomViewHidden();
mCustomViewCallback = null;
HTML5WebView.this.setVisibility(View.VISIBLE);
HTML5WebView.this.goBack();
}
}
}
I would like to offer an alternative, it may not be perfect, but from a web programming point of view, after beating my head against this for some time, the trick was to covert the video to base64 and the feed it to the source tag (jquery in my case). If it isn't in the assets folder it can't get confuse!
I'm trying to create a custom preference for an Android application that limits the number of items the user can select. Once the limit is reached the unselected items should be disabled and only the currently selected items are enabled.. If there are less items selected than the limit all items should be enabled.
Here are the two classes I've cobbled together. The code runs fine but no the CheckedTextView is not checked. As a result no state is maintained.
First the view class...
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.ListView;
public class LimitedMultiChoiceView extends ListView
implements AdapterView.OnItemClickListener
{
private static final String SEPARATOR = "OV=I=XseparatorX=I=VO";
private static final String LIMITEDSELECTION="limitedSelection";
private static final String SUPERSTATE="superState";
private String mSelection = "";
public LimitedMultiChoiceView(Context context, CharSequence[] items, int limit)
{
this(context, null, 0, items, limit);
} // LimitedMultiChoiceView(Context context)
public LimitedMultiChoiceView(Context context, AttributeSet attrs, CharSequence[] items, int limit)
{
this(context, attrs, 0, items, limit);
} // LimitedMultiChoiceView(Context context, AttributeSet attrs)
public LimitedMultiChoiceView(Context context, AttributeSet attrs
, int defStyle, CharSequence[] items, int limit)
{
super(context, attrs, defStyle);
setAdapter(new ItemAdapter(context, android.R.layout.simple_list_item_multiple_choice, items, limit));
} // LimitedMultiChoiceView(Context context, AttributeSet attrs, int defStyle)
public String getSelection()
{
return mSelection;
} // String getSelection()
public void onItemClick(AdapterView<?> parent, View child, int position, long id)
{
// For now we don't need anything...
// we think the ItemAdapter manages what we need for each item.
} // void onItemClick(AdapterView<?> parent, View child, int position, long id)
#Override
public void onRestoreInstanceState(Parcelable toParce)
{
Bundle state=(Bundle)toParce;
super.onRestoreInstanceState(state.getParcelable(SUPERSTATE));
mSelection = state.getString(LIMITEDSELECTION);
} // void onRestoreInstanceState(Parcelable toParce)
#Override
public Parcelable onSaveInstanceState()
{
Bundle state=new Bundle();
state.putParcelable(SUPERSTATE, super.onSaveInstanceState());
state.putString(LIMITEDSELECTION, mSelection);
return(state);
} // Parcelable onSaveInstanceState()
public void setSelection(String value)
{
mSelection = value;
} // void setSelection(String value)
class ItemAdapter extends ArrayAdapter<CharSequence>
{
CharSequence[] mItems = null;
int mLimit = 1;
public ItemAdapter(Context context, int viewResId, CharSequence[] items, int limit)
{
super(context, viewResId, items);
mItems = items;
mLimit = limit;
} // ItemAdapter(Context context, int viewResId, CharSequence[] strings, int limit)
public boolean areAllItemsEnabled()
{
// Since we are in a limited selection list not all items can be
// selected so this always returns false, there is no calculating
// to do.
return false;
} // boolean areAllItemsEnabled()
public boolean isEnabled(int position)
{
boolean[] clickedIndexes = new boolean[this.getCount()];
boolean result = false;
int selectedCount = 0;
mSelection = "";
for (int item=0; item < clickedIndexes.length; item++ )
{
View itemView = this.getView(item, null, LimitedMultiChoiceView.this);
if (itemView instanceof CheckedTextView)
{
CheckedTextView check = (CheckedTextView)itemView;
// First we turn the check mark on or off...
if (item == position)
{
check.setChecked(!check.isChecked());
} // (item == position)
// Now we count how many are checked and mark our tracking array
if (check.isChecked())
{
clickedIndexes[item] = true;
mSelection += check.getText() + SEPARATOR;
}
else
{
clickedIndexes[item] = false;
} // (check.isChecked())
} // (itemView instanceof CheckedTextView)
if (clickedIndexes[item])
selectedCount++;
} // (int item=0; item< clickedIndexes.length; item++ )
if (selectedCount >= mLimit)
{
if (clickedIndexes[position])
{
result = true;
}
else
{
result = false;
} // (clickedIndexes[position])
}
else
{
result = true;
} // (selectedCount >= mLimit)
return result;
} // boolean isEnabled(int position)
} // class ItemAdapter extends ArrayAdapter<CharSequence>
} // class LimitedMultiChoiceView extends ListView
This is the preference class...
import android.content.Context;
import android.preference.ListPreference;
import android.util.AttributeSet;
import android.view.View;
public class ListPreferenceLimitedMultiSelect extends ListPreference
{
int mLimit = 3;
LimitedMultiChoiceView mList = null;
String mSelection = "";
public ListPreferenceLimitedMultiSelect(Context context)
{
this(context, null);
} // ListPreferenceLimitedMultiSelect(Context context)
public ListPreferenceLimitedMultiSelect(Context context, AttributeSet attr)
{
super(context, attr);
} // ListPreferenceLimitedMultiSelect(Context context, AttributeSet attr)
#Override
protected void onBindDialogView(View v)
{
super.onBindDialogView(v);
mList.setSelection(mSelection);
} // void onBindDialogView(View v)
#Override
protected View onCreateDialogView()
{
mList = new LimitedMultiChoiceView(getContext()
, this.getEntries(), mLimit);
return(mList);
} // View onCreateDialogView()
#Override
protected void onDialogClosed(boolean positiveResult)
{
super.onDialogClosed(positiveResult);
if (positiveResult)
{
if (callChangeListener(mList.getSelection()))
{
mSelection = mList.getSelection();
persistString(mSelection);
} // (callChangeListener(mList.getSelection()))
} // (positiveResult)
} // void onDialogClosed(boolean positiveResult)
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue)
{
mSelection =(restoreValue ? getPersistedString(mSelection) : (String)"");
} // void onSetInitialValue(boolean restoreValue, Object defaultValue)
} // class ListPreferenceLimitedMultiSelect extends ListPreference
Thanks,
\ ^ / i l l