getmap is deprecated getMapAsync doesnt work - google-maps-android-api-2

My app call getmap() method and notice that is depracated and I've to use getMapAsync() instead, however I've read all posts everywhere on the internet and none helped me. Sometimes I got "null pointer return message". I'll hope someone help me to do that.....
My MapFragment.java:
private void setUpMapIfNeeded() {
if (map == null) {
map = ((MapView) view.findViewById(R.id.map)).getMap();
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
map.setMyLocationEnabled(false);
map.getUiSettings().setMyLocationButtonEnabled(false);
map.getUiSettings().setZoomControlsEnabled(false);
btnMyLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Location loc = map.getMyLocation();
if (myLocation != null) {
LatLng latLang = new LatLng(myLocation.getLatitude(),
myLocation.getLongitude());
animateCameraToMarker(latLang, true);
}
}
});
map.setOnCameraChangeListener(new OnCameraChangeListener() {
public void onCameraChange(CameraPosition camPos) {
if (currentZoom == -1) {
currentZoom = camPos.zoom;
} else if (camPos.zoom != currentZoom) {
currentZoom = camPos.zoom;
return;
}
if (!isMapTouched) {
curretLatLng = camPos.target;
if (!isAddDestination) {
// layoutMarker.setVisibility(LinearLayout.VISIBLE);
if (listType.size() > 0) {
stopUpdateProvidersLoaction();
getAllProviders(curretLatLng);
}
getAddressFromLocation(camPos.target, etSource);
}
}
isMapTouched = false;
}
});
}
}
The onCreateView:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
...
setUpMapIfNeeded();
...
return view;
}
My fragment_map.xml
<FrameLayout
android:id="#+id/mapFrameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:visibility="visible" >
<com.google.android.gms.maps.MapView
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />

Related

Now that FusedLocationApi is deprecated how can i implement FusedLocationProvideClient when i also have location listener?

I'm building a class that tracks orders origin to deliver packages, im getting an error message that states that FusedLocationProviderApi is deprecated and seems now i have to use FusedLocationProviderClient instead, when i applied FusedLocationProviderApi i also implemented a LocationListener a ConnectionCallback and GoogleaApiClient which i suppose should be removed.
how can i implemente this here
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tracking_order);
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
requestRuntimePermission();
}
else
{
if (checkPlayServices())
{
buildGoogleApiClient();
createLocationRequest();
}
}
displayLocation();
}
private void displayLocation() {
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
requestRuntimePermission();
}
else
{
mLastLocation = LocationServices.fused(null).getLastLocation(mGoogleApiClient);
if (mLastLocation != null)
{
double latitude = mLastLocation.getLatitude();
double longitude = mLastLocation.getLongitude();
LatLng yourLocation = new LatLng(latitude,longitude);
mMap.addMarker(new MarkerOptions().position(yourLocation).title("Tu ubicacion"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(yourLocation));
mMap.animateCamera(CameraUpdateFactory.zoomTo(17.0f));
}
else
{
Toast.makeText(this, "No se pudo obtener ubicacion", Toast.LENGTH_SHORT).show();
}
}
}
ended up with a new approach that worked finer
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tracking_order);
mService = Common.geoCodeService();
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mapFrag = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
mapFrag.getMapAsync(this);
}
public void onMapReady(GoogleMap googleMap)
{
mMap=googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(120000); // two minute interval
mLocationRequest.setFastestInterval(120000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Location Permission already granted
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
mMap.setMyLocationEnabled(true);
} else {
//Request Location Permission
checkLocationPermission();
}
}
else {
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
mMap.setMyLocationEnabled(true);
}
}
LocationCallback mLocationCallback = new LocationCallback(){
#Override
public void onLocationResult(LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
Log.i("MapsActivity", "Location: " + location.getLatitude() + " " + location.getLongitude());
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//Place current location marker
LatLng yourLocation = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(yourLocation);
markerOptions.title("Current Position");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
mCurrLocationMarker = mMap.addMarker(markerOptions);
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(yourLocation, 11));
//after add marker for your location add marker for this order
drawRoute(yourLocation,Common.currentRequest.getAddress());
}
}
};

Camera in Android app

I am creating an app which required to perform from API 15 to API 23 using camera so what should be the best way to implement camera as camera class is deprecated in API 21 and also android.hardware.camera2 not able to implement on lower version then API 21.
The below code is something I have taken out of one of my projects, it has had a lot of stuff ripped out for the purpose of putting it on here so you will have to edit it for your needs. It uses the original camera api which is back compatible for your api needs.
public class RecordGameKam extends Fragment
implements TextureView.SurfaceTextureListener, View.OnClickListener {
private final static String TAG = "CameraRecordTexture";
private Camera mCamera;
private TextureView mTextureView;
int numberOfCameras;
int defaultCameraId;
private boolean isRecording = false;
protected MediaRecorder mediaRecorder;
#SuppressWarnings("ConstantConditions")
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
View rootView = new RelativeLayout(getActivity());
mTextureView = new TextureView(getActivity());
mTextureView.setSurfaceTextureListener(this);
//View parameters-----------------------------------------------------------------------
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
rootView.setLayoutParams(params);
((ViewGroup) rootView).addView(mTextureView);
return rootView;
}
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
// Find the total number of cameras available
numberOfCameras = Camera.getNumberOfCameras();
// Find the ID of the default camera
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
defaultCameraId = i;
}
}
try {
if (mCamera != null) {
//final Camera.Size previewSize = onMeasure();
//Camera.Size recorderSize = previewSize;
final Camera.Parameters params = mCamera.getParameters();
params.setPreviewSize(720, 480);
mCamera.setParameters(params);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
startContinuousAutoFocus();
}
} catch (IOException ioe) {
// Something bad happened
mCamera.release();
mCamera = null;
}
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, Camera does all the work for us
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
try {
if (getActivity().getActionBar() != null) {
getActivity().getActionBar().show();
}
} catch (Exception e) {
e.printStackTrace();
}
releaseMediaRecorder();
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Invoked every time there's a new Camera preview frame
}
private boolean setMediaRecorder() throws IllegalStateException {
try {
//Create a new instance of MediaRecorder.
mediaRecorder = new MediaRecorder();
//Unlock and set camera to Media recorder
mCamera.unlock();
mediaRecorder.setCamera(mCamera);
//Configure audio/video input
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
CamcorderProfile profile = null;
if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P)) {
profile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
}
if (profile != null) {
mediaRecorder.setProfile(profile);
}
//Change oritentation
mediaRecorder.setOrientationHint(90 - 180 + 360);
mediaRecorder.setOutputFile(getFilename());
} catch (Exception e) {
e.printStackTrace();
}
//Attempt to prepare the configuration and record video.
try {
button.setBackgroundResource(R.drawable.camera_pressed);
mediaRecorder.prepare();
} catch (Exception e) {
e.printStackTrace();
mediaRecorder.release();
return false;
}
return true;
}
boolean startContinuousAutoFocus() {
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
assert focusModes != null;
String CAF_PICTURE = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
CAF_VIDEO = Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
supportedMode = focusModes
.contains(CAF_PICTURE) ? CAF_PICTURE : focusModes
.contains(CAF_VIDEO) ? CAF_VIDEO : "";
if (!supportedMode.equals("")) {
params.setFocusMode(supportedMode);
mCamera.setParameters(params);
return true;
}
return false;
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
enter code here

Libstreaming: Can we perform zoom in and out in camera on surfaceview as well as on-touch Focus circle and Flash in camera preview?

I am developing an android application using libstreaming streaming library. The app is sending upstream on Wowza (Mobile to Wowza). I created one surfaceview which has the camera preview. It's working fine but I want to add three functionalities (Zoom in/out, Autofous and Flash).
I don't know whether it is possible with Libstreaming.
SurfaceView which I have used, belongs to
package net.majorkernelpanic.streaming.gl.SurfaceView.
Below is my Activity code:
public class LiveStreamingActivity extends Activity implements RtspClient.Callback, Session.Callback, SurfaceHolder.Callback {
private static SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
private Session mSession;// Rtsp session
private static RtspClient mClient;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
if (!LibsChecker.checkVitamioLibs(this))
return;
mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#SuppressWarnings("deprecation")
private void initRtspClient() {
// Configures the SessionBuilder
mSession = SessionBuilder
.getInstance()
.setContext(getApplicationContext())
.setAudioEncoder(SessionBuilder.AUDIO_AAC)
.setAudioQuality(new AudioQuality(8000, 16000))
.setVideoEncoder(SessionBuilder.VIDEO_H264)
//.setVideoQuality(new VideoQuality(352, 288, 30, 300000))
.setCamera(CameraInfo.CAMERA_FACING_BACK)
.setSurfaceView(mSurfaceView).setPreviewOrientation(0)
.setCallback(this).build();
mClient = new RtspClient();
mClient.setSession(mSession);
mClient.setCallback(this);
mClient.setTransportMode(RtspClient.TRANSPORT_TCP);
mSurfaceView.setAspectRatioMode(SurfaceView.ASPECT_RATIO_PREVIEW);
String ip, port, path;
Pattern uri = Pattern.compile("rtsp://(.+):(\\d+)/(.+)");
Matcher m = uri.matcher("rtsp://219.65.90.226:1935/app2/myStream");
m.find();
ip = m.group(1);
port = m.group(2);
path = m.group(3);
mClient.setCredentials(AppConfig.PUBLISHER_USERNAME,
AppConfig.PUBLISHER_PASSWORD);
mClient.setServerAddress(ip, Integer.parseInt(port));
mClient.setStreamPath("/" + path);
}
#Override
protected void onResume() {System.out.println("on Resume activity 2");
super.onResume();
try{
if(null != mSurfaceView){
/* Broadcastreceiver: check network connectivity */
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(receiver, intentFilter);
/* Start audio streaming background thread: AsyncTask */
vmPlayer = null;
vmPlayer = new MediaPlayer(this);
audioStream= new AudioStreamTask(this);
audioStream.execute("push","push","push");
}
}catch(Exception ex){
ex.printStackTrace();
}
}
#Override
protected void onPause() {
super.onPause();
try{
/* release the surface view */
if(null != mSurfaceView){
mClient.release();
mSession.release();
mSurfaceView.getHolder().removeCallback(this);
}
}catch(Exception ex){
ex.printStackTrace();
}
}
#Override
public void onDestroy() {
try {
super.onDestroy();
if (mClient != null) {
mClient.release();
}
if (mSession != null) {
mSession.release();
}
mSurfaceView.getHolder().removeCallback(this);
} catch (Exception e) {
System.out.println("Error while destroying activity " + e);
}
}
private void toggleStreaming() {
if (!mClient.isStreaming()) {
// Start camera preview
mSession.startPreview();
// mFrontSession.startPreview();
// Start video stream
mClient.startStream();
//startRtmpStream();
} else {
// already streaming, stop streaming
// stop camera preview
mSession.stopPreview();
// mFrontSession.stopPreview();
// stop streaming
mClient.stopStream();
}
}}
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/surface_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/surface_view_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:orientation="vertical" >
<net.majorkernelpanic.streaming.gl.SurfaceView
android:id="#+id/surface_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center" />
</LinearLayout></FrameLayout>
I need complete description to add all these three camera features.
I did it! :)
Go to VideoStream.Java and change:
protected Camera mCamera to public static Camera mCamera.
Go to your MainActivity, in your case LiveStreamingActivity and paste:
private float mDist;
#Override
public boolean onTouchEvent(MotionEvent event) {
// Get the pointer ID
Camera.Parameters params = VideoStream.mCamera.getParameters();
int action = event.getAction();
if (event.getPointerCount() > 1) {
// handle multi-touch events
if (action == MotionEvent.ACTION_POINTER_DOWN) {
mDist = getFingerSpacing(event);
} else if (action == MotionEvent.ACTION_MOVE && params.isZoomSupported()) {
VideoStream.mCamera.cancelAutoFocus();
handleZoom(event, params);
}
} else {
// handle single touch events
if (action == MotionEvent.ACTION_UP) {
handleFocus(event, params);
}
}
return true;
}
private void handleZoom(MotionEvent event, Camera.Parameters params) {
int maxZoom = params.getMaxZoom();
int zoom = params.getZoom();
float newDist = getFingerSpacing(event);
if (newDist > mDist) {
//zoom in
if (zoom < maxZoom)
zoom++;
} else if (newDist < mDist) {
//zoom out
if (zoom > 0)
zoom--;
}
mDist = newDist;
params.setZoom(zoom);
VideoStream.mCamera.setParameters(params);
}
public void handleFocus(MotionEvent event, Camera.Parameters params) {
int pointerId = event.getPointerId(0);
int pointerIndex = event.findPointerIndex(pointerId);
// Get the pointer's current position
float x = event.getX(pointerIndex);
float y = event.getY(pointerIndex);
List<String> supportedFocusModes = params.getSupportedFocusModes();
if (supportedFocusModes != null && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
VideoStream.mCamera.autoFocus(new Camera.AutoFocusCallback() {
#Override
public void onAutoFocus(boolean b, Camera camera) {
// currently set to auto-focus on single touch
}
});
}
}
/**
* Determine the space between the first two fingers
*/
private float getFingerSpacing(MotionEvent event) {
// ...
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
Based here.
Let me know if it helped!
Thank you #José Cunha Fonte your code is great!
For me (Works with Marshmallow SDK) return FloatMath.sqrt(x * x + y * y); is deprecated and gone, so I just changed to return (float)Math.sqrt(x * x + y * y);
Hope it will help someone :)

GetChildView gets not called

I have searched similar threads but they didn't help me and they were light different or they still are unanswered, so I'll describe my trouble.
I have an ExpandableListView with a custom ExpandableListAdapter and I can show my Groups but not my Children. GetChildView don't get called anyway.
I would thank you for your Help.
EDIT:
If I log this section
...
client = (ExpandableListView)row.findViewById(R.id.field_expandable_list);
client.setFocusable(false);
client_adapter = new ClientAdapter(context, titles, allFields);
client.setAdapter(client_adapter);
Log.i("TAG", "WmsMApActivity::doClient:: Adapter #children: "+client_adapter.getChildrenCount(0)+
" ExpListView #children: "+client.getChildCount());
...
, then I get that
I/TAG(692): WmsMApActivity::doClient::0 Adapter #children: 13 ExpListView #children: 0
So, my Adapter gets Data but the variable client (ExpandableListView) don't realize, it has data although I properly set it.
My code is the following
Main Code
// view = Item of my ListView. We come from a OnClickItem Method
private void doClient(View view) {
ArrayList<String> titles = new ArrayList<String>();
titles.add("fields");
ArrayList allFields = transformFarmsResult(parentItems);
final Context context = getApplicationContext();
RelativeLayout mainLayout = (RelativeLayout) view.findViewById(R.id.relLayoutDrawer);
// We check whether the first item (0th position) is expanded
View lin_layout_field_list = view.findViewById(R.id.lin_layout_field_list);
if ( lin_layout_field_list != null ) { // Hide Field_list Layout
((ViewGroup) view).removeView(lin_layout_field_list);
} else {
mainLayout = (RelativeLayout) view.findViewById(R.id.relLayoutDrawer);
// ----------- Inflating ExpandableListView "Fields"
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.field_list, null);
client = (ExpandableListView)row.findViewById(R.id.field_expandable_list);
// Adapter Population
client_adapter = new ClientAdapter(context, titles, allFields);
client.setAdapter(client_adapter);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
TextView title_tv = (TextView)view.findViewById(R.id.title);
params.addRule(RelativeLayout.ALIGN_LEFT, title_tv.getId() );
params.addRule(RelativeLayout.BELOW, title_tv.getId());
mainLayout.addView(row, params);
// Listview Group click listener
client.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
Toast.makeText(context, "Group Clicked " + groupPosition, Toast.LENGTH_SHORT).show();
return false;
}
});
// Listview Group expanded listener
client.setOnGroupExpandListener(new OnGroupExpandListener() {
#Override
public void onGroupExpand(int groupPosition) {
Toast.makeText(context, "Group " + groupPosition + " Expanded", Toast.LENGTH_SHORT).show();
}
});
// Listview Group collasped listener
client.setOnGroupCollapseListener(new OnGroupCollapseListener() {
#Override
public void onGroupCollapse(int groupPosition) {
Toast.makeText(context, "Group " + groupPosition + " Collapsed", Toast.LENGTH_SHORT).show();;
}
});
// Listview on child click listener
client.setOnChildClickListener(new OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
// TODO Auto-generated method stub
Toast.makeText(context, "Group " + groupPosition + " : Child " + childPosition, Toast.LENGTH_SHORT).show();
return false;
}
});
}
}
Adapter
public class ClientAdapter extends BaseExpandableListAdapter{
private Context context;
//private String header_title;
private ArrayList<String> headers;
private ArrayList fields;
private int groupPosition = 0;
private LayoutInflater inflater;
public ClientAdapter(Context context, ArrayList<String> headers, ArrayList fields) {
this.context = context;
this.headers = headers;
this.fields = fields;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Just to check, whether I get correct ArrayList "fields"
Log.i("TAG","ClientAdapter::Constructor:: fields.size: "+fields.size());
for (int i=0;i<fields.size();i++)
Log.i("TAG","ClientAdapter::Constructor:: field["+i+"]: "+fields.get(i).toString());
}
#Override
public int getGroupCount() {
// Just 1 Group
return headers.size();
}
#Override
public String getGroup(int groupPosition) {
return headers.get(groupPosition);
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view = convertView;
GroupHolder holder=null;
String title_item = getGroup(groupPosition);
if ( view == null ) {
holder = new GroupHolder();
view = inflater.inflate(R.layout.group_client, null);
holder.title = (TextView) view.findViewById(R.id.client_group_title);
view.setTag(holder);
} else {
holder = (GroupHolder) view.getTag();
}
holder.title.setText(title_item);
return view;
}
// Children
#Override
public int getChildrenCount(int groupPosition) {
return fields.size();
}
#Override
public Object getChild(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return fields.get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view = convertView;
ChildHolder holder;
Log.i("TAG", "ClientAdapter::getChildView:: 0 - parent.id: "+parent.getId());
final HashMap<String,Object> field = (HashMap<String,Object>) getChild(groupPosition, childPosition);
if (view == null) {
holder = new ChildHolder();
view = inflater.inflate(R.layout.child_client, null);
holder.title = (TextView) view.findViewById(R.id.client_child_title);
holder.map_icon = (ImageView) view.findViewById(R.id.client_child_icon);
holder.contour = (CheckBox) view.findViewById(R.id.client_child_checkbox);
convertView.setTag(holder);
} else {
holder = (ChildHolder) view.getTag();
}
// Handling of Title
String temp =(String)field.get(Constants._FIELDNAME);
Log.i("TAG", "ClientAdapter::getChildView:: title: "+temp);
holder.title.setText((String)field.get(Constants._FIELDNAME));
// Handling of Contour - If it exists!
if ( field.containsKey(Constants._BOUNDARY)) {
holder.contour.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (((CheckBox)v).isChecked()) {
Toast.makeText(context, "Contour enabled", Toast.LENGTH_LONG).show();
// TODO : Fade-in Contour in Graphics
} else {
Toast.makeText(context, "Contour disabled", Toast.LENGTH_LONG).show();
// TODO : Fade-in Contour in Graphics
}
}
});
} else { // If there is no Contour, remains the checkbox but it's not clickable, so, it's grey!
holder.contour.setFocusable(false);
holder.contour.setClickable(false);
}
// Handling of Map Icon
Bitmap bitmap_icon = BitmapFactory.decodeResource(context.getResources(), R.drawable.gmaps_icon_24);
holder.map_icon.setImageBitmap(bitmap_icon);
// Applying gray filter if not referentiable
if ( !field.containsKey(Constants._LATITUDE) || !field.containsKey(Constants._LONGITUDE))
holder.map_icon.setColorFilter(Color.GRAY);
holder.map_icon.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if ( field.containsKey(Constants._LATITUDE) && field.containsKey(Constants._LONGITUDE)) {
Toast.makeText(context, "Center in Field Position", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, Constants.NOT_CENTRED, Toast.LENGTH_LONG).show();
}
}
});
return view;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return true;
}
#Override
public boolean hasStableIds() {
return true;
}
/** Events **/
/** Holder Classes **/
private static class ChildHolder {
TextView title;
ImageView map_icon;
CheckBox contour;
}
private static class GroupHolder {
TextView title;
}
}
My Layouts.
Main xml. field_list.xml -> Layout for ExpandableListView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lin_layout_field_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ExpandableListView
android:id="#+id/field_expandable_list"
android:layout_width="match_parent"
android:layout_height="0dp" <- That's a SO advice, in order that children won't be croped. Originally wrap_content
android:layout_weight="1"
android:headerDividersEnabled="true"
android:divider="#color/metallic_silver"
android:dividerHeight="1dp">
</ExpandableListView>
</LinearLayout>
Group_client.xml -> Layout for each Group Item
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/lin_layout_client_group"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/client_group_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="30dp"
android:text="Something"
android:textColor="#android:color/white"
android:textSize="16dp"
android:textStyle="normal" />
</LinearLayout>
</LinearLayout>
child_client.xml -> Layout for each Child Item
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/lin_layout_client_child"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<CheckBox
android:id="#+id/client_child_checkbox"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.05"
android:checked="true"
android:gravity="center_vertical|center" />
<TextView
android:id="#+id/client_child_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="10dp"
android:text="FIELD_NAME"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#android:color/white"
android:layout_weight="0.90" />
<ImageView
android:id="#+id/client_child_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.05"
android:layout_margin="5dp"
android:gravity="center_vertical|center"
android:src="#drawable/gmaps_icon_24" />
</LinearLayout>
</LinearLayout>
EDIT(2):
As said, it's no problem cause of Layouts or ClientAdapter, so that it works fine in this example
public class ClientActivity2 extends Activity{
private ExpandableListView client;
private ClientAdapter client_adapter;
private ArrayList children;
private ArrayList<String> groups;
private LayoutInflater inflater;
private LinearLayout lin_layout_probe;
private Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.field_list);
context = getApplicationContext();
prepareData();
ExpandableListView client = (ExpandableListView)findViewById(R.id.field_expandable_list);
client_adapter = new ClientAdapter(context, groups, children);
client.setAdapter(client_adapter);
client.expandGroup(0);
}
private void prepareData() {
children = new ArrayList();
HashMap<String,Object> hm1 = new HashMap<String,Object>();
hm1.put(Constants._FIELDNAME,"Child1");
children.add(hm1);
HashMap<String,Object> hm2 = new HashMap<String,Object>();
hm2.put(Constants._FIELDNAME,"Child2");
children.add(hm2);
HashMap<String,Object> hm3 = new HashMap<String,Object>();
hm3.put(Constants._FIELDNAME,"Child3");
children.add(hm3);
groups = new ArrayList<String>();
groups.add("Group1");
}
}
Now it comes what confuses me...
If I test all(Adapter and the same calls) with a simple Activity, which has a clickable TextView at its main layout then works fine!
If I click this TextView then the ExpandableListView prompts with properly populated Group and Children and they are expandable/collapsable.
If I test like my last post hier,(ExpandableListView embedded in a ListView Item) so, the ExpandableListView prompts, if I click that the ExpandableListView of that Item
then the groups are populated but not the children. GetChildView gets never called!!!(I used LogCat, so I'm completely sure)
I have seen, many people had troubles with clicks in ExpandableListViews in ListViewItems, my case is different, I can perform that, my trouble is understanding, why with a TextView works fine that ExpandableListView Population via my custom BaseExpandableListAdapter but not in a ListView Item.
Solved
In my first level Adapter (An adapter for the first level ExpandableListView) I modified the getChildView Method
...
// Member Field
private ExpandableListView expandable_field_list;
...
#Override
public View getChildView(int groupPosition, int childPosition,boolean isLastChild, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
if ( groupPosition == 1 ) {
if ( expandable_field_list == null ) {
expandable_field_list = new CustomExpandableListView(context);
// Here I initialize the second and third Level
client_adapter = new ClientAdapter(context, groups, children);
expandable_field_list.setAdapter(client_adapter);
} else {
client_adapter.notifyDataSetChanged();
}
convertView = expandable_field_list;
}
return convertView;
}
...
And CustomExpandableListView looks like this
public class CustomExpandableListView extends ExpandableListView {
private boolean expanded = true;
public CustomExpandableListView(Context context) {
super(context);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isExpanded()) {
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
#Override
protected void onDetachedFromWindow() {
try {
super.onDetachedFromWindow();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
public void setIsExpanded(boolean expanded) {
this.expanded = expanded;
}
public boolean isExpanded() {
return expanded;
}
}
That is its aspect now as desired

Autocomplete textbox highlighting the typed character in the suggestion list

I have been working on AutoCompleteTextView. I was able to get the suggestion and all in the drop down list as we type.
My question is: Can we highlight the typed character in the suggestion drop down list?
I have achieved the functionality. The solution is as follows:
AutoCompleteAdapter.java
public class AutoCompleteAdapter extends ArrayAdapter<String> implements
Filterable {
private ArrayList<String> fullList;
private ArrayList<String> mOriginalValues;
private ArrayFilter mFilter;
LayoutInflater inflater;
String text = "";
public AutoCompleteAdapter(Context context, int resource,
int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
fullList = (ArrayList<String>) objects;
mOriginalValues = new ArrayList<String>(fullList);
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return fullList.size();
}
#Override
public String getItem(int position) {
return fullList.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
// tvViewResourceId = (TextView) view.findViewById(android.R.id.text1);
String item = getItem(position);
Log.d("item", "" + item);
if (convertView == null) {
convertView = view = inflater.inflate(
android.R.layout.simple_dropdown_item_1line, null);
}
// Lookup view for data population
TextView myTv = (TextView) convertView.findViewById(android.R.id.text1);
myTv.setText(highlight(text, item));
return view;
}
#Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}
private class ArrayFilter extends Filter {
private Object lock;
#Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (prefix != null) {
text = prefix.toString();
}
if (mOriginalValues == null) {
synchronized (lock) {
mOriginalValues = new ArrayList<String>(fullList);
}
}
if (prefix == null || prefix.length() == 0) {
synchronized (lock) {
ArrayList<String> list = new ArrayList<String>(
mOriginalValues);
results.values = list;
results.count = list.size();
}
} else {
final String prefixString = prefix.toString().toLowerCase();
ArrayList<String> values = mOriginalValues;
int count = values.size();
ArrayList<String> newValues = new ArrayList<String>(count);
for (int i = 0; i < count; i++) {
String item = values.get(i);
if (item.toLowerCase().contains(prefixString)) {
newValues.add(item);
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
if (results.values != null) {
fullList = (ArrayList<String>) results.values;
} else {
fullList = new ArrayList<String>();
}
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
public static CharSequence highlight(String search, String originalText) {
// ignore case and accents
// the same thing should have been done for the search text
String normalizedText = Normalizer
.normalize(originalText, Normalizer.Form.NFD)
.replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
.toLowerCase(Locale.ENGLISH);
int start = normalizedText.indexOf(search.toLowerCase(Locale.ENGLISH));
if (start < 0) {
// not found, nothing to to
return originalText;
} else {
// highlight each appearance in the original text
// while searching in normalized text
Spannable highlighted = new SpannableString(originalText);
while (start >= 0) {
int spanStart = Math.min(start, originalText.length());
int spanEnd = Math.min(start + search.length(),
originalText.length());
highlighted.setSpan(new ForegroundColorSpan(Color.BLUE),
spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = normalizedText.indexOf(search, spanEnd);
}
return highlighted;
}
}
}
MainActivity.java
public class MainActivity extends Activity {
String[] languages = { "C", "C++", "Java", "C#", "PHP", "JavaScript",
"jQuery", "AJAX", "JSON" };
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
List<String> wordList = new ArrayList<String>();
Collections.addAll(wordList, languages);
AutoCompleteAdapter adapter = new AutoCompleteAdapter(this,
android.R.layout.simple_dropdown_item_1line,
android.R.id.text1,wordList);
AutoCompleteTextView acTextView = (AutoCompleteTextView) findViewById(R.id.languages);
acTextView.setThreshold(1);
acTextView.setAdapter(adapter);
}
}
Working like charm!
Enjoy!
I reckon that should be possible, provided you know the index/indices of the character(s) the user typed last. You can then use a SpannableStringBuilder and set a ForegroundColorSpan and BackgroundColorSpan to give the character(s) the appearance of a highlight.
The idea looks somewhat like this:
// start & end of the highlight
int start = ...;
int end = ...;
SpannableStringBuilder builder = new SpannableStringBuilder(suggestionText);
// set foreground color (text color) - optional, you may not want to change the text color too
builder.setSpan(new ForegroundColorSpan(Color.RED), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// set background color
builder.setSpan(new BackgroundColorSpan(Color.YELLOW), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// set result to AutoCompleteTextView
autocompleteTextview.setText(builder);
Note that the 'highlight' will remain as long as you don't type another character. You may want to remove the highlight when e.g. the user changes the cursor position in the AutoCompleteTextView, but I'll leave that up to you.
I know it's to late for answering this question , But as I personally battled to find the answer , finally I wrote it myself (with the help of the answer from #MH. ofcourse), so here it is :
First , You have to create a Custom ArrayAdapter :
public class AdapterAustocomplete extends ArrayAdapter<String> {
private static final String TAG = "AdapterAustocomplete";
String q = "";
public AdapterAustocomplete(Context context, int resource, List objects) {
super(context, resource, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String item = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView =
// I'll use a custom view for each Item , this way I can customize it also!
G.inflater.from(getContext()).inflate(R.layout.textview_autocomplete, parent, false);
}
// Lookup view for data population
TextView myTv = (TextView) convertView.findViewById(R.id.txt_autocomplete);
int start = item.indexOf(q);
int end = q.length()+start;
SpannableStringBuilder builder = new SpannableStringBuilder(item);
builder.setSpan(new ForegroundColorSpan(Color.RED), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
myTv.setText(builder);
return convertView;
}
public void setQ(String q) {
this.q = q;
}
}
And in the Code that you want to set the adapter for AutoCompleteTextView ;
AutoCompleteTextView myAutoComplete = findViewById(its_id);
AdapterAustocomplete adapter_autoComplete = new AdapterAustocomplete(getActivity(), 0, items); // items is an arrayList of Strings
adapter_autoComplete.setQ(q);
myAutoComplete.setAdapter(adapter_autoComplete);
Thanks to vadher jitendra I wrote the same and fixed some bugs.
Changed a dropdown layout to own.
Added showing a full list when clicking inside AutoCompleteTextView.
Fixed a bug of freezing the list when showing (added a check for empty string in highlight).
row_dropdown.xml (item layout):
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/text1"
style="?android:attr/dropDownItemStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:ellipsize="marquee"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:singleLine="true"
android:textColor="#333333"
android:textSize="15sp"
tools:text="text"
tools:textAppearance="?android:attr/textAppearanceLargePopupMenu" />
To filter a list when typing we should implement ArrayAdapter. It depends on items (T class). You can later use AutoCompleteAdapter<String> or any data class you like.
AutoCompleteAdapter:
import android.content.Context;
import android.graphics.Typeface;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class AutoCompleteAdapter<T> extends ArrayAdapter<T> implements Filterable {
private Context context;
#LayoutRes
private int layoutRes;
#IdRes
private int textViewResId;
private ArrayList<T> fullList;
private ArrayList<T> originalValues;
private ArrayFilter filter;
private LayoutInflater inflater;
private String query = "";
public AutoCompleteAdapter(#NonNull Context context, #LayoutRes int resource, #IdRes int textViewResourceId, #NonNull List<T> objects) {
super(context, resource, textViewResourceId, objects);
this.context = context;
layoutRes = resource;
textViewResId = textViewResourceId;
fullList = (ArrayList<T>) objects;
originalValues = new ArrayList<>(fullList);
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return fullList.size();
}
#Override
public T getItem(int position) {
return fullList.get(position);
}
/**
* You can use either
* vadher jitendra method (getView)
* or get the method from ArrayAdapter.java.
*/
// #NotNull
// #Override
// public View getView(int position, View convertView, ViewGroup parent) {
// View view = convertView;
// T item = getItem(position);
// Log.d("item", "" + item);
// if (convertView == null) {
// convertView = view = inflater.inflate(layoutRes, null);
// }
// // Lookup view for data population
// TextView myTv = convertView.findViewById(textViewResId);
// myTv.setText(highlight(query, item));
// return view;
// }
#Override
public #NonNull
View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
return createViewFromResource(inflater, position, convertView, parent, layoutRes);
}
private #NonNull
View createViewFromResource(#NonNull LayoutInflater inflater, int position,
#Nullable View convertView, #NonNull ViewGroup parent, int resource) {
final View view;
final TextView text;
if (convertView == null) {
view = inflater.inflate(resource, parent, false);
} else {
view = convertView;
}
try {
if (textViewResId == 0) {
// If no custom field is assigned, assume the whole resource is a TextView
text = (TextView) view;
} else {
// Otherwise, find the TextView field within the layout
text = view.findViewById(textViewResId);
if (text == null) {
throw new RuntimeException("Failed to find view with ID "
+ context.getResources().getResourceName(textViewResId)
+ " in item layout");
}
}
} catch (ClassCastException e) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
throw new IllegalStateException(
"ArrayAdapter requires the resource ID to be a TextView", e);
}
final T item = getItem(position);
text.setText(highlight(query, item.toString()));
// if (item instanceof CharSequence) {
// text.setText(highlight(query, (CharSequence) item));
// } else {
// text.setText(item.toString());
// }
return view;
}
#Override
public #NonNull
Filter getFilter() {
if (filter == null) {
filter = new ArrayFilter();
}
return filter;
}
private class ArrayFilter extends Filter {
private final Object lock = new Object();
#Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (prefix == null) {
query = "";
} else {
query = prefix.toString();
}
if (originalValues == null) {
synchronized (lock) {
originalValues = new ArrayList<>(fullList);
}
}
if (prefix == null || prefix.length() == 0) {
synchronized (lock) {
ArrayList<T> list = new ArrayList<>(originalValues);
results.values = list;
results.count = list.size();
}
} else {
final String prefixString = prefix.toString().toLowerCase();
ArrayList<T> values = originalValues;
int count = values.size();
ArrayList<T> newValues = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
T item = values.get(i);
if (item.toString().toLowerCase().contains(prefixString)) {
newValues.add(item);
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.values != null) {
fullList = (ArrayList<T>) results.values;
} else {
fullList = new ArrayList<>();
}
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
private static CharSequence highlight(#NonNull String search, #NonNull CharSequence originalText) {
if (search.isEmpty())
return originalText;
// ignore case and accents
// the same thing should have been done for the search text
String normalizedText = Normalizer
.normalize(originalText, Normalizer.Form.NFD)
.replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
.toLowerCase(Locale.ENGLISH);
int start = normalizedText.indexOf(search.toLowerCase(Locale.ENGLISH));
if (start < 0) {
// not found, nothing to do
return originalText;
} else {
// highlight each appearance in the original text
// while searching in normalized text
Spannable highlighted = new SpannableString(originalText);
while (start >= 0) {
int spanStart = Math.min(start, originalText.length());
int spanEnd = Math.min(start + search.length(),
originalText.length());
highlighted.setSpan(new StyleSpan(Typeface.BOLD), spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = normalizedText.indexOf(search, spanEnd);
}
return highlighted;
}
}
}
In order to show dropdown list when clicked inside AutoCompleteTextView we need to override setOnTouchListener as described in https://stackoverflow.com/a/26036902/2914140. Lint also prints warnings, so we have to write a custom view:
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.appcompat.widget.AppCompatAutoCompleteTextView;
/*
Avoids a warning "Custom view `AutoCompleteTextView` has setOnTouchListener called on it but does not override performClick".
*/
public class AutoCompleteTV extends AppCompatAutoCompleteTextView {
public AutoCompleteTV(Context context) {
super(context);
}
public AutoCompleteTV(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoCompleteTV(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
performClick();
}
return super.onTouchEvent(event);
}
#Override
public boolean performClick() {
super.performClick();
return true;
}
}
Then use it in activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.autocompletetextview1.AutoCompleteTV
android:id="#+id/languages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:completionThreshold="1"
android:hint="language"
android:imeOptions="actionNext"
android:maxLines="1"
android:paddingLeft="10dp"
android:paddingTop="15dp"
android:paddingRight="10dp"
android:paddingBottom="15dp"
android:singleLine="true"
android:textColor="#333333"
android:textColorHint="#808080"
android:textSize="12sp" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
I use TextInputLayout here for better decoration, in this case we have to add Material Design Components:
in build.gradle:
implementation 'com.google.android.material:material:1.3.0-alpha01'
and in styles.xml:
<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
...
MainActivity:
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.AutoCompleteTextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
String[] items = {"C", "C++", "Java", "C#", "PHP", "JavaScript", "jQuery", "AJAX", "JSON"};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<DataClass> wordList = new ArrayList<>();
for (int i = 0; i < items.length; i++) {
DataClass data = new DataClass(i, items[i]);
wordList.add(data);
}
AutoCompleteAdapter<DataClass> adapter = new AutoCompleteAdapter<>(this,
R.layout.row_dropdown, R.id.text1, wordList);
//adapter.setDropDownViewResource(R.layout.row_dropdown);
AutoCompleteTV acTextView = findViewById(R.id.languages);
acTextView.setThreshold(1);
acTextView.setAdapter(adapter);
acTextView.setText("Java");
acTextView.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
((AutoCompleteTextView) v).showDropDown();
v.requestFocus();
v.performClick(); // Added to avoid warning "onTouch lambda should call View#performClick when a click is detected".
}
return false;
}
);
}
}