Получите входные значения EditText и отобразите некоторые результаты вычислений в TextView. - PullRequest
1 голос
/ 19 апреля 2020

Я сделал очень простой c калькулятор средневзвешенного значения как Android Приложение (в Java), и оно работало нормально.

Пользователь просто вводит 3 значения a, b , c через три EditText с, и он рассчитывает формулу:

d = 0.25 * a + 0.25 * b + 0.5 * c;

Результат этого математического уравнения отображается в TextView, все это в MainActivity при нажатии Кнопка.

Но после создания нового проекта для улучшения пользовательского интерфейса (используется Android Студийный шаблон Navigation Drawer Activity) я понял, что мой код не работает.

Как я могу изменить этот калькулятор на получить вход в мой фрагмент (с именем CalculatorWeightedFragment), чтобы выполнить вычисления и отобразить результат в TextView в том же фрагменте, когда моя кнопка нажата?

На данный момент все, что я получаю, это отображение чего-то stati c и для кнопки не назначено никаких действий.

Код ниже:

CalculatorWeightedFragment. java

public class CalculatorWeightedFragment extends Fragment {

    private CalculatorWeightedViewModel calculatorWeightedViewModel;

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        calculatorWeightedViewModel =
                ViewModelProviders.of(this).get(calculatorWeightedViewModel.class);
        View root = inflater.inflate(R.layout.fragment_calculator_w, container, false);

        final TextView textView = root.findViewById(R.id.id_result);  // result d stored in id_result


        calculatorWeightedViewModel.takeText().observe(getViewLifecycleOwner(),
                new Observer<String>() {
                    @Override
                    public void onChanged(@Nullable String str) {
                        textView.setText(str);
                    }
                });

        return root;
    }
}

CalculatorWeightedViewModel. java

public class CalculatorWeightedViewModel extends ViewModel {

    private MutableLiveData<String> testString;

    public CalculatorWeightedViewModel() {
        testString = new MutableLiveData<>();
        testString.setValue("" + 0.5);
    }

    public LiveData<String> takeText() {
        return testString;
    }
}

1 Ответ

0 голосов
/ 20 апреля 2020

На основе вашего xml содержимого макета:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/id_a"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/id_b"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/id_c"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/id_buton_rata"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="calculateFunction" />

    <TextView
        android:id="@+id/id_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Пример № 1 (без LiveData и ViewModel)

Я создаю какой-то новый простой фрагмент (как пример)

public class CalculatorWeightedFragment extends Fragment {

    private Button button;
    private EditText editTextA;
    private EditText editTextB;
    private EditText editTextC;
    private TextView textViewD;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_calculator_w, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        button = view.findViewById(R.id.id_buton_rata);
        editTextA = view.findViewById(R.id.id_a);
        editTextB = view.findViewById(R.id.id_b);
        editTextC = view.findViewById(R.id.id_c);
        textViewD = view.findViewById(R.id.id_result);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                double result = calculateResult();
                String output = String.format("Result:  %s", result);
                textViewD.setText(output);
            }
        });
    }

    private double calculateResult() {
        try {
            int a = Integer.parseInt(editTextA.getText().toString());
            int b = Integer.parseInt(editTextB.getText().toString());
            int c = Integer.parseInt(editTextC.getText().toString());

            // Result
            return 0.25 * a + 0.25 * b + 0.5 * c;
        } catch (NumberFormatException e) {
            e.printStackTrace();
            return 0;
        }
    }
}

Пример # 2 (с LiveData и ViewModel)

Когда вы используете LiveData и ViewModel, вам не нужна кнопка на вашем Fragment. Вы можете наблюдать за всеми изменениями.

Активность, в которой вы создаете этот фрагмент. Чтобы иметь ViewModel во Fragment, вы можете использовать внедрение зависимостей (например, используя библиотеку Dagger) или получить его из ViewModelProviders (или AndroidViewModelFactory).

Здесь, чтобы сделать пример максимально простым, я передаю его через конструктор.

Activity

public class MainActivity extends AppCompatActivity {

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        CalculatorWeightedViewModel vm = new CalculatorWeightedViewModel();

        CalculatorWeightedFragment fragment = new CalculatorWeightedFragment(vm);

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.add(R.id.frame_layout, fragment);
        transaction.commit();
    }
}

ViewModel

Вы можете хранить свои значения (a, b, c) как поля для различного назначения. Здесь я пересчитываю результат вживую, без лишних полей. Чтобы сделать его максимально простым.

package com.example.stack_android;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class CalculatorWeightedViewModel extends ViewModel {

    private MutableLiveData<String> testString = new MutableLiveData<>();

    public LiveData<String> takeText() {
        return testString;
    }

    void updateValues(double a, double b, double c) {
        double result = recalculate(a, b, c);
        String value = "Result: " + result;
        testString.postValue(value);
    }

    void showError() {
        testString.postValue("Wrong Value");
    }

    private double recalculate(double a, double b, double c) {
        return 0.25 * a + 0.25 * b + 0.5 * c;
    }
}

Фрагмент:

Дополнительно вы можете создать отдельных слушателей (для каждого из полей). Здесь я использую один (названный TextWatcher listener) для всех полей.

public class CalculatorWeightedFragment extends Fragment {

    private CalculatorWeightedViewModel viewModel;

    private EditText editTextA;
    private EditText editTextB;
    private EditText editTextC;
    private TextView textViewD;

    public CalculatorWeightedFragment(CalculatorWeightedViewModel viewModel) {
        this.viewModel = viewModel;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_calculator_w, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        editTextA = view.findViewById(R.id.id_a);
        editTextB = view.findViewById(R.id.id_b);
        editTextC = view.findViewById(R.id.id_c);
        textViewD = view.findViewById(R.id.id_result);

        TextWatcher listener = new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                textChanged();
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                // Not used
            }

            @Override
            public void afterTextChanged(Editable s) {
                // Not used
            }
        };

        editTextA.addTextChangedListener(listener);
        editTextB.addTextChangedListener(listener);
        editTextC.addTextChangedListener(listener);

        viewModel.takeText().observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(String newValue) {
                textViewD.setText(newValue);
            }
        });
    }

    private void textChanged() {
        try {
            int a = Integer.parseInt(editTextA.getText().toString());
            int b = Integer.parseInt(editTextB.getText().toString());
            int c = Integer.parseInt(editTextC.getText().toString());

            viewModel.updateValues(a, b, c);
        } catch (NumberFormatException e) {
            viewModel.showError();
            e.printStackTrace();
        }
    }
}

Он должен работать так:

Demo

...