仿Iphone中搜索结果的布局详解
程序员文章站
2023-11-29 22:34:40
复制代码 代码如下:public class search extends linearlayout implements oncli...
复制代码 代码如下:
public class search extends linearlayout
implements onclicklistener, onkeylistener, onlongclicklistener, onitemclicklistener {
// speed at which the widget slides up/down, in pixels/ms.
private static final float animation_velocity = 1.0f;
/** the distance in dips between the optical top of the widget and the top if its bounds */
private static final float widget_top_offset = 9;
private final string tag = "searchwidget";
private launcher mlauncher;
private edittext msearchtext;
private imagebutton mvoicebutton;
private imagebutton mclearbutton;
/** the animation that morphs the search widget to the search dialog. */
private animation mmorphanimation;
/** the animation that morphs the search widget back to its normal position. */
private animation munmorphanimation;
// these four are passed to launcher.startsearch() when the search widget
// has finished morphing. they are instance variables to make it possible to update
// them while the widget is morphing.
private string minitialquery;
private boolean mselectinitialquery;
private bundle mappsearchdata;
private boolean mglobalsearch;
listview msearchresultlist=null;
linearlayout msearchresult=null;
// for voice searching
private intent mvoicesearchintent;
private int mwidgettopoffset;
private int malpha = 0xff;//2011-01-12 add for draw alpha
private arraylist<map<string, object>> mdata;
private lockscreenadapter madapter;
private list<info> datalist;
private context mcontext;
private static final string[] all_threads_projection = {
threads._id, threads.date, threads.message_count, threads.recipient_ids,
threads.snippet, threads.snippet_charset, threads.read, threads.error,
threads.has_attachment
};
private static final uri sallthreadsuri =
threads.content_uri.buildupon().appendqueryparameter("simple", "true").build();
/**
* used to inflate the workspace from xml.
*
* @param context the application's context.
* @param attrs the attributes set containing the workspace's customization values.
*/
public search(context context, attributeset attrs) {
super(context, attrs);
mcontext = context;
final float scale = context.getresources().getdisplaymetrics().density;
mwidgettopoffset = math.round(widget_top_offset * scale);
interpolator interpolator = new acceleratedecelerateinterpolator();
mmorphanimation = new toparentoriginanimation();
// no need to apply transformation before the animation starts,
// since the gadget is already in its normal place.
mmorphanimation.setfillbefore(false);
// stay in the top position after the animation finishes
mmorphanimation.setfillafter(true);
mmorphanimation.setinterpolator(interpolator);
mmorphanimation.setanimationlistener(new animation.animationlistener() {
// the amount of time before the animation ends to show the search dialog.
private static final long time_before_animation_end = 80;
// the runnable which we'll pass to our handler to show the search dialog.
private final runnable mshowsearchdialogrunnable = new runnable() {
public void run() {
showsearchdialog();
}
};
public void onanimationend(animation animation) { }
public void onanimationrepeat(animation animation) { }
public void onanimationstart(animation animation) {
// make the search dialog show up ideally *just* as the animation reaches
// the top, to aid the illusion that the widget becomes the search dialog.
// otherwise, there is a short delay when the widget reaches the top before
// the search dialog shows. we do this roughly 80ms before the animation ends.
gethandler().postdelayed(
mshowsearchdialogrunnable,
math.max(mmorphanimation.getduration() - time_before_animation_end, 0));
}
});
munmorphanimation = new fromparentoriginanimation();
// stay in the top position until the animation starts
munmorphanimation.setfillbefore(true);
// no need to apply transformation after the animation finishes,
// since the gadget is now back in its normal place.
munmorphanimation.setfillafter(false);
munmorphanimation.setinterpolator(interpolator);
munmorphanimation.setanimationlistener(new animation.animationlistener(){
public void onanimationend(animation animation) {
clearanimation();
}
public void onanimationrepeat(animation animation) { }
public void onanimationstart(animation animation) { }
});
mvoicesearchintent = new intent(android.speech.recognizerintent.action_web_search);
mvoicesearchintent.putextra(android.speech.recognizerintent.extra_language_model,
android.speech.recognizerintent.language_model_web_search);
}
/**
* implements onclicklistener.
*/
public void onvoiceclick(view v) {
/*if (v == mvoicebutton) {
startvoicesearch();
} else {
mlauncher.onsearchrequested();
}*/
}
public void onclick(view v) {//sxyang modified.
msearchtext.settext("");
msearchresult.setvisibility(view.invisible);
}
@override
public void onitemclick(adapterview<?> parent, view view, int position, long id) {
/**
log.w(tag, "view="+view+"position="+position+"id="+id);
map map = (map)madapter.getitem(position);
log.w(tag, "onitemclick title="+map.get("title")+" intent="+map.get("intent"));
intent intent = (intent) map.get("intent");
getcontext().startactivity(intent);
*/
}
private void startvoicesearch() {
try {
getcontext().startactivity(mvoicesearchintent);
} catch (activitynotfoundexception ex) {
// should not happen, since we check the availability of
// voice search before showing the button. but just in case...
log.w(tag, "could not find voice search activity");
}
}
/**
* sets the query text. the query field is not editable, instead we forward
* the key events to the launcher, which keeps track of the text,
* calls setquery() to show it, and gives it to the search dialog.
*/
public void setquery(string query) {
msearchtext.settext(query, textview.buffertype.normal);
}
/**
* morph the search gadget to the search dialog.
* see {@link activity#startsearch()} for the arguments.
*/
public void startsearch(string initialquery, boolean selectinitialquery,
bundle appsearchdata, boolean globalsearch) {
minitialquery = initialquery;
mselectinitialquery = selectinitialquery;
mappsearchdata = appsearchdata;
mglobalsearch = globalsearch;
showsearchdialog();
if (isattop()) {
// showsearchdialog();
} else {
// call up the keyboard before we actually call the search dialog so that it
// (hopefully) animates in at about the same time as the widget animation, and
// so that it becomes available as soon as possible. only do this if a hard
// keyboard is not currently available.
if (getcontext().getresources().getconfiguration().hardkeyboardhidden ==
configuration.hardkeyboardhidden_yes) {
inputmethodmanager inputmanager = (inputmethodmanager)
getcontext().getsystemservice(context.input_method_service);
// inputmanager.showsoftinputunchecked(0, null);
}
// start the animation, unless it has already started.
// if (getanimation() != mmorphanimation) {
// mmorphanimation.setduration(getanimationduration());
// startanimation(mmorphanimation);
// }
}
}
/**
* shows the system search dialog immediately, without any animation.
*/
private void showsearchdialog() {
log.d(tag, "showsearchdialog gettext="+msearchtext.gettext());
/*mlauncher.showsearchdialog(
minitialquery, mselectinitialquery, mappsearchdata, mglobalsearch);*/
}
/**
* restore the search gadget to its normal position.
*
* @param animate whether to animate the movement of the gadget.
*/
public void stopsearch(boolean animate) {
setquery("");
// only restore if we are not already restored.
if (getanimation() == mmorphanimation) {
if (animate && !isattop()) {
munmorphanimation.setduration(getanimationduration());
startanimation(munmorphanimation);
} else {
clearanimation();
}
}
}
private boolean isattop() {
return getwidgettop() == 0;
}
private int getanimationduration() {
return (int) (getwidgettop() / animation_velocity);
}
/**
* modify clearanimation() to invalidate the parent. this works around
* an issue where the region where the end of the animation placed the view
* was not redrawn after clearing the animation.
*/
@override
public void clearanimation() {
animation animation = getanimation();
if (animation != null) {
super.clearanimation();
if (animation.hasended()
&& animation.getfillafter()
&& animation.willchangebounds()) {
((view) getparent()).invalidate();
} else {
invalidate();
}
}
}
public boolean onkey(view v, int keycode, keyevent event) {
if (!event.issystem() &&
(keycode != keyevent.keycode_dpad_up) &&
(keycode != keyevent.keycode_dpad_down) &&
(keycode != keyevent.keycode_dpad_left) &&
(keycode != keyevent.keycode_dpad_right) &&
(keycode != keyevent.keycode_dpad_center)) {
// forward key events to launcher, which will forward text
// to search dialog
switch (event.getaction()) {
case keyevent.action_down:
return mlauncher.onkeydown(keycode, event);
case keyevent.action_multiple:
return mlauncher.onkeymultiple(keycode, event.getrepeatcount(), event);
case keyevent.action_up:
return mlauncher.onkeyup(keycode, event);
}
}
return false;
}
/**
* implements onlongclicklistener to pass long clicks on child views
* to the widget. this makes it possible to pick up the widget by long
* clicking on the text field or a button.
*/
public boolean onlongclick(view v) {
return performlongclick();
}
@override
protected void onfinishinflate() {
super.onfinishinflate();
msearchtext = (edittext) findviewbyid(r.id.search_src_text);
/**begin: add by liuzepeng **/
if(android.provider.settings.system.getint(mcontext.getcontentresolver(),android.provider.settings.system.isiphone,0) == 1) {
msearchtext.sethint(r.string.search_hint_iphone);
}
/**end: add by liuzepeng **/
mvoicebutton = (imagebutton) findviewbyid(r.id.search_voice_btn);//sxyang modified.
mclearbutton = (imagebutton) findviewbyid(r.id.search_clear_btn);//sxyang modified.
msearchtext.setonkeylistener(this);
//msearchtext.setonclicklistener(this);
mvoicebutton.setonclicklistener(this);
mclearbutton.setonclicklistener(this);//modified by liuzepeng
msearchtext.setonlongclicklistener(this);
mvoicebutton.setonlongclicklistener(this);
msearchresultlist = (listview)findviewbyid(r.id.searchresultview);
msearchresult = (linearlayout)findviewbyid(r.id.search_result);
msearchresult.setvisibility(view.gone);
/**
mdata = new arraylist<map<string, object>>();
madapter = new simpleadapter(getcontext(),
mdata,
r.layout.searchitem,
new string[]{"icon","title"},
new int[]{r.id.searchappicon,r.id.searchapptitle}
);
*/
/**
madapter.setviewbinder(new viewbinder(){
@override
public boolean setviewvalue(view view ,object data,string textrepresentation){
if(view instanceof imageview && data instanceof drawable){
imageview iv=(imageview)view;
iv.setimagedrawable((drawable)data);
return true;
}
return false;
}
});
*/
configurevoicesearchbutton();
configureclearsearchbutton();
msearchresultlist.setonscrolllistener(new onscrolllistener() {
@override
public void onscrollstatechanged(abslistview view, int scrollstate) {
inputmethodmanager inputmethodmanager = (inputmethodmanager)
getcontext().getsystemservice(context.input_method_service);
inputmethodmanager.hidesoftinputfromwindow(msearchresultlist.getwindowtoken(), 0);
}
@override
public void onscroll(abslistview view, int firstvisibleitem, int visibleitemcount, int totalitemcount) {}
});
if(cachednumbers == null)
cachednumbers = new hashmap<long, string>();
datalist = new arraylist<info>();
madapter = new lockscreenadapter(getcontext(), datalist);
msearchresultlist.setadapter(madapter);
msearchtext.addtextchangedlistener(new textwatcher(){
public void aftertextchanged(editable s) {}
public void beforetextchanged(charsequence s, int start, int count,int after) {}
public void ontextchanged(charsequence s, int start, int before,int count) {
datalist.clear();
if (s == null || s.tostring().equals("")|| msearchtext.gettext().tostring().trim() == null) {
msearchresult.setvisibility(view.invisible);
return;
}
if(mqueryhandler == null)
mqueryhandler = new searchqueryhandler(mlauncher.getcontentresolver());
string filter = s.tostring().replace("'",".");
startquery(mqueryhandler, filter);
}});
}
private static uri sallcanonical = uri.parse("content://mms-sms/canonical-addresses");
private static final int query_filtered_sms_token = 1000;
private static final int query_thread_id_token = 1001;
private static final int query_filtered_contacts_token = 1002;
private static final int query_favorites_token = 1003;
private static final int query_panel_token = 1004;
private static final int contacts_id_index = 0;
private static final int contacts_lookup_key_index = 1;
private static final int contacts_display_name_index = 2;
private static final int thread_id_index = 0;
private static final int recipient_ids_index = 3;
private static final int snippet_index = 4;
private static final int type_mms = 100;
private static final int type_contacts = 101;
private static final int type_favorites = 102;
private static final int type_panel = 103;
private static final int type_web = 104;
private searchqueryhandler mqueryhandler;
private map<long, string> cachednumbers;
private string[] contacts_filter_projection = new string[] {
contacts._id, // 0
contacts.lookup_key, // 1
contacts.display_name, // 2
};
/**
* the query order is:favorites->panel->mms->contacts. at last, add web search
* cancel all querying process and start a new
*/
public void startquery(asyncqueryhandler handler, string filter) {
handler.canceloperation(query_favorites_token);
handler.canceloperation(query_panel_token);
handler.canceloperation(query_thread_id_token);
handler.canceloperation(query_filtered_sms_token);
handler.canceloperation(query_filtered_contacts_token);
startqueryfavorites(mqueryhandler, query_favorites_token, " title like '%"+filter+"%'", null , filter);//query favorites
}
public void startqueryfavorites(asyncqueryhandler handler, int token,string selection,string[] selectionargs, string filter) {
//handler.canceloperation(token);
handler.startquery(token, filter, launchersettings.favorites.content_uri,
null, selection, selectionargs, null);
}
public void startquerypanel(asyncqueryhandler handler, int token,string selection,string[] selectionargs, string filter) {
//handler.canceloperation(token);
handler.startquery(token, filter, launchersettings.panel.content_uri, null, selection, selectionargs, null);
}
public void startquerythreadidfrommms(asyncqueryhandler handler, int token,string selection,string[] selectionargs, string filter) {
//handler.canceloperation(token);
handler.startquery(token, filter, threads.content_uri,
new string[]{conversations.thread_id}, selection, selectionargs, conversations.iphone_default_sort_order);
}
public void startqueryfilteredcontentfrommms(asyncqueryhandler handler, int token,string selection,string[] selectionargs, string filter) {
//handler.canceloperation(token);
handler.startquery(token, filter, sallthreadsuri,
all_threads_projection, selection, selectionargs, conversations.iphone_default_sort_order);
}
public void startqueryfromcontacts(asyncqueryhandler handler, int token, string[] projection, string selection,string[] selectionargs, string filter) {
handler.canceloperation(token);
handler.startquery(token, filter, uri.withappendedpath(contactscontract.contacts.content_filter_uri, filter),
projection, selection, selectionargs, "sort_key");
}
private final class searchqueryhandler extends asyncqueryhandler {
drawable mmsicon = null, contactsicon = null;
public searchqueryhandler(contentresolver contentresolver) {
super(contentresolver);
if(mmsicon == null)
mmsicon = getappicon("com.android.mms");
if(contactsicon == null)
contactsicon = getappicon("com.android.contacts");
}
@override
protected void onquerycomplete(int token, object cookie, cursor cursor) {
//if(cursor == null) return;
//datalist.clear();
switch (token) {
case query_filtered_sms_token:
list<iteminfo> iteminfolist = new arraylist<iteminfo>();
while(cursor.movetonext()) {
long threadid = cursor.getlong(thread_id_index);
string snippet = cursor.getstring(snippet_index);
string recipientids = cursor.getstring(recipient_ids_index);
string numbers = getaddresses(recipientids);
if(!textutils.isempty(snippet) && !textutils.isempty(numbers)) {
iteminfo iteminfo = new iteminfo();
string title = numbers;
intent intent = new intent();
intent.setdata(contenturis.withappendedid(threads.content_uri, threadid));
intent.setaction("android.intent.action.view");
intent.addcategory("android.intent.category.default");
intent.putextra("from", numbers);
//intent.putextra("inner", true);//deleted by sunjinbiao on 20120814 for bug[548]
if (title!= null ) {
msearchresult.setvisibility(view.visible);
iteminfo.title = title;
iteminfo.intent = intent;
}
iteminfolist.add(iteminfo);
}
}
//system.out.println("iteminfolist.size()="+iteminfolist.size());
if(iteminfolist.size()>0) {
info info = new info();
info.type = type_mms;
info.data = iteminfolist;
synchronized (datalist) {
datalist.add(info);
}
}
madapter.notifydatasetchanged();
string filter = (string)cookie;
if(isdigits(filter) && filter.length() > 3) {
startqueryfromcontacts(mqueryhandler, query_filtered_contacts_token, contacts_filter_projection, null, null, filter);//query contacts
} else if(!isdigits(filter)) {
startqueryfromcontacts(mqueryhandler, query_filtered_contacts_token, contacts_filter_projection, null, null, filter);//query contacts
}
break;
case query_thread_id_token:
string id = null;
while(cursor.movetonext()) {
if (id == null)
id = " _id = " + cursor.getlong(0);
else
id += " or _id = " + cursor.getlong(0);
}
if (id == null)
id = " _id = -1";
startqueryfilteredcontentfrommms(mqueryhandler, query_filtered_sms_token,id, null, (string)cookie);
break;
case query_filtered_contacts_token:
iteminfolist = new arraylist<iteminfo>();
if(cursor == null) break;
while(cursor.movetonext()) {
long contactid = cursor.getlong(contacts_id_index);
string lookupkey = cursor.getstring(contacts_lookup_key_index);
string name = cursor.getstring(contacts_display_name_index);
uri lookupuri = contacts.getlookupuri(contactid, lookupkey);
iteminfo iteminfo = new iteminfo();
string title = name;
intent intent = intent = new intent(intent.action_view, lookupuri);
if (title!= null ) {
msearchresult.setvisibility(view.visible);
iteminfo.title = title;
iteminfo.intent = intent;
iteminfolist.add(iteminfo);
}
}
if(iteminfolist.size()>0) {
info info = new info();
info.type = type_contacts;
info.data = iteminfolist;
synchronized (datalist) {
datalist.add(info);
}
}
addwebsearch((string)cookie);
break;
case query_favorites_token:
int titleindex = cursor.getcolumnindexorthrow(launchersettings.favorites.title);
int iconindex = cursor.getcolumnindexorthrow(launchersettings.favorites.icon);
int intentindex = cursor.getcolumnindexorthrow(launchersettings.favorites.intent);
intent intent=null;
packagemanager manager = getcontext().getpackagemanager();
drawable icon=null;
while (cursor.movetonext()) {
iteminfolist = new arraylist<iteminfo>();
iteminfo iteminfo = new iteminfo();
final string title = cursor.getstring(titleindex);
final string intentdescription = cursor.getstring(intentindex);
if(intentdescription == null)
continue;
try {
intent = intent.parseuri(intentdescription, 0);
} catch (java.net.urisyntaxexception e) {
}
icon = getapplicationsicons(manager, getcontext(), intent);
if (title!= null ) {
msearchresult.setvisibility(view.visible);
iteminfo.title = title;
iteminfo.intent = intent;
iteminfo.icon = icon;
iteminfolist.add(iteminfo);
}
if(iteminfolist.size()>0) {
info info = new info();
info.type = type_favorites;
info.data = iteminfolist;
synchronized (datalist) {
datalist.add(info);
madapter.notifydatasetchanged();
}
}
}
madapter.notifydatasetchanged();
startquerypanel(mqueryhandler, query_panel_token, " title like '%"+((string)cookie)+"%'", null , (string)cookie);//query panel
break;
case query_panel_token:
titleindex = cursor.getcolumnindexorthrow(launchersettings.panel.title);
iconindex = cursor.getcolumnindexorthrow(launchersettings.panel.icon);
intentindex = cursor.getcolumnindexorthrow(launchersettings.panel.intent);
intent=null;
manager = getcontext().getpackagemanager();
icon=null;
while (cursor.movetonext()) {
iteminfolist = new arraylist<iteminfo>();
iteminfo iteminfo = new iteminfo();
final string title = cursor.getstring(titleindex);
final string intentdescription = cursor.getstring(intentindex);
if(intentdescription == null)
continue;
try {
intent = intent.parseuri(intentdescription, 0);
} catch (java.net.urisyntaxexception e) {
//intent = null;
}
icon = getapplicationsicons(manager, getcontext(), intent);
if (title!= null ) {
msearchresult.setvisibility(view.visible);
iteminfo.title = title;
iteminfo.intent = intent;
iteminfo.icon = icon;
iteminfolist.add(iteminfo);
}
if(iteminfolist.size()>0) {
info info = new info();
info.type = type_panel;
info.data = iteminfolist;
synchronized (datalist) {
datalist.add(info);
madapter.notifydatasetchanged();
}
}
}
madapter.notifydatasetchanged();
startquerythreadidfrommms(mqueryhandler, query_thread_id_token," body like '%"+((string)cookie)+"%'", null, ((string)cookie));//query mms
break;
default:
log.e(tag, "onquerycomplete called with unknown token " + token);
}
cursor.close();
}
@override
protected void ondeletecomplete(int token, object cookie, int result) {}
}
private info mfootinfo = null;
private void addwebsearch(string filter) {
/**begin: add by liuzepeng **/
string edittext = msearchtext.gettext().tostring().trim();
//log.v("liuzepeng","filter:"+filter+"/msearchtext.gettext():"+msearchtext.gettext());
if(!edittext.equals(filter)) {
filter = edittext;
if(filter.equals("")) {
msearchresult.setvisibility(view.invisible);
return;
}
}
/**begin: add by liuzepeng **/
list<iteminfo> iteminfolist = new arraylist<iteminfo>();
iteminfo iteminfo = new iteminfo();
drawable icon = getappicon("com.android.browser");
uri uri = uri.parse("http://m.baidu.com/s?ie=utf-8&word="+filter);
resources re = getcontext().getresources();
string title = re.getstring(r.string.web_search);
intent intent = new intent(intent.action_view,uri);
if (title!= null ) {
msearchresult.setvisibility(view.visible);
iteminfo.title = title;
iteminfo.intent = intent;
iteminfo.icon = icon;
iteminfolist.add(iteminfo);
}
if(mfootinfo == null){
mfootinfo = new info();
mfootinfo.type = type_web;
}
mfootinfo.data = iteminfolist;
/**begin: modified by liuzepeng **/
if(!datalist.contains(mfootinfo)) {
datalist.add(mfootinfo);
} else {
datalist.remove(mfootinfo);
datalist.add(mfootinfo);
}
/**begin: modified by liuzepeng **/
madapter.notifydatasetchanged();
}
private drawable getappicon(string packagename) {
list<packageinfo> packages = getcontext().getpackagemanager().getinstalledpackages(0);
drawable appicon = null;
for (int i = 0; i < packages.size(); i++) {
packageinfo packageinfo = packages.get(i);
if(packageinfo.packagename.equals(packagename)) {
appicon = packageinfo.applicationinfo.loadicon(getcontext().getpackagemanager());
break;
}
}
return appicon;
}
public string getaddresses(string spacesepids) {
string numbers = "";
synchronized (cachednumbers) {
string[] ids = spacesepids.split(" ");
for (string id : ids) {
long longid;
try {
longid = long.parselong(id);
} catch (numberformatexception ex) {
// skip this id
continue;
}
string number = cachednumbers.get(longid);
if (number == null) {
getnumbers();
number = cachednumbers.get(longid);
}
if (textutils.isempty(number)) {
log.w(tag, "recipientid " + longid + " has empty number!");
} else {
numbers += number;
}
}
return numbers;
}
}
public void getnumbers() {
final contentresolver contentresolver = mlauncher.getcontentresolver();
cursor c = contentresolver.query(sallcanonical, null, null, null, null);
if (c == null) {
log.w(tag, "null cursor in fill()");
return;
}
try {
synchronized (cachednumbers) {
// technically we don't have to clear this because the stupid
// canonical_addresses table is never gc'ed.
cachednumbers.clear();
while (c.movetonext()) {
// todo: don't hardcode the column indices
long id = c.getlong(0);
string number = c.getstring(1);
cachednumbers.put(id, number);
}
}
} finally {
c.close();
}
}
private boolean isdigits(string str) {
if(str == null || "".equals(str))
return false;
int len = str.length();
for(int i=0;i<len;i++) {
char c = str.charat(i);
if(!character.isdigit(c))
return false;
}
return true;
}
private class info {
public int type;
public list<iteminfo> data;
public string tostring() {
return "type="+type;
}
}
private class iteminfo {
public drawable icon;
public string title;
public intent intent;
public string tostring() {
return "title="+title;
}
}
class lockscreenadapter extends baseadapter {
private context context;
list<info> data;
layoutinflater inflater;
drawable mmsicon = null, contactsicon = null;
public lockscreenadapter(context acontext,list<info> adata) {
context = acontext;
inflater = layoutinflater.from(context);
data = adata;
if(mmsicon == null)
mmsicon = getappicon("com.android.mms");
if(contactsicon == null)
contactsicon = getappicon("com.android.contacts");
}
public int getcount() {
return data.size();
}
public object getitem(int position) {
return data.get(position);
}
public long getitemid(int position) {
return position;
}
public view getview(int position, view convertview, viewgroup parent) {
convertview = inflater.inflate(r.layout.item_launcher_search, null);
if((position+1)%2 == 0 ){
convertview.setbackgrounddrawable(getresources().getdrawable(r.drawable.result0));
}else{
convertview.setbackgrounddrawable(getresources().getdrawable(r.drawable.result1));
}
int wrapcontent = linearlayout.layoutparams.wrap_content;
int fillparent = linearlayout.layoutparams.fill_parent;
linearlayout.layoutparams contentsllp = new linearlayout.layoutparams(fillparent, wrapcontent);
linearlayout contents = (linearlayout) convertview.findviewbyid(r.id.contents);
imageview icon = (imageview) convertview.findviewbyid(r.id.icon);
info info = data.get(position);
int type = info.type;
int size = info.data.size();
for (int i = 0; i < size; i++) {
iteminfo iteminfo = info.data.get(i);
contents.addview(createitemview(iteminfo), contentsllp);
if(type == type_mms)
icon.setbackgrounddrawable(mmsicon);
else if(type == type_contacts)
icon.setbackgrounddrawable(contactsicon);
else
icon.setbackgrounddrawable(iteminfo.icon);
if(size>1 && i!=size -1){
textview hline = new textview(getcontext());
linearlayout.layoutparams hlinellp = new linearlayout.layoutparams(fillparent, wrapcontent);
hlinellp.height = 1;
hline.setbackgroundcolor(color.argb(255, 157, 157, 160));
contents.addview(hline, hlinellp);
textview bline = new textview(getcontext());
bline.setbackgroundcolor(color.argb(255, 255, 255, 255));
contents.addview(bline, hlinellp);
}
}
return convertview;
}
}
linearlayout createitemview(final iteminfo iteminfo) {
final context cxt = getcontext();
linearlayout contentlayout = new linearlayout(cxt);
textview seperatorline = new textview(cxt);
textview content = new textview(cxt);
int wrapcontent = linearlayout.layoutparams.wrap_content;
int fillparent = linearlayout.layoutparams.fill_parent;
linearlayout.layoutparams seperatorlinellp = new linearlayout.layoutparams(wrapcontent, 45);
seperatorlinellp.rightmargin = 50;
seperatorlinellp.height = 70;
linearlayout.layoutparams contentllp = new linearlayout.layoutparams(fillparent, 45);
contentllp.gravity=gravity.center_vertical;
contentllp.leftmargin = 5;
seperatorline.setbackgroundresource(r.drawable.launcher_item_vertical_line);
content.settext(iteminfo.title);
content.settextcolor(color.black);
content.setgravity(gravity.center_vertical);
contentlayout.setorientation(linearlayout.horizontal);
contentlayout.addview(seperatorline, seperatorlinellp);
contentlayout.addview(content, contentllp);
contentlayout.setbackgroundresource(r.drawable.search_item_press);
contentlayout.setonclicklistener(new onclicklistener() {
@override
public void onclick(view v) {
cxt.startactivity(iteminfo.intent);
}
});
return contentlayout;
}
@override
public void ondetachedfromwindow() {
super.ondetachedfromwindow();
}
/**
* if appropriate & available, configure voice search
*
* note: because the home screen search widget is always web search, we only check for
* getvoicesearchlaunchwebsearch() modes. we don't support the alternate form of app-specific
* voice search.
*/
private void configurevoicesearchbutton() {
// enable the voice search button if there is an activity that can handle it
packagemanager pm = getcontext().getpackagemanager();
resolveinfo ri = pm.resolveactivity(mvoicesearchintent,
packagemanager.match_default_only);
boolean voicesearchvisible = ri != null;
// finally, set visible state of voice search button, as appropriate
mvoicebutton.setvisibility(voicesearchvisible ? view.visible : view.gone);
}
private void configureclearsearchbutton() {
//sxyang modified.
msearchtext.addtextchangedlistener(new textwatcher(){
public void aftertextchanged(editable s) {}
public void beforetextchanged(charsequence s, int start, int count,int after) {}
public void ontextchanged(charsequence s, int start, int before,int count) {
if (s == null || s.tostring().equals("")) {
mclearbutton.setvisibility(view.invisible);
} else {
mclearbutton.setvisibility(view.visible);
}
}});
}
/**
* sets the {@link launcher} that this gadget will call on to display the search dialog.
*/
public void setlauncher(launcher launcher) {
mlauncher = launcher;
}
/**
* moves the view to the top left corner of its parent.
*/
private class toparentoriginanimation extends animation {
@override
protected void applytransformation(float interpolatedtime, transformation t) {
float dx = -getleft() * interpolatedtime;
float dy = -getwidgettop() * interpolatedtime;
t.getmatrix().settranslate(dx, dy);
}
}
/**
* moves the view from the top left corner of its parent.
*/
private class fromparentoriginanimation extends animation {
@override
protected void applytransformation(float interpolatedtime, transformation t) {
float dx = -getleft() * (1.0f - interpolatedtime);
float dy = -getwidgettop() * (1.0f - interpolatedtime);
t.getmatrix().settranslate(dx, dy);
}
}
/**
* the widget is centered vertically within it's 4x1 slot. this is
* accomplished by nesting the actual widget inside another view. for
* animation purposes, we care about the top of the actual widget rather
* than it's container. this method return the top of the actual widget.
*/
private int getwidgettop() {
return gettop() + getchildat(0).gettop() + mwidgettopoffset;
}
/*
* //2011-01-12 add for draw alpha
*/
public boolean setalpha(int alpha) {
if (malpha != alpha) {
malpha = alpha;
drawable background = findviewbyid(r.id.search_plate).getbackground();
//drawable background = findviewbyid(r.id.search_plate).getbackground();
if (background != null) {
background.setalpha(alpha);
} else {
log.d(tag, "background null");
}
background = findviewbyid(r.id.search_src_text).getbackground();
if (background != null) {
if (background instanceof statelistdrawable) {
statelistdrawable statedrawable = (statelistdrawable)background;
int statecount = statedrawable.getstatecount();
for (int i = 0; i < statecount; i++) {
drawable d = statedrawable.getstatedrawable(i);
d.setalpha(alpha);
}
} else {
background.setalpha(alpha);
}
} else {
log.d(tag, "background null");
}
this.invalidate();
return true;
}
return false;
}
/**
* morph the search gadget to the search dialog.
* see {@link activity#startsearch()} for the arguments.
*/
public void showstartsearch() {
//msearchtext.settext("", textview.buffertype.normal);
//msearchresult.setvisibility(view.gone);
if(msearchresult.getvisibility() != view.visible) {
msearchtext.requestfocus();
log.d(tag, "showstartsearch");
if (getcontext().getresources().getconfiguration().hardkeyboardhidden ==
configuration.hardkeyboardhidden_yes) {
inputmethodmanager inputmanager = (inputmethodmanager)
getcontext().getsystemservice(context.input_method_service);
inputmanager.showsoftinputunchecked(0, null);
}
}
}
private drawable getapplicationsicons(packagemanager manager,context context, intent intent){
drawable icon=null;
final resolveinfo resolveinfo = manager.resolveactivity(intent, 0);
if(resolveinfo == null) return null;
final activityinfo activityinfo = resolveinfo.activityinfo;
drawable customericon = utilities.getcustomericon(context, intent);
if(customericon != null){
icon = utilities.createiconthumbnail(customericon, context);
} else {
icon = utilities.createiconthumbnail(activityinfo.loadicon(manager), context);
}
bitmap bitmap = utilities.createmiddleicon(icon,context);
bitmapdrawable bd = new bitmapdrawable(bitmap);
return bd;
}
}
<com.hskj.hometest.search
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher2"
android:id="@+id/widget_search"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="top">
<linearlayout
android:id="@+id/search_plate"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingleft="14dip"
android:paddingright="4dip"
android:paddingtop="5dip"
android:layout_marginleft="10dip"
android:layout_marginright="10dip"
android:background="@drawable/textfield_searchwidget" >
<edittext
android:id="@+id/search_src_text"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:textsize="15sp"
android:paddingleft="16dip"
android:hint="@string/search_hint"
android:singleline="true"
android:background="@android:color/transparent"
android:textappearance="?android:attr/textappearancemediuminverse"
android:textcolor="@android:color/primary_text_light"
/>
<imagebutton
android:id="@+id/search_clear_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginright="0dip"
android:background="@drawable/iphone_clean_icon"
/>
<imagebutton
android:id="@+id/search_voice_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginleft="4dip"
android:background="@*android:drawable/btn_search_dialog_voice"
android:src="@*android:drawable/ic_btn_speak_now"
/>
</linearlayout>
<linearlayout android:id="@+id/search_result"
android:layout_weight="1"
android:layout_height="0dip"
android:layout_width="fill_parent"
android:layout_margintop="5dip"
android:layout_marginleft="10dip"
android:layout_marginright="11dip"
android:background="@drawable/search_list_bg">
<listview android:layout_width="fill_parent"
android:id="@+id/searchresultview"
android:scrollbars="vertical"
android:listselector="@android:color/transparent"
android:cachecolorhint="#00000000"
android:divider="#cccccc"
android:dividerheight="1px"
android:layout_height="fill_parent"
android:fadingedge="none" >
</listview>
</linearlayout>
</com.hskj.hometest.search>
<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="horizontal">
<imageview android:id="@+id/icon" android:layout_width="30dip"
android:layout_height="30dip"
android:layout_margin="5dip" />
<linearlayout android:id="@+id/contents"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_gravity="center_vertical"
android:layout_torightof="@id/icon">
</linearlayout>
</relativelayout>
推荐阅读