I am trying to set focus on a LinearLayout view when returning to an activity from another activity. The scenario:
I have one activity with a bunch of LinearLayout items (with stuff in them), some of which are text, others photos. Let's say the top most of 20 is a TextView and the rest are photos. When I leave this activity (to take a picture), activity goes to the top of the list where the TextView is - no matter what I do.
How do I force the focus back on the item that I was on before the new activity was triggered?
I have already tried this with no success:
[How Linear Layout get Focus?
I am currently trying to force the focus by remembering the previous view without success (though I can see the code being executed). The in my main activity:
#Override
public void onResume() {
super.onResume();
// See if we had a field with focus previously...
if (mPreviousView != null) {
if (mPreviousView.isFocusable()) {
mPreviousView.requestFocus();
}
}
}
...
#Override
protected void onPause() {
super.onPause();
mPreviousView = this.getCurrentFocus();
}
I am dynamically setting the focus in the LinearLayout:
private void initialize() {
LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.field_photo_picker, this);
// To allow focus to be returned to control after taking photo
this.setFocusableInTouchMode(true);
this.setFocusable(true);
this.setClickable(true);
And finally the XML for the LinearLayout:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp">
<TextView
android:id="#+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="normal"
android:text="" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/photoValue"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="17sp"
android:textStyle="normal"
android:gravity="right|center_vertical"
android:layout_weight="1"
android:layout_marginRight="5dp"
android:text="" />
<ImageButton
android:id="#+id/photoPicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/form_photo"
android:padding ="5dp"
android:gravity="center_vertical"
android:focusableInTouchMode="false"
android:background="?android:attr/selectableItemBackground"
android:layout_weight="0"
/>
</LinearLayout>
<View
android:layout_marginTop="8dp"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/grey" />
</LinearLayout>
</merge>
make your textview and other views focusable, you made this.setFocusable(true); which doesn't make sense
Related
I'm learning android and And I'm facing some troubles. I kindly request you to solve these problems.
I have 2 linear layouts inside a linear layout, both are placed horizontally. The left side section contains some buttons and if we click the button the respective layout must come on the right-side section. As of now, if I click the button the specific layout is appearing but not inside the second linear layout. And also, I want to set a default layout to appear on the right side layout. For ex, here I've added the "breakfastdishes.xml", which I want as a default right-side layout, and when I click on the buttons from the left-side layout, according to id the right-side layout must change. Can you please help me to achieve it?
Here is my code:
MenuSection.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MenuSection"
android:background="#drawable/gradient"
android:padding="10dp">
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="#+id/breakfast"
android:layout_width="220dp"
android:layout_height="65dp"
android:text="#string/breakfast"
android:textSize="20dp"
android:background="#drawable/menu_category"
android:fontFamily="sans-serif"
android:textStyle="bold"
app:backgroundTint="#AC8E0D"/>
<Button
android:id="#+id/lunch"
android:layout_width="220dp"
android:layout_height="65dp"
android:layout_marginTop="60dp"
android:text="#string/lunch"
android:textSize="20dp"
android:background="#drawable/menu_category"
android:fontFamily="sans-serif"
android:textStyle="bold"
app:backgroundTint="#0A5FAA"/>
<Button
android:id="#+id/eveningSnacks"
android:layout_width="220dp"
android:layout_height="65dp"
android:layout_marginTop="60dp"
android:background="#drawable/menu_category"
android:fontFamily="sans-serif"
android:text="#string/snacks"
android:textSize="20dp"
android:textStyle="bold"
app:backgroundTint="#DF5124" />
<Button
android:id="#+id/dinner"
android:layout_width="220dp"
android:layout_height="65dp"
android:layout_marginTop="60dp"
android:text="#string/dinner"
android:textSize="20dp"
android:background="#drawable/menu_category"
android:fontFamily="sans-serif"
android:textStyle="bold"
app:backgroundTint="#14A61A"/>
</LinearLayout>
</ScrollView>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:id="#+id/itemsDisplay">
<LinearLayout
android:id="#+id/menuDispArea"
android:layout_width="508dp"
android:layout_height="412dp">
<!-- <include-->
<!-- layout="#layout/breakfastdishes"-->
<!-- android:layout_width="508dp"-->
<!-- android:layout_height="412dp" />-->
</LinearLayout>
</ScrollView>
</LinearLayout>
BreakfastDishes.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/gradient"
android:paddingStart="12dp"
android:paddingLeft="10dp"
android:paddingTop="20dp"
android:paddingEnd="12dp"
android:paddingRight="10dp"
android:paddingBottom="20dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:orientation="vertical">
<ImageView
android:id="#+id/burger"
android:layout_width="155dp"
android:layout_height="102dp"
android:layout_x="10dp"
android:layout_y="10dp"
app:srcCompat="#mipmap/burger_breakfast" />
<TextView
android:id="#+id/burgerTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/burger"
android:layout_alignTop="#+id/burger"
android:layout_alignRight="#+id/burger"
android:layout_alignBottom="#+id/burger"
android:layout_gravity="center_horizontal"
android:layout_margin="1dp"
android:gravity="center"
android:text="#string/burger"
android:textColor="#FFF"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:orientation="vertical">
<ImageView
android:id="#+id/eggOmlet"
android:layout_width="160dp"
android:layout_height="104dp"
android:layout_x="233dp"
android:layout_y="7dp"
app:srcCompat="#mipmap/egg_omlet" />
<TextView
android:id="#+id/eggOmletTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/eggOmlet"
android:layout_alignTop="#+id/eggOmlet"
android:layout_alignRight="#+id/eggOmlet"
android:layout_alignBottom="#+id/eggOmlet"
android:layout_gravity="center_horizontal"
android:layout_margin="1dp"
android:gravity="center"
android:text="#string/eggOmlet"
android:textColor="#FFF"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
MenuSection.java
package com.example.restaurant;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MenuSection extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu_section);
Button breakfast = (Button) findViewById(R.id.breakfast);
Button lunch = (Button) findViewById(R.id.lunch);
breakfast.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MenuSection.this, BreakfastDishes.class);
startActivity(intent);
}
});
lunch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MenuSection.this, LunchDishes.class);
startActivity(intent);
}
});
}
#Override
public void onBackPressed(){
//super.onBackPressed();
}
}
Akshay, here are a few things you have to keep in mind ;
In the button click listener you are launching new activity instead of updating
the existing layout. When you use Intent it will launch new activity and
close the current activity. So in your case do not use startActivity
Use findViewById for the menuDispArea layout and add update
the content when user clicks on the button.
never use dp for text size, use sp
you can divide the layout using LinearLayout weights to split your layouts on
all the devices instead of hardcoding the height and width
https://developer.android.com/guide/topics/ui/layout/linear#Weight
edit: Added sample
LayoutInflater inflater = LayoutInflater.from(MenuSection.this);
LinearLayout parentLayout = findViewById(R.id.menuDispArea);
View menuLayout= inflater.inflate(R.layout.BreakfastDishes, parentLayout, false);
parentLayout.addView(menuLayout);
You can use this to inflate any XML in your layout dynamically. Make sure you are doing this inside button onClick for your use case.
I've a custom button layout: Its a FrameLayout as a background with a normal Button in the center with an icon next to the text.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/framelayout"
style="?android:attr/buttonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:background="#F00">
<android.support.v7.widget.AppCompatButton
android:id="#+id/buttonWithIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:background="#null"
android:drawableStart="#android:drawable/ic_delete"
android:gravity="center"
android:textAllCaps="false"
android:textColor="#FFF"/>
</FrameLayout>
I had an onClickListeners on the Button and I realized, clicks on the background (=FrameLayout) weren't detected. Because of this I want an onClickListener that detects clicks on the FrameLayout and also on the Button, without having two Listeners, that do the same.
I tried giving the RelativeLayout an ID, but the layout couldn't be found (=null).
Maybe my button layout isn't optimal. But I need a fullwidth button with a icon next to the text, without any spaces between the icon and the text.
The Icons gets set like this
button.setCompoundDrawablesWithIntrinsicBounds(R.mipmap.ic_icon, 0, 0,0);
Thank you
You can just add one OnClickListener to both views. That way, you only write your code once, and if you click either the FrameLayout or the Button that same code will run.
final View.OnClickListener mOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Add Your OnClick Code Here
}
};
framelayout.setOnClickListener(mOnClickListener);
buttonWithIcon.setOnClickListener(mOnClickListener);
You can put all of your views that you want them to be clickable and remove all clickListeners of entire views.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/linearlayout">
<FrameLayout
style="?android:attr/buttonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:background="#F00">
<android.support.v7.widget.AppCompatButton
android:id="#+id/buttonWithIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:background="#null"
android:drawableStart="#android:drawable/ic_delete"
android:gravity="center"
android:textAllCaps="false"
android:textColor="#FFF"/>
</FrameLayout>
</LinearLayout>
and add this clickListener to LinearLayout:
LinearLayout linearlayout=(linearLayout)findViewById(R.id.linearlayout);
linearlayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Add Your Code Here
}
});
Create a function in your Activity with a View Argument, and in your layout, set the onClick to your two views.
Activity:
public void myAction(View v){
// Do what you want
}
Your Layout:
<FrameLayout
android:id="#+id/framelayout"
style="?android:attr/buttonStyle"
android:onClick="myAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:background="#F00">
<android.support.v7.widget.AppCompatButton
android:id="#+id/buttonWithIcon"
android:onClick="myAction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:background="#null"
android:drawableStart="#android:drawable/ic_delete"
android:gravity="center"
android:textAllCaps="false"
android:textColor="#FFF"/>
</FrameLayout>
Maybe adding in just the FrameLayout may dispatch the event in the button also, i can't test right now :)
I have a ScrollView with a nested LinearLayout that has some length to it. At the bottom I have a button that has a function that will need to act similarly to a Return to Top.
I've tried creating an onClickListener and with setFocusableInTouchMode and setFocusable set to true, use the listener to request focus. No luck.
I've tried the following without success.
scrollView.smoothScrollTo(0,0);
scrollView.fullScroll(scrollView.FOCUS_UP);
scrollGetStartedGetMostFromLearning.fullScroll(View.FOCUS_UP);
XML
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Title"
android:id="#+id/textgTitle"
android:textColor="#F0F0F0"
android:textSize="30sp"
android:focusable="true"
android:focusableInTouchMode="true"/>
<Button
android:id="#+id/btnTop"
android:text="To Top"
android:textSize="25sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/white"
/>
</LinearLayout>
</ScrollView>
Java
btnTop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
scrollView.fullScroll(View.FOCUS_UP);
} //or any of the 3 used above
Any help or direction as to what I'm doing wrong is appreciated. Thanks!
I have a three tab interface setup using a ViewPager. In the 3rd tab, I have a CardView which can expand/retract onclick to reveal more information. Inside the CardView is a RecyclerView which is inflated with a bunch of data.
The first time the app opens and the CardView is expanded, the expand animation is quite laggy but afterwards, it can be expanded/retracted smoothly. The RecyclerView data can also be updated with no problem.
Is there a way to somehow load/cache the data upon opening the app so the lagg does not occur.
Sorry if question is poor, just starting android development.
Thanks
Layout on third tab:
<android.support.v7.widget.CardView
android:id="#+id/SF_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp">
<LinearLayout
android:id="#+id/SF_wrapper"
android:layout_width="fill_parent"
android:layout_height="80dp"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/SF_list"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
</android.support.v7.widget.CardView>
The data which is used to inflate the recyclerView is a list of objects each with 2 float variables. Roughly length ~50.
The xml used to inflate each item:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4sp"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="36sp"
android:layout_weight="1">
<TextView
android:id="#+id/value_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="lorem"
android:textSize="8sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="36sp"
android:layout_weight="1">
<TextView
android:id="#+id/value_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="ipsom"
android:textSize="8sp" />
</RelativeLayout>
</LinearLayout>
The code to expand/retract the cardView simply animated changing the height of SF_frame to reveal more elements of the RecyclerView and it is this first reveal which is laggy.
Resolve your Layouting as first:
Use sp only with texts and dp for other dimensions (width, height, margins, paddings etc.). For texts it is recommended to use at least android:textsize="12sp". Look at the android:gravity attribute instead of android:layout_gravity so you don't have to use parent layout just to center it.
<android.support.v7.widget.CardView
android:id="#+id/SF_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp">
<!-- No need to use LinearLayout since only one child is used -->
<android.support.v7.widget.RecyclerView
android:id="#+id/SF_list"
android:layout_width="match_parent"
android:layout_height="80dp">
</android.support.v7.widget.RecyclerView>
</android.support.v7.widget.CardView>
In this layout, if you are expanding RecyclerView, it is possible that new views are being instantiated (RecyclerView.Adapter.onCreateViewHolder and RecyclerView.Adapter.onBindViewHolder) are called mulitple times.
In fact switching to that Tab is also a little bit delayed, but it is clearly visible on animation. (you are expandig from about 3 items to maybe 20 or so, I don't know how rest of your layout looks)
and second:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:orientation="horizontal">
<TextView
android:id="#+id/value_1"
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_weight="1"
android:layout_gravity="center"
android:text="lorem"
android:textSize="8sp" />
<TextView
android:id="#+id/value_2"
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_weight="1"
android:layout_gravity="center"
android:text="ipsom"
android:textSize="8sp" />
</LinearLayout>
If filling these 2 TextViews is so terribly slow, that you are experiencing hickups. Then you probably doing very very complex math operations (try to simplify them if possible) or you are somehow downloading data synchronously and waiting for results.
Please have a look at AsyncTask and use it while binding data... You can use it something like this (modify by yourself):
private class MyAsyncTask extends AsyncTask<Void, Void, String> {
private TextView view;
MyAsyncTask(TextView view) {
this.view = view;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
// display progressbar or something
}
#Override
protected String doInBackground(Void... params) {
// do heavyweight operation here
String result = heavyWeightOperation(params);
return result;
}
#Override
protected void onPostExecute(String s) {
// hide progressbar or something
if (view != null) {
view.setText(s);
}
super.onPostExecute(s);
}
}
I have a stand-alone EditText and a ListView. Each item in the ListView also has two EditText fields. When I touch inside the ListView EditText, the stand-alone EditText steals the focus. This makes it impossible to edit any of the ListView EditText fields.
Name steals the focus from the other TextView elements inside the ListView
Here is the activity's XML, containing the stand-alone EditText and the ListView
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dip"
android:orientation = "vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="16dip" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dip"
android:layout_weight="1"
android:text="#string/name"
android:textAppearance="?android:attr/textAppearanceMedium" />
<EditText
android:id="#+id/editblindschedule_name"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="5"
android:ems="10"
android:inputType="text" />
</LinearLayout>
<ListView
android:id="#+id/listview_editblindschedule"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
And here is the ListView row 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" >
<TextView
android:id="#+id/editblindschedule_round"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"/>
<EditText
android:id="#+id/editblindschedule_small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="#string/small"
android:ems="4"
android:inputType="number"
android:layout_weight="4"
android:layout_marginRight="10dip"
android:text="#string/integer_zero"
android:gravity="center" />
<EditText
android:id="#+id/editblindschedule_big"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="#string/big"
android:ems="4"
android:inputType="number"
android:layout_weight="4"
android:layout_marginRight="10dip"
android:paddingRight="6dip"
android:text="#string/integer_zero"
android:gravity="center" />
<CheckBox
android:id="#+id/editblindschedule_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:checked="true" />
</LinearLayout>
Here is the Java code
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_blind_schedule);
...
adapter = new BlindAdapter(this, blindSchedule.getBlindLevels());
listView = (ListView) findViewById(R.id.listview_editblindschedule);
listView.setAdapter(adapter);
And finally, the adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.listview_editblindschedule, parent, false);
if (!creating) { // Set default values.
TextView round = (TextView) row.findViewById(R.id.editblindschedule_round);
EditText small = (EditText) row.findViewById(R.id.editblindschedule_small);
EditText big = (EditText) row.findViewById(R.id.editblindschedule_big);
round.setText("" + (position + 1));
small.setText("" + blindLevels.get(position).getSmallBlind());
big.setText("" + blindLevels.get(position).getBigBlind());
}
return row;
}
The solution that worked for me was to put android:windowSoftInputMode="adjustPan" in the activity in the manifest. This was the only change necessary for me.
I don't like it but after digging ListView code I ended up by overriding the getFocusedChild() method and returning null as all other trials of flag combinations didn't get to a satisfactory solution.
Even if android:windowSoftInputMode="adjustPan" works adjusting pan leads to too much artifacts in my layout.
Beware overriding that method may lead to other unwanted behaviours so use it and test it comprehensively in all android versions you support and may be call super instead of returning null for android versions that does not/will have this problem.